Merge "SF: trace adjusted expected vsync time" into sc-dev
diff --git a/include/input/Input.h b/include/input/Input.h
index bb5ca0e..7b522bb 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -318,6 +318,12 @@
*/
constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN();
+/**
+ * Invalid value for display size. Used when display size isn't available for an event or doesn't
+ * matter. This is just a constant 0 so that it has no effect if unused.
+ */
+constexpr int32_t AMOTION_EVENT_INVALID_DISPLAY_SIZE = 0;
+
/*
* Pointer coordinate data.
*/
@@ -360,6 +366,8 @@
return getAxisValue(AMOTION_EVENT_AXIS_Y);
}
+ vec2 getXYValue() const { return vec2(getX(), getY()); }
+
#ifdef __linux__
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
@@ -548,6 +556,8 @@
void setCursorPosition(float x, float y);
+ int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; }
+
static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
inline nsecs_t getDownTime() const { return mDownTime; }
@@ -570,8 +580,17 @@
inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
+ /**
+ * The actual raw pointer coords: whatever comes from the input device without any external
+ * transforms applied.
+ */
const PointerCoords* getRawPointerCoords(size_t pointerIndex) const;
+ /**
+ * This is the raw axis value. However, for X/Y axes, this currently applies a "compat-raw"
+ * transform because many apps (incorrectly) assumed that raw == oriented-screen-space.
+ * "compat raw" is raw coordinates with screen rotation applied.
+ */
float getRawAxisValue(int32_t axis, size_t pointerIndex) const;
inline float getRawX(size_t pointerIndex) const {
@@ -634,9 +653,18 @@
return mSampleEventTimes[historicalIndex];
}
+ /**
+ * The actual raw pointer coords: whatever comes from the input device without any external
+ * transforms applied.
+ */
const PointerCoords* getHistoricalRawPointerCoords(
size_t pointerIndex, size_t historicalIndex) const;
+ /**
+ * This is the raw axis value. However, for X/Y axes, this currently applies a "compat-raw"
+ * transform because many apps (incorrectly) assumed that raw == oriented-screen-space.
+ * "compat raw" is raw coordinates with screen rotation applied.
+ */
float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
size_t historicalIndex) const;
@@ -704,9 +732,9 @@
int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform,
float xPrecision, float yPrecision, float rawXCursorPosition,
- float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
- size_t pointerCount, const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords);
+ float rawYCursorPosition, int32_t displayWidth, int32_t displayHeight,
+ nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
+ const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -759,6 +787,8 @@
float mYPrecision;
float mRawXCursorPosition;
float mRawYCursorPosition;
+ int32_t mDisplayWidth;
+ int32_t mDisplayHeight;
nsecs_t mDownTime;
Vector<PointerProperties> mPointerProperties;
std::vector<nsecs_t> mSampleEventTimes;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 898d1a9..ff33678 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -136,6 +136,8 @@
float yPrecision;
float xCursorPosition;
float yCursorPosition;
+ int32_t displayWidth;
+ int32_t displayHeight;
uint32_t pointerCount;
uint32_t empty3;
/**
@@ -353,8 +355,9 @@
int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform,
float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
- uint32_t pointerCount, const PointerProperties* pointerProperties,
+ float yCursorPosition, int32_t displayWidth, int32_t displayHeight,
+ nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
+ const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
/* Publishes a focus event to the input channel.
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 36097d6..121be6d 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -168,6 +168,10 @@
// Transform applied to individual windows.
ui::Transform transform;
+ // Display size in its natural rotation. Used to rotate raw coordinates for compatibility.
+ int32_t displayWidth = AMOTION_EVENT_INVALID_DISPLAY_SIZE;
+ int32_t displayHeight = AMOTION_EVENT_INVALID_DISPLAY_SIZE;
+
/*
* This is filled in by the WM relative to the frame and then translated
* to absolute coordinates by SurfaceFlinger once the frame is computed.
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index d964d25..d5bdd1c 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -29,6 +29,16 @@
namespace android {
+// Service implementations inherit from BBinder and IBinder, and this is frozen
+// in prebuilts.
+#ifdef __LP64__
+static_assert(sizeof(IBinder) == 24);
+static_assert(sizeof(BBinder) == 40);
+#else
+static_assert(sizeof(IBinder) == 12);
+static_assert(sizeof(BBinder) == 20);
+#endif
+
// ---------------------------------------------------------------------------
IBinder::IBinder()
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index a735309..cbe590f 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -78,7 +78,11 @@
namespace android {
// many things compile this into prebuilts on the stack
-static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
+#ifdef __LP64__
+static_assert(sizeof(Parcel) == 120);
+#else
+static_assert(sizeof(Parcel) == 60);
+#endif
static std::atomic<size_t> gParcelGlobalAllocCount;
static std::atomic<size_t> gParcelGlobalAllocSize;
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index ee5f508..4b3a53f 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -18,13 +18,7 @@
#include <binder/RpcConnection.h>
-#include <arpa/inet.h>
#include <inttypes.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
#include <unistd.h>
#include <string_view>
@@ -33,6 +27,7 @@
#include <binder/Stability.h>
#include <utils/String8.h>
+#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"
@@ -40,62 +35,9 @@
extern "C" pid_t gettid();
#endif
-#ifdef __BIONIC__
-#include <linux/vm_sockets.h>
-#endif
-
namespace android {
-using base::borrowed_fd;
using base::unique_fd;
-using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
-
-namespace {
-bool checkSockaddrSize(const char* name, size_t actual, size_t expected) {
- if (actual >= expected) return true;
- ALOGW("getSockaddrPort: family is %s but size is %zu < %zu", name, actual, expected);
- return false;
-}
-
-// Get the port number of |storage| for certain families. Requires storage->sa_family to be
-// set to a known family; otherwise, return nullopt.
-std::optional<unsigned int> getSockaddrPort(const sockaddr* storage, socklen_t len) {
- switch (storage->sa_family) {
- case AF_INET: {
- if (!checkSockaddrSize("INET", len, sizeof(sockaddr_in))) return std::nullopt;
- auto inetStorage = reinterpret_cast<const sockaddr_in*>(storage);
- return ntohs(inetStorage->sin_port);
- }
- default: {
- uint16_t family = storage->sa_family;
- ALOGW("Don't know how to infer port for family %" PRIu16, family);
- return std::nullopt;
- }
- }
-}
-
-std::optional<unsigned int> getSocketPort(borrowed_fd socketfd,
- const RpcConnection::SocketAddress& socketAddress) {
- sockaddr_storage storage{};
- socklen_t len = sizeof(storage);
- auto storagePtr = reinterpret_cast<sockaddr*>(&storage);
- if (0 != getsockname(socketfd.get(), storagePtr, &len)) {
- int savedErrno = errno;
- ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
- strerror(savedErrno));
- return std::nullopt;
- }
-
- // getsockname does not fill in family, but getSockaddrPort() needs it.
- if (storage.ss_family == AF_UNSPEC) {
- storage.ss_family = socketAddress.addr()->sa_family;
- }
- return getSockaddrPort(storagePtr, len);
-}
-
-} // namespace
-
-RpcConnection::SocketAddress::~SocketAddress() {}
RpcConnection::RpcConnection() {
LOG_RPC_DETAIL("RpcConnection created %p", this);
@@ -114,134 +56,20 @@
return sp<RpcConnection>::make();
}
-class UnixSocketAddress : public RpcConnection::SocketAddress {
-public:
- explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
- unsigned int pathLen = strlen(path) + 1;
- LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s",
- pathLen, path);
- memcpy(mAddr.sun_path, path, pathLen);
- }
- virtual ~UnixSocketAddress() {}
- std::string toString() const override {
- return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
- mAddr.sun_path)
- .c_str();
- }
- const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
- size_t addrSize() const override { return sizeof(mAddr); }
-
-private:
- sockaddr_un mAddr;
-};
-
-bool RpcConnection::setupUnixDomainServer(const char* path) {
- return setupSocketServer(UnixSocketAddress(path));
-}
-
bool RpcConnection::setupUnixDomainClient(const char* path) {
return setupSocketClient(UnixSocketAddress(path));
}
#ifdef __BIONIC__
-class VsockSocketAddress : public RpcConnection::SocketAddress {
-public:
- VsockSocketAddress(unsigned int cid, unsigned int port)
- : mAddr({
- .svm_family = AF_VSOCK,
- .svm_port = port,
- .svm_cid = cid,
- }) {}
- virtual ~VsockSocketAddress() {}
- std::string toString() const override {
- return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str();
- }
- const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
- size_t addrSize() const override { return sizeof(mAddr); }
-
-private:
- sockaddr_vm mAddr;
-};
-
-bool RpcConnection::setupVsockServer(unsigned int port) {
- // realizing value w/ this type at compile time to avoid ubsan abort
- constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
-
- return setupSocketServer(VsockSocketAddress(kAnyCid, port));
-}
-
bool RpcConnection::setupVsockClient(unsigned int cid, unsigned int port) {
return setupSocketClient(VsockSocketAddress(cid, port));
}
#endif // __BIONIC__
-class InetSocketAddress : public RpcConnection::SocketAddress {
-public:
- InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port)
- : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {}
- [[nodiscard]] std::string toString() const override {
- return String8::format("%s:%u", mAddr, mPort).c_str();
- }
- [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; }
- [[nodiscard]] size_t addrSize() const override { return mSize; }
-
-private:
- const sockaddr* mSockAddr;
- size_t mSize;
- const char* mAddr;
- unsigned int mPort;
-};
-
-AddrInfo GetAddrInfo(const char* addr, unsigned int port) {
- addrinfo hint{
- .ai_flags = 0,
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_STREAM,
- .ai_protocol = 0,
- };
- addrinfo* aiStart = nullptr;
- if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) {
- ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc));
- return AddrInfo(nullptr, nullptr);
- }
- if (aiStart == nullptr) {
- ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port);
- return AddrInfo(nullptr, nullptr);
- }
- return AddrInfo(aiStart, &freeaddrinfo);
-}
-
-bool RpcConnection::setupInetServer(unsigned int port, unsigned int* assignedPort) {
- const char* kAddr = "127.0.0.1";
-
- if (assignedPort != nullptr) *assignedPort = 0;
- auto aiStart = GetAddrInfo(kAddr, port);
- if (aiStart == nullptr) return false;
- for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
- InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
- if (!setupSocketServer(socketAddress)) {
- continue;
- }
- auto realPort = getSocketPort(mServer.get(), socketAddress);
- LOG_ALWAYS_FATAL_IF(!realPort.has_value(), "Unable to get port number after setting up %s",
- socketAddress.toString().c_str());
- LOG_ALWAYS_FATAL_IF(port != 0 && *realPort != port,
- "Requesting inet server on %s but it is set up on %u.",
- socketAddress.toString().c_str(), *realPort);
- if (assignedPort != nullptr) {
- *assignedPort = *realPort;
- }
- return true;
- }
- ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
- port);
- return false;
-}
-
bool RpcConnection::setupInetClient(const char* addr, unsigned int port) {
- auto aiStart = GetAddrInfo(addr, port);
+ auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
if (aiStart == nullptr) return false;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
@@ -287,23 +115,43 @@
return state()->sendDecStrong(socket.fd(), address);
}
-void RpcConnection::join() {
- // TODO(b/185167543): do this dynamically, instead of from a static number
- // of threads
- unique_fd clientFd(
- TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
- if (clientFd < 0) {
- // If this log becomes confusing, should save more state from setupUnixDomainServer
- // in order to output here.
- ALOGE("Could not accept4 socket: %s", strerror(errno));
- return;
+status_t RpcConnection::readId() {
+ {
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ LOG_ALWAYS_FATAL_IF(mForServer != nullptr, "Can only update ID for client.");
}
- LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+ int32_t id;
+ ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
+ status_t status =
+ state()->getConnectionId(socket.fd(), sp<RpcConnection>::fromExisting(this), &id);
+ if (status != OK) return status;
+
+ LOG_RPC_DETAIL("RpcConnection %p has id %d", this, id);
+ mId = id;
+ return OK;
+}
+
+void RpcConnection::startThread(unique_fd client) {
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ sp<RpcConnection> holdThis = sp<RpcConnection>::fromExisting(this);
+ int fd = client.release();
+ auto thread = std::thread([=] {
+ holdThis->join(unique_fd(fd));
+ {
+ std::lock_guard<std::mutex> _l(holdThis->mSocketMutex);
+ size_t erased = mThreads.erase(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(erased != 0, "Could not erase thread.");
+ }
+ });
+ mThreads[thread.get_id()] = std::move(thread);
+}
+
+void RpcConnection::join(unique_fd client) {
// must be registered to allow arbitrary client code executing commands to
// be able to do nested calls (we can't only read from it)
- sp<ConnectionSocket> socket = assignServerToThisThread(std::move(clientFd));
+ sp<ConnectionSocket> socket = assignServerToThisThread(std::move(client));
while (true) {
status_t error =
@@ -319,41 +167,11 @@
"bad state: socket object guaranteed to be in list");
}
-void RpcConnection::setForServer(const wp<RpcServer>& server) {
- mForServer = server;
-}
-
wp<RpcServer> RpcConnection::server() {
return mForServer;
}
-bool RpcConnection::setupSocketServer(const SocketAddress& addr) {
- LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server.");
-
- unique_fd serverFd(
- TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
- if (serverFd == -1) {
- ALOGE("Could not create socket: %s", strerror(errno));
- return false;
- }
-
- if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
- int savedErrno = errno;
- ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
- return false;
- }
-
- if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
- int savedErrno = errno;
- ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
- return false;
- }
-
- mServer = std::move(serverFd);
- return true;
-}
-
-bool RpcConnection::setupSocketClient(const SocketAddress& addr) {
+bool RpcConnection::setupSocketClient(const RpcSocketAddress& addr) {
{
std::lock_guard<std::mutex> _l(mSocketMutex);
LOG_ALWAYS_FATAL_IF(mClients.size() != 0,
@@ -361,7 +179,7 @@
mClients.size());
}
- if (!setupOneSocketClient(addr)) return false;
+ if (!setupOneSocketClient(addr, RPC_CONNECTION_ID_NEW)) return false;
// TODO(b/185167543): we should add additional connections dynamically
// instead of all at once.
@@ -373,11 +191,17 @@
return false;
}
+ if (status_t status = readId(); status != OK) {
+ ALOGE("Could not get connection id after initial connection to %s; %s",
+ addr.toString().c_str(), statusToString(status).c_str());
+ return false;
+ }
+
// we've already setup one client
for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
// TODO(b/185167543): avoid race w/ accept4 not being called on server
for (size_t tries = 0; tries < 5; tries++) {
- if (setupOneSocketClient(addr)) break;
+ if (setupOneSocketClient(addr, mId.value())) break;
usleep(10000);
}
}
@@ -385,7 +209,7 @@
return true;
}
-bool RpcConnection::setupOneSocketClient(const SocketAddress& addr) {
+bool RpcConnection::setupOneSocketClient(const RpcSocketAddress& addr, int32_t id) {
unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
if (serverFd == -1) {
@@ -400,20 +224,32 @@
return false;
}
+ if (sizeof(id) != TEMP_FAILURE_RETRY(write(serverFd.get(), &id, sizeof(id)))) {
+ int savedErrno = errno;
+ ALOGE("Could not write id to socket at %s: %s", addr.toString().c_str(),
+ strerror(savedErrno));
+ return false;
+ }
+
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
addClient(std::move(serverFd));
return true;
}
-void RpcConnection::addClient(unique_fd&& fd) {
+void RpcConnection::addClient(unique_fd fd) {
std::lock_guard<std::mutex> _l(mSocketMutex);
sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
connection->fd = std::move(fd);
mClients.push_back(connection);
}
-sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd&& fd) {
+void RpcConnection::setForServer(const wp<RpcServer>& server, int32_t connectionId) {
+ mId = connectionId;
+ mForServer = server;
+}
+
+sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd fd) {
std::lock_guard<std::mutex> _l(mSocketMutex);
sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
connection->fd = std::move(fd);
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 8f2805f..4df12ce 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -27,10 +27,13 @@
#include <log/log.h>
#include "RpcState.h"
+#include "RpcSocketAddress.h"
#include "RpcWireFormat.h"
namespace android {
+using base::unique_fd;
+
RpcServer::RpcServer() {}
RpcServer::~RpcServer() {}
@@ -42,14 +45,63 @@
mAgreedExperimental = true;
}
+bool RpcServer::setupUnixDomainServer(const char* path) {
+ return setupSocketServer(UnixSocketAddress(path));
+}
+
+#ifdef __BIONIC__
+
+bool RpcServer::setupVsockServer(unsigned int port) {
+ // realizing value w/ this type at compile time to avoid ubsan abort
+ constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
+
+ return setupSocketServer(VsockSocketAddress(kAnyCid, port));
+}
+
+#endif // __BIONIC__
+
+bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
+ const char* kAddr = "127.0.0.1";
+
+ if (assignedPort != nullptr) *assignedPort = 0;
+ auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port);
+ if (aiStart == nullptr) return false;
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
+ if (!setupSocketServer(socketAddress)) {
+ continue;
+ }
+
+ LOG_ALWAYS_FATAL_IF(socketAddress.addr()->sa_family != AF_INET, "expecting inet");
+ sockaddr_in addr{};
+ socklen_t len = sizeof(addr);
+ if (0 != getsockname(mServer.get(), reinterpret_cast<sockaddr*>(&addr), &len)) {
+ int savedErrno = errno;
+ ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
+ strerror(savedErrno));
+ return false;
+ }
+ LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu",
+ static_cast<size_t>(len), sizeof(addr));
+ unsigned int realPort = ntohs(addr.sin_port);
+ LOG_ALWAYS_FATAL_IF(port != 0 && realPort != port,
+ "Requesting inet server on %s but it is set up on %u.",
+ socketAddress.toString().c_str(), realPort);
+
+ if (assignedPort != nullptr) {
+ *assignedPort = realPort;
+ }
+
+ return true;
+ }
+ ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
+ port);
+ return false;
+}
+
void RpcServer::setMaxThreads(size_t threads) {
LOG_ALWAYS_FATAL_IF(threads <= 0, "RpcServer is useless without threads");
- {
- // this lock should only ever be needed in the error case
- std::lock_guard<std::mutex> _l(mLock);
- LOG_ALWAYS_FATAL_IF(mConnections.size() > 0,
- "Must specify max threads before creating a connection");
- }
+ LOG_ALWAYS_FATAL_IF(mStarted, "must be called before started");
mMaxThreads = threads;
}
@@ -67,35 +119,97 @@
return mRootObject;
}
-sp<RpcConnection> RpcServer::addClientConnection() {
+void RpcServer::join() {
LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
- auto connection = RpcConnection::make();
- connection->setForServer(sp<RpcServer>::fromExisting(this));
- {
- std::lock_guard<std::mutex> _l(mLock);
- LOG_ALWAYS_FATAL_IF(mStarted,
- "currently only supports adding client connections at creation time");
- mConnections.push_back(connection);
- }
- return connection;
-}
-
-void RpcServer::join() {
std::vector<std::thread> pool;
{
std::lock_guard<std::mutex> _l(mLock);
- mStarted = true;
- for (const sp<RpcConnection>& connection : mConnections) {
- for (size_t i = 0; i < mMaxThreads; i++) {
- pool.push_back(std::thread([=] { connection->join(); }));
- }
- }
+ LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join.");
}
- // TODO(b/185167543): don't waste extra thread for join, and combine threads
- // between clients
- for (auto& t : pool) t.join();
+ while (true) {
+ unique_fd clientFd(
+ TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
+
+ if (clientFd < 0) {
+ ALOGE("Could not accept4 socket: %s", strerror(errno));
+ continue;
+ }
+ LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
+ // TODO(b/183988761): cannot trust this simple ID
+ LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+ int32_t id;
+ if (sizeof(id) != read(clientFd.get(), &id, sizeof(id))) {
+ ALOGE("Could not read ID from fd %d", clientFd.get());
+ continue;
+ }
+
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+
+ sp<RpcConnection> connection;
+ if (id == RPC_CONNECTION_ID_NEW) {
+ // new client!
+ LOG_ALWAYS_FATAL_IF(mConnectionIdCounter >= INT32_MAX, "Out of connection IDs");
+ mConnectionIdCounter++;
+
+ connection = RpcConnection::make();
+ connection->setForServer(wp<RpcServer>::fromExisting(this), mConnectionIdCounter);
+
+ mConnections[mConnectionIdCounter] = connection;
+ } else {
+ auto it = mConnections.find(id);
+ if (it == mConnections.end()) {
+ ALOGE("Cannot add thread, no record of connection with ID %d", id);
+ continue;
+ }
+ connection = it->second;
+ }
+
+ connection->startThread(std::move(clientFd));
+ }
+ }
+}
+
+std::vector<sp<RpcConnection>> RpcServer::listConnections() {
+ std::lock_guard<std::mutex> _l(mLock);
+ std::vector<sp<RpcConnection>> connections;
+ for (auto& [id, connection] : mConnections) {
+ (void)id;
+ connections.push_back(connection);
+ }
+ return connections;
+}
+
+bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcServer can only have one server.");
+ }
+
+ unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ if (serverFd == -1) {
+ ALOGE("Could not create socket: %s", strerror(errno));
+ return false;
+ }
+
+ if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ int savedErrno = errno;
+ ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
+ int savedErrno = errno;
+ ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ mServer = std::move(serverFd);
+ return true;
}
} // namespace android
diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h
new file mode 100644
index 0000000..c6a06cf
--- /dev/null
+++ b/libs/binder/RpcSocketAddress.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 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 <string>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#endif
+
+namespace android {
+
+class RpcSocketAddress {
+public:
+ virtual ~RpcSocketAddress() {}
+ virtual std::string toString() const = 0;
+ virtual const sockaddr* addr() const = 0;
+ virtual size_t addrSize() const = 0;
+};
+
+class UnixSocketAddress : public RpcSocketAddress {
+public:
+ explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
+ unsigned int pathLen = strlen(path) + 1;
+ LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s",
+ pathLen, path);
+ memcpy(mAddr.sun_path, path, pathLen);
+ }
+ virtual ~UnixSocketAddress() {}
+ std::string toString() const override {
+ return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
+ mAddr.sun_path)
+ .c_str();
+ }
+ const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+ size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+ sockaddr_un mAddr;
+};
+
+#ifdef __BIONIC__
+
+class VsockSocketAddress : public RpcSocketAddress {
+public:
+ VsockSocketAddress(unsigned int cid, unsigned int port)
+ : mAddr({
+ .svm_family = AF_VSOCK,
+ .svm_port = port,
+ .svm_cid = cid,
+ }) {}
+ virtual ~VsockSocketAddress() {}
+ std::string toString() const override {
+ return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str();
+ }
+ const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+ size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+ sockaddr_vm mAddr;
+};
+
+#endif // __BIONIC__
+
+class InetSocketAddress : public RpcSocketAddress {
+public:
+ InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port)
+ : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {}
+ [[nodiscard]] std::string toString() const override {
+ return String8::format("%s:%u", mAddr, mPort).c_str();
+ }
+ [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; }
+ [[nodiscard]] size_t addrSize() const override { return mSize; }
+
+ using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
+ static AddrInfo getAddrInfo(const char* addr, unsigned int port) {
+ addrinfo hint{
+ .ai_flags = 0,
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = 0,
+ };
+ addrinfo* aiStart = nullptr;
+ if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) {
+ ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc));
+ return AddrInfo(nullptr, nullptr);
+ }
+ if (aiStart == nullptr) {
+ ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port);
+ return AddrInfo(nullptr, nullptr);
+ }
+ return AddrInfo(aiStart, &freeaddrinfo);
+ }
+
+private:
+ const sockaddr* mSockAddr;
+ size_t mSize;
+ const char* mAddr;
+ unsigned int mPort;
+};
+
+} // namespace android
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 6bfcc42..19dea7e 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -249,7 +249,7 @@
}
status_t RpcState::getMaxThreads(const base::unique_fd& fd, const sp<RpcConnection>& connection,
- size_t* maxThreads) {
+ size_t* maxThreadsOut) {
Parcel data;
data.markForRpc(connection);
Parcel reply;
@@ -261,15 +261,36 @@
return status;
}
- int32_t threads;
- status = reply.readInt32(&threads);
+ int32_t maxThreads;
+ status = reply.readInt32(&maxThreads);
if (status != OK) return status;
- if (threads <= 0) {
- ALOGE("Error invalid max threads: %d", threads);
+ if (maxThreads <= 0) {
+ ALOGE("Error invalid max maxThreads: %d", maxThreads);
return BAD_VALUE;
}
- *maxThreads = threads;
+ *maxThreadsOut = maxThreads;
+ return OK;
+}
+
+status_t RpcState::getConnectionId(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+ int32_t* connectionIdOut) {
+ Parcel data;
+ data.markForRpc(connection);
+ Parcel reply;
+
+ status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_CONNECTION_ID, data,
+ connection, &reply, 0);
+ if (status != OK) {
+ ALOGE("Error getting connection ID: %s", statusToString(status).c_str());
+ return status;
+ }
+
+ int32_t connectionId;
+ status = reply.readInt32(&connectionId);
+ if (status != OK) return status;
+
+ *connectionIdOut = connectionId;
return OK;
}
@@ -554,6 +575,16 @@
replyStatus = reply.writeInt32(server->getMaxThreads());
break;
}
+ case RPC_SPECIAL_TRANSACT_GET_CONNECTION_ID: {
+ // only connections w/ services can be the source of a
+ // connection ID (so still guarded by non-null server)
+ //
+ // connections associated with servers must have an ID
+ // (hence abort)
+ int32_t id = connection->getPrivateAccessorForId().get().value();
+ replyStatus = reply.writeInt32(id);
+ break;
+ }
default: {
replyStatus = UNKNOWN_TRANSACTION;
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 1cfa406..825fd7c 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -50,9 +50,12 @@
RpcState();
~RpcState();
+ // TODO(b/182940634): combine some special transactions into one "getServerInfo" call?
sp<IBinder> getRootObject(const base::unique_fd& fd, const sp<RpcConnection>& connection);
status_t getMaxThreads(const base::unique_fd& fd, const sp<RpcConnection>& connection,
size_t* maxThreadsOut);
+ status_t getConnectionId(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+ int32_t* connectionIdOut);
[[nodiscard]] status_t transact(const base::unique_fd& fd, const RpcAddress& address,
uint32_t code, const Parcel& data,
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index cc7cacb..a7e8a52 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -48,8 +48,11 @@
enum : uint32_t {
RPC_SPECIAL_TRANSACT_GET_ROOT = 0,
RPC_SPECIAL_TRANSACT_GET_MAX_THREADS = 1,
+ RPC_SPECIAL_TRANSACT_GET_CONNECTION_ID = 2,
};
+constexpr int32_t RPC_CONNECTION_ID_NEW = -1;
+
// serialization is like:
// |RpcWireHeader|struct desginated by 'command'| (over and over again)
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 52f221d..97c826c 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android-base/unique_fd.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
index 3a2d8e5..87984d7 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -21,7 +21,9 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <map>
#include <optional>
+#include <thread>
#include <vector>
// WARNING: This is a feature which is still in development, and it is subject
@@ -32,6 +34,7 @@
class Parcel;
class RpcServer;
+class RpcSocketAddress;
class RpcState;
/**
@@ -43,19 +46,6 @@
static sp<RpcConnection> make();
/**
- * This represents a connection for responses, e.g.:
- *
- * process A serves binder a
- * process B opens a connection to process A
- * process B makes binder b and sends it to A
- * A uses this 'back connection' to send things back to B
- *
- * This should be called once, and then a call should be made to join per
- * connection thread.
- */
- [[nodiscard]] bool setupUnixDomainServer(const char* path);
-
- /**
* This should be called once per thread, matching 'join' in the remote
* process.
*/
@@ -63,28 +53,12 @@
#ifdef __BIONIC__
/**
- * Creates an RPC server at the current port.
- */
- [[nodiscard]] bool setupVsockServer(unsigned int port);
-
- /**
* Connects to an RPC server at the CVD & port.
*/
[[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
#endif // __BIONIC__
/**
- * Creates an RPC server at the current port using IPv4.
- *
- * TODO(b/182914638): IPv6 support
- *
- * Set |port| to 0 to pick an ephemeral port; see discussion of
- * /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort|
- * will be set to the picked port number, if it is not null.
- */
- [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
-
- /**
* Connects to an RPC server at the given address and port.
*/
[[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
@@ -116,26 +90,33 @@
~RpcConnection();
- void setForServer(const wp<RpcServer>& server);
wp<RpcServer> server();
// internal only
const std::unique_ptr<RpcState>& state() { return mState; }
- class SocketAddress {
- public:
- virtual ~SocketAddress();
- virtual std::string toString() const = 0;
- virtual const sockaddr* addr() const = 0;
- virtual size_t addrSize() const = 0;
+ class PrivateAccessorForId {
+ private:
+ friend class RpcConnection;
+ friend class RpcState;
+ explicit PrivateAccessorForId(const RpcConnection* connection) : mConnection(connection) {}
+
+ const std::optional<int32_t> get() { return mConnection->mId; }
+
+ const RpcConnection* mConnection;
};
+ PrivateAccessorForId getPrivateAccessorForId() const { return PrivateAccessorForId(this); }
private:
+ friend PrivateAccessorForId;
friend sp<RpcConnection>;
friend RpcServer;
RpcConnection();
- void join();
+ status_t readId();
+
+ void startThread(base::unique_fd client);
+ void join(base::unique_fd client);
struct ConnectionSocket : public RefBase {
base::unique_fd fd;
@@ -145,11 +126,11 @@
std::optional<pid_t> exclusiveTid;
};
- bool setupSocketServer(const SocketAddress& address);
- bool setupSocketClient(const SocketAddress& address);
- bool setupOneSocketClient(const SocketAddress& address);
- void addClient(base::unique_fd&& fd);
- sp<ConnectionSocket> assignServerToThisThread(base::unique_fd&& fd);
+ bool setupSocketClient(const RpcSocketAddress& address);
+ bool setupOneSocketClient(const RpcSocketAddress& address, int32_t connectionId);
+ void addClient(base::unique_fd fd);
+ void setForServer(const wp<RpcServer>& server, int32_t connectionId);
+ sp<ConnectionSocket> assignServerToThisThread(base::unique_fd fd);
bool removeServerSocket(const sp<ConnectionSocket>& socket);
enum class SocketUse {
@@ -195,16 +176,24 @@
wp<RpcServer> mForServer; // maybe null, for client connections
+ // TODO(b/183988761): this shouldn't be guessable
+ std::optional<int32_t> mId;
+
std::unique_ptr<RpcState> mState;
- base::unique_fd mServer; // socket we are accepting connections on
-
std::mutex mSocketMutex; // for all below
+
std::condition_variable mSocketCv; // for mWaitingThreads
size_t mWaitingThreads = 0;
size_t mClientsOffset = 0; // hint index into clients, ++ when sending an async transaction
std::vector<sp<ConnectionSocket>> mClients;
std::vector<sp<ConnectionSocket>> mServers;
+
+ // TODO(b/185167543): use for reverse connections (allow client to also
+ // serve calls on a connection).
+ // TODO(b/185167543): allow sharing between different connections in a
+ // process? (or combine with mServers)
+ std::map<std::thread::id, std::thread> mThreads;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 9247128..81ea3a7 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -29,14 +29,52 @@
namespace android {
+class RpcSocketAddress;
+
/**
* This represents a server of an interface, which may be connected to by any
* number of clients over sockets.
+ *
+ * Usage:
+ * auto server = RpcServer::make();
+ * // only supports one now
+ * if (!server->setup*Server(...)) {
+ * :(
+ * }
+ * server->join();
*/
class RpcServer final : public virtual RefBase {
public:
static sp<RpcServer> make();
+ /**
+ * This represents a connection for responses, e.g.:
+ *
+ * process A serves binder a
+ * process B opens a connection to process A
+ * process B makes binder b and sends it to A
+ * A uses this 'back connection' to send things back to B
+ */
+ [[nodiscard]] bool setupUnixDomainServer(const char* path);
+
+#ifdef __BIONIC__
+ /**
+ * Creates an RPC server at the current port.
+ */
+ [[nodiscard]] bool setupVsockServer(unsigned int port);
+#endif // __BIONIC__
+
+ /**
+ * Creates an RPC server at the current port using IPv4.
+ *
+ * TODO(b/182914638): IPv6 support
+ *
+ * Set |port| to 0 to pick an ephemeral port; see discussion of
+ * /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort|
+ * will be set to the picked port number, if it is not null.
+ */
+ [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
+
void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
/**
@@ -58,33 +96,34 @@
sp<IBinder> getRootObject();
/**
- * Setup a static connection, when the number of clients are known.
- *
- * Each call to this function corresponds to a different client, and clients
- * each have their own threadpools.
- *
- * TODO(b/167966510): support dynamic creation of connections/threads
- */
- sp<RpcConnection> addClientConnection();
-
- /**
* You must have at least one client connection before calling this.
+ *
+ * TODO(b/185167543): way to shut down?
*/
void join();
+ /**
+ * For debugging!
+ */
+ std::vector<sp<RpcConnection>> listConnections();
+
~RpcServer();
private:
friend sp<RpcServer>;
RpcServer();
+ bool setupSocketServer(const RpcSocketAddress& address);
+
bool mAgreedExperimental = false;
bool mStarted = false; // TODO(b/185167543): support dynamically added clients
size_t mMaxThreads = 1;
+ base::unique_fd mServer; // socket we are accepting connections on
std::mutex mLock; // for below
sp<IBinder> mRootObject;
- std::vector<sp<RpcConnection>> mConnections; // per-client
+ std::map<int32_t, sp<RpcConnection>> mConnections;
+ int32_t mConnectionIdCounter = 0;
};
} // namespace android
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index 2bdb264..814e094 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -18,8 +18,8 @@
oneway void sendString(@utf8InCpp String str);
@utf8InCpp String doubleString(@utf8InCpp String str);
- // number of known RPC binders to process, RpcState::countBinders
- int countBinders();
+ // number of known RPC binders to process, RpcState::countBinders by connection
+ int[] countBinders();
// Caller sends server, callee pings caller's server and returns error code.
int pingMe(IBinder binder);
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index b3282ff..ce47c0d 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -121,12 +121,8 @@
std::thread([addr]() {
sp<RpcServer> server = RpcServer::make();
server->setRootObject(sp<MyBinderRpcBenchmark>::make());
-
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-
- sp<RpcConnection> connection = server->addClientConnection();
- CHECK(connection->setupUnixDomainServer(addr.c_str()));
-
+ CHECK(server->setupUnixDomainServer(addr.c_str()));
server->join();
}).detach();
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index f3ec904..50bff91 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -78,7 +78,7 @@
class MyBinderRpcTest : public BnBinderRpcTest {
public:
- sp<RpcConnection> connection;
+ wp<RpcServer> server;
Status sendString(const std::string& str) override {
(void)str;
@@ -88,13 +88,20 @@
*strstr = str + str;
return Status::ok();
}
- Status countBinders(int32_t* out) override {
- if (connection == nullptr) {
+ Status countBinders(std::vector<int32_t>* out) override {
+ sp<RpcServer> spServer = server.promote();
+ if (spServer == nullptr) {
return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}
- *out = connection->state()->countBinders();
- if (*out != 1) {
- connection->state()->dump();
+ out->clear();
+ for (auto connection : spServer->listConnections()) {
+ size_t count = connection->state()->countBinders();
+ if (count != 1) {
+ // this is called when there is only one binder held remaining,
+ // so to aid debugging
+ connection->state()->dump();
+ }
+ out->push_back(count);
}
return Status::ok();
}
@@ -222,25 +229,33 @@
// reference to process hosting a socket server
Process host;
- // client connection object associated with other process
- sp<RpcConnection> connection;
+ struct ConnectionInfo {
+ sp<RpcConnection> connection;
+ sp<IBinder> root;
+ };
- // pre-fetched root object
- sp<IBinder> rootBinder;
-
- // whether connection should be invalidated by end of run
- bool expectInvalid = false;
+ // client connection objects associated with other process
+ // each one represents a separate connection
+ std::vector<ConnectionInfo> connections;
ProcessConnection(ProcessConnection&&) = default;
~ProcessConnection() {
- rootBinder = nullptr;
- EXPECT_NE(nullptr, connection);
- EXPECT_NE(nullptr, connection->state());
- EXPECT_EQ(0, connection->state()->countBinders()) << (connection->state()->dump(), "dump:");
+ for (auto& connection : connections) {
+ connection.root = nullptr;
+ }
- wp<RpcConnection> weakConnection = connection;
- connection = nullptr;
- EXPECT_EQ(nullptr, weakConnection.promote()) << "Leaked connection";
+ for (auto& info : connections) {
+ sp<RpcConnection>& connection = info.connection;
+
+ EXPECT_NE(nullptr, connection);
+ EXPECT_NE(nullptr, connection->state());
+ EXPECT_EQ(0, connection->state()->countBinders())
+ << (connection->state()->dump(), "dump:");
+
+ wp<RpcConnection> weakConnection = connection;
+ connection = nullptr;
+ EXPECT_EQ(nullptr, weakConnection.promote()) << "Leaked connection";
+ }
}
};
@@ -249,19 +264,25 @@
struct BinderRpcTestProcessConnection {
ProcessConnection proc;
- // pre-fetched root object
+ // pre-fetched root object (for first connection)
sp<IBinder> rootBinder;
- // pre-casted root object
+ // pre-casted root object (for first connection)
sp<IBinderRpcTest> rootIface;
+ // whether connection should be invalidated by end of run
+ bool expectInvalid = false;
+
BinderRpcTestProcessConnection(BinderRpcTestProcessConnection&&) = default;
~BinderRpcTestProcessConnection() {
- if (!proc.expectInvalid) {
- int32_t remoteBinders = 0;
- EXPECT_OK(rootIface->countBinders(&remoteBinders));
- // should only be the root binder object, iface
- EXPECT_EQ(remoteBinders, 1);
+ if (!expectInvalid) {
+ std::vector<int32_t> remoteCounts;
+ // calling over any connections counts across all connections
+ EXPECT_OK(rootIface->countBinders(&remoteCounts));
+ EXPECT_EQ(remoteCounts.size(), proc.connections.size());
+ for (auto remoteCount : remoteCounts) {
+ EXPECT_EQ(remoteCount, 1);
+ }
}
rootIface = nullptr;
@@ -296,8 +317,10 @@
// This creates a new process serving an interface on a certain number of
// threads.
ProcessConnection createRpcTestSocketServerProcess(
- size_t numThreads,
- const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
+ size_t numThreads, size_t numConnections,
+ const std::function<void(const sp<RpcServer>&)>& configure) {
+ CHECK_GE(numConnections, 1) << "Must have at least one connection to a server";
+
SocketType socketType = GetParam();
std::string addr = allocateSocketAddress();
@@ -312,21 +335,18 @@
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
server->setMaxThreads(numThreads);
- // server supporting one client on one socket
- sp<RpcConnection> connection = server->addClientConnection();
-
switch (socketType) {
case SocketType::UNIX:
- CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr;
+ CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
break;
#ifdef __BIONIC__
case SocketType::VSOCK:
- CHECK(connection->setupVsockServer(vsockPort));
+ CHECK(server->setupVsockServer(vsockPort));
break;
#endif // __BIONIC__
case SocketType::INET: {
unsigned int outPort = 0;
- CHECK(connection->setupInetServer(0, &outPort));
+ CHECK(server->setupInetServer(0, &outPort));
CHECK_NE(0, outPort);
CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort,
sizeof(outPort)));
@@ -336,11 +356,10 @@
LOG_ALWAYS_FATAL("Unknown socket type");
}
- configure(server, connection);
+ configure(server);
server->join();
}),
- .connection = RpcConnection::make(),
};
unsigned int inetPort = 0;
@@ -350,46 +369,46 @@
CHECK_NE(0, inetPort);
}
- // create remainder of connections
- for (size_t tries = 0; tries < 10; tries++) {
- usleep(10000);
- switch (socketType) {
- case SocketType::UNIX:
- if (ret.connection->setupUnixDomainClient(addr.c_str())) goto success;
- break;
+ for (size_t i = 0; i < numConnections; i++) {
+ sp<RpcConnection> connection = RpcConnection::make();
+ for (size_t tries = 0; tries < 10; tries++) {
+ usleep(10000);
+ switch (socketType) {
+ case SocketType::UNIX:
+ if (connection->setupUnixDomainClient(addr.c_str())) goto success;
+ break;
#ifdef __BIONIC__
- case SocketType::VSOCK:
- if (ret.connection->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
- break;
+ case SocketType::VSOCK:
+ if (connection->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
+ break;
#endif // __BIONIC__
- case SocketType::INET:
- if (ret.connection->setupInetClient("127.0.0.1", inetPort)) goto success;
- break;
- default:
- LOG_ALWAYS_FATAL("Unknown socket type");
+ case SocketType::INET:
+ if (connection->setupInetClient("127.0.0.1", inetPort)) goto success;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ }
}
+ LOG_ALWAYS_FATAL("Could not connect");
+ success:
+ ret.connections.push_back({connection, connection->getRootObject()});
}
- LOG_ALWAYS_FATAL("Could not connect");
- success:
-
- ret.rootBinder = ret.connection->getRootObject();
return ret;
}
- BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
+ BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads,
+ size_t numConnections = 1) {
BinderRpcTestProcessConnection ret{
- .proc = createRpcTestSocketServerProcess(numThreads,
- [&](const sp<RpcServer>& server,
- const sp<RpcConnection>& connection) {
+ .proc = createRpcTestSocketServerProcess(numThreads, numConnections,
+ [&](const sp<RpcServer>& server) {
sp<MyBinderRpcTest> service =
new MyBinderRpcTest;
server->setRootObject(service);
- service->connection =
- connection; // for testing only
+ service->server = server;
}),
};
- ret.rootBinder = ret.proc.rootBinder;
+ ret.rootBinder = ret.proc.connections.at(0).root;
ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
return ret;
@@ -397,18 +416,12 @@
};
TEST_P(BinderRpc, RootObjectIsNull) {
- auto proc = createRpcTestSocketServerProcess(1,
- [](const sp<RpcServer>& server,
- const sp<RpcConnection>&) {
- // this is the default, but to be explicit
- server->setRootObject(nullptr);
- });
+ auto proc = createRpcTestSocketServerProcess(1, 1, [](const sp<RpcServer>& server) {
+ // this is the default, but to be explicit
+ server->setRootObject(nullptr);
+ });
- // retrieved by getRootObject when process is created above
- EXPECT_EQ(nullptr, proc.rootBinder);
-
- // make sure we can retrieve it again (process doesn't crash)
- EXPECT_EQ(nullptr, proc.connection->getRootObject());
+ EXPECT_EQ(nullptr, proc.connections.at(0).root);
}
TEST_P(BinderRpc, Ping) {
@@ -423,6 +436,14 @@
EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
}
+TEST_P(BinderRpc, MultipleConnections) {
+ auto proc = createRpcTestSocketServerProcess(1 /*threads*/, 5 /*connections*/);
+ for (auto connection : proc.proc.connections) {
+ ASSERT_NE(nullptr, connection.root);
+ EXPECT_EQ(OK, connection.root->pingBinder());
+ }
+}
+
TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
auto proc = createRpcTestSocketServerProcess(1);
Parcel data;
@@ -570,6 +591,15 @@
proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
}
+TEST_P(BinderRpc, CannotMixBindersBetweenTwoConnectionsToTheSameServer) {
+ auto proc = createRpcTestSocketServerProcess(1 /*threads*/, 2 /*connections*/);
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc.rootIface->repeatBinder(proc.proc.connections.at(1).root, &outBinder)
+ .transactionError());
+}
+
TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
auto proc = createRpcTestSocketServerProcess(1);
@@ -854,7 +884,7 @@
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
<< "Do death cleanup: " << doDeathCleanup;
- proc.proc.expectInvalid = true;
+ proc.expectInvalid = true;
}
}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 5600eb3..deb4679 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -340,7 +340,8 @@
int32_t flags, int32_t edgeFlags, int32_t metaState,
int32_t buttonState, MotionClassification classification,
const ui::Transform& transform, float xPrecision, float yPrecision,
- float rawXCursorPosition, float rawYCursorPosition, nsecs_t downTime,
+ float rawXCursorPosition, float rawYCursorPosition,
+ int32_t displayWidth, int32_t displayHeight, nsecs_t downTime,
nsecs_t eventTime, size_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
@@ -357,6 +358,8 @@
mYPrecision = yPrecision;
mRawXCursorPosition = rawXCursorPosition;
mRawYCursorPosition = rawYCursorPosition;
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
mDownTime = downTime;
mPointerProperties.clear();
mPointerProperties.appendArray(pointerProperties, pointerCount);
@@ -380,6 +383,8 @@
mYPrecision = other->mYPrecision;
mRawXCursorPosition = other->mRawXCursorPosition;
mRawYCursorPosition = other->mRawYCursorPosition;
+ mDisplayWidth = other->mDisplayWidth;
+ mDisplayHeight = other->mDisplayHeight;
mDownTime = other->mDownTime;
mPointerProperties = other->mPointerProperties;
@@ -426,7 +431,7 @@
}
float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
- return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
+ return getHistoricalRawAxisValue(axis, pointerIndex, getHistorySize());
}
float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
@@ -440,7 +445,32 @@
float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
size_t historicalIndex) const {
- return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+ if (axis != AMOTION_EVENT_AXIS_X && axis != AMOTION_EVENT_AXIS_Y) {
+ return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+ }
+ // 0x7 encapsulates all 3 rotations (see ui::Transform::RotationFlags)
+ static const int ALL_ROTATIONS_MASK = 0x7;
+ uint32_t orientation = (mTransform.getOrientation() & ALL_ROTATIONS_MASK);
+ if (orientation == ui::Transform::ROT_0) {
+ return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+ }
+
+ // For compatibility, convert raw coordinates into "oriented screen space". Once app developers
+ // are educated about getRaw, we can consider removing this.
+ vec2 xy = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getXYValue();
+ const float unrotatedX = xy.x;
+ if (orientation == ui::Transform::ROT_90) {
+ xy.x = mDisplayHeight - xy.y;
+ xy.y = unrotatedX;
+ } else if (orientation == ui::Transform::ROT_180) {
+ xy.x = mDisplayWidth - xy.x;
+ xy.y = mDisplayHeight - xy.y;
+ } else if (orientation == ui::Transform::ROT_270) {
+ xy.x = xy.y;
+ xy.y = mDisplayWidth - unrotatedX;
+ }
+ static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
+ return xy[axis];
}
float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
@@ -449,19 +479,10 @@
return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
}
- float rawX = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getX();
- float rawY = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getY();
- vec2 vals = mTransform.transform(rawX, rawY);
-
- switch (axis) {
- case AMOTION_EVENT_AXIS_X:
- return vals.x;
- case AMOTION_EVENT_AXIS_Y:
- return vals.y;
- }
-
- // This should never happen
- return 0;
+ vec2 vals = mTransform.transform(
+ getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getXYValue());
+ static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
+ return vals[axis];
}
ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
@@ -606,6 +627,8 @@
mYPrecision = parcel->readFloat();
mRawXCursorPosition = parcel->readFloat();
mRawYCursorPosition = parcel->readFloat();
+ mDisplayWidth = parcel->readInt32();
+ mDisplayHeight = parcel->readInt32();
mDownTime = parcel->readInt64();
mPointerProperties.clear();
@@ -665,6 +688,8 @@
parcel->writeFloat(mYPrecision);
parcel->writeFloat(mRawXCursorPosition);
parcel->writeFloat(mRawYCursorPosition);
+ parcel->writeInt32(mDisplayWidth);
+ parcel->writeInt32(mDisplayHeight);
parcel->writeInt64(mDownTime);
for (size_t i = 0; i < pointerCount; i++) {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 31027b6..61d72ad 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -87,8 +87,10 @@
// Search system repository.
std::string path;
- // Treblized input device config files will be located /odm/usr or /vendor/usr.
- const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
+ // Treblized input device config files will be located /product/usr, /system_ext/usr,
+ // /odm/usr or /vendor/usr.
+ const char* rootsForPartition[]{"/product", "/system_ext", "/odm", "/vendor",
+ getenv("ANDROID_ROOT")};
for (size_t i = 0; i < size(rootsForPartition); i++) {
if (rootsForPartition[i] == nullptr) {
continue;
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 56a064b..de75691 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -228,6 +228,10 @@
msg->body.motion.xCursorPosition = body.motion.xCursorPosition;
// float yCursorPosition
msg->body.motion.yCursorPosition = body.motion.yCursorPosition;
+ // int32_t displayW
+ msg->body.motion.displayWidth = body.motion.displayWidth;
+ // int32_t displayH
+ msg->body.motion.displayHeight = body.motion.displayHeight;
// uint32_t pointerCount
msg->body.motion.pointerCount = body.motion.pointerCount;
//struct Pointer pointers[MAX_POINTERS]
@@ -517,9 +521,9 @@
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform, float xPrecision,
- float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime,
- nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords) {
+ float yPrecision, float xCursorPosition, float yCursorPosition, int32_t displayWidth,
+ int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
+ const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf(
"publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
@@ -577,6 +581,8 @@
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.xCursorPosition = xCursorPosition;
msg.body.motion.yCursorPosition = yCursorPosition;
+ msg.body.motion.displayWidth = displayWidth;
+ msg.body.motion.displayHeight = displayHeight;
msg.body.motion.downTime = downTime;
msg.body.motion.eventTime = eventTime;
msg.body.motion.pointerCount = pointerCount;
@@ -1343,6 +1349,7 @@
msg->body.motion.buttonState, msg->body.motion.classification, transform,
msg->body.motion.xPrecision, msg->body.motion.yPrecision,
msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
+ msg->body.motion.displayWidth, msg->body.motion.displayHeight,
msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount,
pointerProperties, pointerCoords);
}
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 601d8da..15ab428 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -271,6 +271,7 @@
AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
MotionClassification::NONE, mTransform, 2.0f, 2.1f,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties,
pointerCoords);
@@ -592,6 +593,7 @@
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
pointerCoords);
float originalRawX = 0 + 3;
@@ -634,6 +636,71 @@
ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
}
+TEST_F(MotionEventTest, RawCompatTransform) {
+ auto createTouchDownEvent = [](int x, int y, ui::Transform transform) {
+ std::vector<PointerProperties> pointerProperties;
+ pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER});
+ std::vector<PointerCoords> pointerCoords;
+ pointerCoords.emplace_back().clear();
+ pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, x);
+ pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+ nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ MotionEvent event;
+ event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN,
+ /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN,
+ /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE,
+ /* buttonState */ 0, MotionClassification::NONE, transform,
+ /* xPrecision */ 0, /* yPrecision */ 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400,
+ /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(),
+ pointerProperties.data(), pointerCoords.data());
+ return event;
+ };
+
+ {
+ // Make sure raw is raw regardless of transform translation.
+ ui::Transform xform;
+ xform.set(20, 40);
+ MotionEvent event = createTouchDownEvent(60, 100, xform);
+ ASSERT_EQ(60, event.getRawX(0));
+ ASSERT_EQ(100, event.getRawY(0));
+ ASSERT_NE(event.getRawX(0), event.getX(0));
+ ASSERT_NE(event.getRawY(0), event.getY(0));
+ }
+
+ // Next check that getRaw contains rotation (for compatibility) but otherwise is still
+ // "Screen-space". The following tests check all 3 rotations.
+ {
+ // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
+ ui::Transform xform(ui::Transform::ROT_90, 800, 400);
+ xform.set(xform.tx() + 20, xform.ty() + 40);
+ MotionEvent event = createTouchDownEvent(60, 100, xform);
+ ASSERT_EQ(700, event.getRawX(0));
+ ASSERT_EQ(60, event.getRawY(0));
+ ASSERT_NE(event.getRawX(0), event.getX(0));
+ ASSERT_NE(event.getRawY(0), event.getY(0));
+ }
+
+ {
+ // Same as above, but check rotate-180.
+ ui::Transform xform(ui::Transform::ROT_180, 400, 800);
+ xform.set(xform.tx() + 20, xform.ty() + 40);
+ MotionEvent event = createTouchDownEvent(60, 100, xform);
+ ASSERT_EQ(340, event.getRawX(0));
+ ASSERT_EQ(700, event.getRawY(0));
+ }
+
+ {
+ // Same as above, but check rotate-270.
+ ui::Transform xform(ui::Transform::ROT_270, 800, 400);
+ xform.set(xform.tx() + 20, xform.ty() + 40);
+ MotionEvent event = createTouchDownEvent(60, 100, xform);
+ ASSERT_EQ(100, event.getRawX(0));
+ ASSERT_EQ(340, event.getRawY(0));
+ }
+}
+
TEST_F(MotionEventTest, Initialize_SetsClassification) {
std::array<MotionClassification, 3> classifications = {
MotionClassification::NONE,
@@ -657,7 +724,8 @@
DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(classification, event.getClassification());
}
@@ -678,8 +746,10 @@
event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID,
INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE,
AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0,
- 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/,
- 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+ 280 /*xCursorPosition*/, 540 /*yCursorPosition*/,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
+ pointerCoords);
event.offsetLocation(20, 60);
ASSERT_EQ(280, event.getRawXCursorPosition());
ASSERT_EQ(540, event.getRawYCursorPosition());
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 088e00b..a2cfaa1 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -162,6 +162,8 @@
constexpr float yPrecision = 0.5;
constexpr float xCursorPosition = 1.3;
constexpr float yCursorPosition = 50.6;
+ constexpr int32_t displayWidth = 1000;
+ constexpr int32_t displayHeight = 2000;
constexpr nsecs_t downTime = 3;
constexpr size_t pointerCount = 3;
constexpr nsecs_t eventTime = 4;
@@ -190,8 +192,9 @@
status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action,
actionButton, flags, edgeFlags, metaState, buttonState,
classification, transform, xPrecision, yPrecision,
- xCursorPosition, yCursorPosition, downTime, eventTime,
- pointerCount, pointerProperties, pointerCoords);
+ xCursorPosition, yCursorPosition, displayWidth,
+ displayHeight, downTime, eventTime, pointerCount,
+ pointerProperties, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
@@ -228,6 +231,8 @@
EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
+ EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x);
+ EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y);
EXPECT_EQ(downTime, motionEvent->getDownTime());
EXPECT_EQ(eventTime, motionEvent->getEventTime());
EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
@@ -455,7 +460,7 @@
status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
0, 0, 0, MotionClassification::NONE, identityTransform,
0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -471,7 +476,7 @@
status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
0, 0, 0, MotionClassification::NONE, identityTransform,
0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -492,7 +497,7 @@
status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
0, 0, 0, MotionClassification::NONE, identityTransform,
0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 585779e..5861d55 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -74,9 +74,11 @@
CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124);
CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128);
CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132);
- CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 136);
- CHECK_OFFSET(InputMessage::Body::Motion, empty3, 140);
- CHECK_OFFSET(InputMessage::Body::Motion, pointers, 144);
+ CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 136);
+ CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 140);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 144);
+ CHECK_OFFSET(InputMessage::Body::Motion, empty3, 148);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152);
CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0);
CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index d049d05..aefc2ec 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -183,7 +183,8 @@
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/,
entry.eventTime.count(), pointerCount, properties, coords);
events.emplace_back(event);
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
index 36f87b8..f79098c 100644
--- a/libs/input/tests/VerifiedInputEvent_test.cpp
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -46,8 +46,10 @@
INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/,
- 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 100 /*downTime*/,
- 200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+ 280 /*xCursorPosition*/, 540 /*yCursorPosition*/,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ 100 /*downTime*/, 200 /*eventTime*/, pointerCount, pointerProperties,
+ pointerCoords);
return event;
}
diff --git a/libs/permission/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
index c048cbe..e3d705f 100644
--- a/libs/permission/include/binder/AppOpsManager.h
+++ b/libs/permission/include/binder/AppOpsManager.h
@@ -146,7 +146,8 @@
OP_UWB_RANGING = 112,
OP_ACTIVITY_RECOGNITION_SOURCE = 113,
OP_BLUETOOTH_ADVERTISE = 114,
- _NUM_OP = 115
+ OP_RECORD_INCOMING_PHONE_AUDIO = 115,
+ _NUM_OP = 116
};
AppOpsManager();
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index f395ab4..3ad55bf 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -117,7 +117,7 @@
include_dirs: [
"external/skia/src/gpu",
],
- whole_static_libs: ["libskia"],
+ whole_static_libs: ["libskia_renderengine"],
lto: {
thin: true,
},
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index d87315f..9400037 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -249,7 +249,7 @@
// initialize EGL for the default display
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!eglInitialize(display, nullptr, nullptr)) {
- LOG_ALWAYS_FATAL("failed to initialize EGL");
+ LOG_ALWAYS_FATAL("failed to initialize EGL. EGL error=0x%x", eglGetError());
}
const auto eglVersion = eglQueryString(display, EGL_VERSION);
diff --git a/libs/renderengine/skia/debug/record.sh b/libs/renderengine/skia/debug/record.sh
index bc406d9..25c8cef 100755
--- a/libs/renderengine/skia/debug/record.sh
+++ b/libs/renderengine/skia/debug/record.sh
@@ -31,7 +31,7 @@
# give the device time to both record, and starting writing the file.
# Total time needed to write the file depends on how much data was recorded.
# the loop at the end waits for this.
-sleep $(($1 / 1000 + 2));
+sleep $(($1 / 1000 + 4));
# There is no guarantee that at least one frame passed through renderengine during that time
# but as far as I know it always at least writes a 0-byte file with a new name, unless it crashes
@@ -54,7 +54,7 @@
mskp_size=$(adb_filesize "/data/user/$name")
if [[ $mskp_size = "0" ]]; then
- echo "Empty file, probably no RenderEngine activity during recording period."
+ echo "File opened, but remains empty after recording period + wait. Either there was no RenderEngine activity during recording period, or recording process is still working. Check /data/user/$name manually later."
exit 1
fi
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 2028def..5cba8fb 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -86,8 +86,8 @@
float radiusByPasses = tmpRadius / (float)numberOfPasses;
// create blur surface with the bit depth and colorspace of the original surface
- SkImageInfo scaledInfo = input->imageInfo().makeWH(blurRect.width() * kInputScale,
- blurRect.height() * kInputScale);
+ SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale),
+ std::ceil(blurRect.height() * kInputScale));
const float stepX = radiusByPasses;
const float stepY = radiusByPasses;
@@ -105,7 +105,7 @@
input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale};
blurBuilder.uniform("in_maxSizeXY") =
- SkV2{blurRect.width() * kInputScale - 1, blurRect.height() * kInputScale - 1};
+ SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale};
sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
@@ -116,7 +116,7 @@
tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
blurBuilder.uniform("in_maxSizeXY") =
- SkV2{blurRect.width() * kInputScale - 1, blurRect.height() * kInputScale - 1};
+ SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale};
tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
}
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 34ef0a4..85322a9 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -487,6 +487,9 @@
void fillBufferAndBlurBackground();
template <typename SourceVariant>
+ void fillSmallLayerAndBlurBackground();
+
+ template <typename SourceVariant>
void overlayCorners();
void fillRedBufferTextureTransform();
@@ -966,11 +969,44 @@
if (mRE->supportsBackgroundBlur()) {
// blurred color (downsampling should result in the center color being close to 128)
expectBufferColor(Rect(center - 1, center - 5, center + 1, center + 5), 128, 128, 0, 255,
- 10 /* tolerance */);
+ 50 /* tolerance */);
}
}
template <typename SourceVariant>
+void RenderEngineTest::fillSmallLayerAndBlurBackground() {
+ auto blurRadius = 50;
+ renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<const renderengine::LayerSettings*> layers;
+
+ renderengine::LayerSettings backgroundLayer;
+ backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+ SourceVariant::fillColor(backgroundLayer, 1.0f, 0.0f, 0.0f, this);
+ backgroundLayer.alpha = 1.0f;
+ layers.push_back(&backgroundLayer);
+
+ renderengine::LayerSettings blurLayer;
+ blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ blurLayer.geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f);
+ blurLayer.backgroundBlurRadius = blurRadius;
+ SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
+ blurLayer.alpha = 0;
+ layers.push_back(&blurLayer);
+
+ invokeDraw(settings, layers);
+
+ // Give a generous tolerance - the blur rectangle is very small and this test is
+ // mainly concerned with ensuring that there's no device failure.
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), 255, 0, 0, 255,
+ 40 /* tolerance */);
+}
+
+template <typename SourceVariant>
void RenderEngineTest::overlayCorners() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
@@ -1402,12 +1438,16 @@
fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
}
-// TODO(b/186010146): reenable once swiftshader is happy with this test
-TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
initializeRenderEngine();
fillBufferAndBlurBackground<ColorSourceVariant>();
}
+TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_colorSource) {
+ initializeRenderEngine();
+ fillSmallLayerAndBlurBackground<ColorSourceVariant>();
+}
+
TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
initializeRenderEngine();
overlayCorners<ColorSourceVariant>();
@@ -1478,12 +1518,16 @@
fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-// TODO(b/186010146): reenable once swiftshader is happy with this test
-TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
initializeRenderEngine();
fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
+TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_opaqueBufferSource) {
+ initializeRenderEngine();
+ fillSmallLayerAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
initializeRenderEngine();
overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
@@ -1554,12 +1598,16 @@
fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-// TODO(b/186010146): reenable once swiftshader is happy with this test
-TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
initializeRenderEngine();
fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
+TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_bufferSource) {
+ initializeRenderEngine();
+ fillSmallLayerAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
initializeRenderEngine();
overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 7bd0c6b..1b5f1ab 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -232,7 +232,8 @@
/* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
identityTransform, /* xPrecision */ 0,
/* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, currentTime,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, currentTime, currentTime,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
return event;
}
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 5270b8a..6ed9593 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -296,12 +296,13 @@
volatile int32_t DispatchEntry::sNextSeqAtomic;
DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
- ui::Transform transform, float globalScaleFactor)
+ ui::Transform transform, float globalScaleFactor, vec2 displaySize)
: seq(nextSeq()),
eventEntry(std::move(eventEntry)),
targetFlags(targetFlags),
transform(transform),
globalScaleFactor(globalScaleFactor),
+ displaySize(displaySize),
deliveryTime(0),
resolvedAction(0),
resolvedFlags(0) {}
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index f3ef64b..45c5e24 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -215,6 +215,7 @@
int32_t targetFlags;
ui::Transform transform;
float globalScaleFactor;
+ vec2 displaySize;
// Both deliveryTime and timeoutTime are only populated when the entry is sent to the app,
// and will be undefined before that.
nsecs_t deliveryTime; // time when the event was actually delivered
@@ -227,7 +228,7 @@
int32_t resolvedFlags;
DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
- ui::Transform transform, float globalScaleFactor);
+ ui::Transform transform, float globalScaleFactor, vec2 displaySize);
inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 27443b0..16cb7d7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -339,14 +339,16 @@
// values do not represent on-screen coordinates, so they should not have any window
// transformations applied to them.
return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform,
- 1.0f /*globalScaleFactor*/);
+ 1.0f /*globalScaleFactor*/,
+ inputTarget.displaySize);
}
}
if (inputTarget.useDefaultPointerTransform()) {
const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
- inputTarget.globalScaleFactor);
+ inputTarget.globalScaleFactor,
+ inputTarget.displaySize);
}
ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
@@ -397,7 +399,8 @@
std::unique_ptr<DispatchEntry> dispatchEntry =
std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
- firstPointerTransform, inputTarget.globalScaleFactor);
+ firstPointerTransform, inputTarget.globalScaleFactor,
+ inputTarget.displaySize);
return dispatchEntry;
}
@@ -2402,6 +2405,8 @@
inputTarget.inputChannel = inputChannel;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
+ inputTarget.displaySize =
+ vec2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
inputTargets.push_back(inputTarget);
it = inputTargets.end() - 1;
}
@@ -3107,6 +3112,8 @@
motionEntry.xPrecision, motionEntry.yPrecision,
motionEntry.xCursorPosition,
motionEntry.yCursorPosition,
+ dispatchEntry->displaySize.x,
+ dispatchEntry->displaySize.y,
motionEntry.downTime, motionEntry.eventTime,
motionEntry.pointerCount,
motionEntry.pointerProperties, usingCoords);
@@ -3819,7 +3826,8 @@
args->action, args->actionButton, args->flags, args->edgeFlags,
args->metaState, args->buttonState, args->classification, transform,
args->xPrecision, args->yPrecision, args->xCursorPosition,
- args->yCursorPosition, args->downTime, args->eventTime,
+ args->yCursorPosition, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
policyFlags |= POLICY_FLAG_FILTERED;
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index debf805..2543852 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -100,6 +100,9 @@
// (ignored for KeyEvents)
float globalScaleFactor = 1.0f;
+ // Display-size in its natural rotation. Used for compatibility transform of raw coordinates.
+ vec2 displaySize = {AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE};
+
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
BitSet32 pointerIds;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 31d6900..9687c83 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -526,7 +526,8 @@
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
/*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -539,6 +540,7 @@
(1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
@@ -551,6 +553,7 @@
(~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
@@ -564,6 +567,7 @@
(1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
@@ -576,6 +580,7 @@
(~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
@@ -587,7 +592,8 @@
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -597,7 +603,8 @@
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -609,7 +616,8 @@
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -620,7 +628,8 @@
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -633,7 +642,8 @@
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+ AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -1237,8 +1247,8 @@
mAction, mActionButton, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE,
mButtonState, MotionClassification::NONE, identityTransform,
/* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition,
- mRawYCursorPosition, mEventTime, mEventTime, mPointers.size(),
- pointerProperties.data(), pointerCoords.data());
+ mRawYCursorPosition, mDisplayWidth, mDisplayHeight, mEventTime, mEventTime,
+ mPointers.size(), pointerProperties.data(), pointerCoords.data());
return event;
}
@@ -1252,6 +1262,8 @@
int32_t mButtonState{0};
float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+ int32_t mDisplayWidth{AMOTION_EVENT_INVALID_DISPLAY_SIZE};
+ int32_t mDisplayHeight{AMOTION_EVENT_INVALID_DISPLAY_SIZE};
std::vector<PointerBuilder> mPointers;
};
@@ -2029,6 +2041,19 @@
expectedDisplayId, expectedFlags);
}
+ MotionEvent* consumeMotion() {
+ InputEvent* event = mInputReceiver->consume();
+ if (!event) {
+ ADD_FAILURE() << "No event was produced";
+ return nullptr;
+ }
+ if (event->getType() != AINPUT_EVENT_TYPE_MOTION) {
+ ADD_FAILURE() << "Received event of type " << event->getType() << " instead of motion";
+ return nullptr;
+ }
+ return static_cast<MotionEvent*>(event);
+ }
+
void assertNoEvents() { mInputReceiver->assertNoEvents(); }
private:
@@ -2115,6 +2140,27 @@
mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
}
+// Tests for gesture monitors
+TEST_F(InputDispatcherTest, GestureMonitor_NoWindowTransform) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ window->setWindowOffset(20, 40);
+ window->setWindowTransform(0, 1, -1, 0);
+
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ MotionEvent* event = monitor.consumeMotion();
+ // Even though window has transform, gesture monitor must not.
+ ASSERT_EQ(ui::Transform(), event->getTransform());
+}
+
TEST_F(InputDispatcherTest, TestMoveEvent) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 9885352..f20bfe1 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -25,7 +25,7 @@
name: "libsurfaceflinger_defaults",
defaults: [
"surfaceflinger_defaults",
- "skia_deps",
+ "skia_renderengine_deps",
],
cflags: [
"-DLOG_TAG=\"SurfaceFlinger\"",
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 570a41a..a273230 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -51,9 +51,6 @@
return flags;
}
- uint32_t getActiveWidth(const Layer::State& s) const override { return s.width; }
- uint32_t getActiveHeight(const Layer::State& s) const override { return s.height; }
- ui::Transform getActiveTransform(const Layer::State& s) const override { return s.transform; }
Region getActiveTransparentRegion(const Layer::State& s) const override {
return s.transparentRegionHint;
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index aa049a8..fd22aa3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -57,11 +57,15 @@
void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
sp<GraphicBuffer>* outBuffer);
+ // Special caching slot for the layer caching feature.
+ static const constexpr size_t FLATTENER_CACHING_SLOT = BufferQueue::NUM_BUFFER_SLOTS;
+
private:
// an array where the index corresponds to a slot and the value corresponds to a (counter,
// buffer) pair. "counter" is a unique value that indicates the last time this slot was updated
// or used and allows us to keep track of the least-recently used buffer.
- wp<GraphicBuffer> mBuffers[BufferQueue::NUM_BUFFER_SLOTS];
+ static const constexpr size_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
+ wp<GraphicBuffer> mBuffers[kMaxLayerBufferCount];
};
} // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 356965c..b98043b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -102,7 +102,7 @@
// behind the OutputLayer represented by this CompositionState and will
// be visible through it. Unowned - the OutputLayer's lifetime will
// outlast this.)
- OutputLayer* peekThroughLayer = nullptr;
+ compositionengine::OutputLayer* peekThroughLayer = nullptr;
} overrideInfo;
/*
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index a6c4eaf..06f26eb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -60,7 +60,6 @@
void addLayer(const LayerState*, std::chrono::steady_clock::time_point lastUpdate);
std::chrono::steady_clock::time_point getLastUpdate() const { return mLastUpdate; }
- NonBufferHash getFingerprint() const { return mFingerprint; }
size_t getLayerCount() const { return mLayers.size(); }
const Layer& getFirstLayer() const { return mLayers[0]; }
const Rect& getBounds() const { return mBounds; }
@@ -121,7 +120,7 @@
void addHolePunchLayerIfFeasible(const CachedSet&, bool isFirstLayer);
// Retrieve the layer that will be drawn behind this one.
- OutputLayer* getHolePunchLayer() const;
+ compositionengine::OutputLayer* getHolePunchLayer() const;
private:
CachedSet() = default;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 942592a..b09f1d1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -49,6 +49,7 @@
const OutputCompositionState& outputState);
void dump(std::string& result) const;
+ void dumpLayers(std::string& result) const;
private:
size_t calculateDisplayCost(const std::vector<const LayerState*>& layers) const;
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index cedc333..f95382d 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -36,7 +36,7 @@
sp<GraphicBuffer>* outBuffer) {
// default is 0
if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0 ||
- slot >= BufferQueue::NUM_BUFFER_SLOTS) {
+ slot >= static_cast<int32_t>(kMaxLayerBufferCount)) {
*outSlot = 0;
} else {
*outSlot = static_cast<uint32_t>(slot);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index c809e1a..297e687 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -707,7 +707,7 @@
editState().earliestPresentTime = refreshArgs.earliestPresentTime;
- OutputLayer* peekThroughLayer = nullptr;
+ compositionengine::OutputLayer* peekThroughLayer = nullptr;
sp<GraphicBuffer> previousOverride = nullptr;
bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
uint32_t z = 0;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 7f5c01c..01da070 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -18,6 +18,7 @@
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/Output.h>
+#include <compositionengine/impl/HwcBufferCache.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -548,9 +549,11 @@
sp<GraphicBuffer> buffer = outputIndependentState.buffer;
sp<Fence> acquireFence = outputIndependentState.acquireFence;
+ int slot = outputIndependentState.bufferSlot;
if (getState().overrideInfo.buffer != nullptr) {
buffer = getState().overrideInfo.buffer->getBuffer();
acquireFence = getState().overrideInfo.acquireFence;
+ slot = HwcBufferCache::FLATTENER_CACHING_SLOT;
}
ALOGV("Writing buffer %p", buffer.get());
@@ -559,8 +562,7 @@
sp<GraphicBuffer> hwcBuffer;
// We need access to the output-dependent state for the buffer cache there,
// though otherwise the buffer is not output-dependent.
- editState().hwc->hwcBufferCache.getHwcBuffer(outputIndependentState.bufferSlot, buffer,
- &hwcSlot, &hwcBuffer);
+ editState().hwc->hwcBufferCache.getHwcBuffer(slot, buffer, &hwcSlot, &hwcBuffer);
if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
error != hal::Error::NONE) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 4cf83d9..67854cf 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -306,7 +306,7 @@
}
}
-OutputLayer* CachedSet::getHolePunchLayer() const {
+compositionengine::OutputLayer* CachedSet::getHolePunchLayer() const {
return mHolePunchLayer ? mHolePunchLayer->getOutputLayer() : nullptr;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index b4e7610..a63f21f 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -45,7 +45,10 @@
}
for (size_t i = 0; i < incomingLayers.size(); i++) {
- if (incomingLayers[i]->getDifferingFields(*(existingLayers[i])) != LayerStateField::None) {
+ // Checking the IDs here is very strict, but we do this as otherwise we may mistakenly try
+ // to access destroyed OutputLayers later on.
+ if (incomingLayers[i]->getId() != existingLayers[i]->getId() ||
+ incomingLayers[i]->getDifferingFields(*(existingLayers[i])) != LayerStateField::None) {
return false;
}
}
@@ -96,6 +99,14 @@
mNewCachedSet->render(renderEngine, outputState);
}
+void Flattener::dumpLayers(std::string& result) const {
+ result.append(" Current layers:");
+ for (const CachedSet& layer : mLayers) {
+ result.append("\n");
+ layer.dump(result);
+ }
+}
+
void Flattener::dump(std::string& result) const {
const auto now = std::chrono::steady_clock::now();
@@ -140,11 +151,7 @@
base::StringAppendF(&result, "\n Current hash %016zx, last update %sago\n\n", mCurrentGeometry,
durationString(lastUpdate).c_str());
- result.append(" Current layers:");
- for (const CachedSet& layer : mLayers) {
- result.append("\n");
- layer.dump(result);
- }
+ dumpLayers(result);
}
size_t Flattener::calculateDisplayCost(const std::vector<const LayerState*>& layers) const {
@@ -232,7 +239,8 @@
auto currentLayerIter = mLayers.begin();
auto incomingLayerIter = layers.begin();
while (incomingLayerIter != layers.end()) {
- if (mNewCachedSet && mNewCachedSet->getFingerprint() == (*incomingLayerIter)->getHash()) {
+ if (mNewCachedSet &&
+ mNewCachedSet->getFirstLayer().getState()->getId() == (*incomingLayerIter)->getId()) {
if (mNewCachedSet->hasBufferUpdate()) {
ALOGV("[%s] Dropping new cached set", __func__);
++mInvalidatedCachedSetAges[0];
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 7d2bf06..7e85dca 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -233,6 +233,8 @@
}
mPredictor.listSimilarStacks(*plan, result);
+ } else if (command == "--layers" || command == "-l") {
+ mFlattener.dumpLayers(result);
} else {
base::StringAppendF(&result, "Unknown command '%s'\n\n", command.string());
dumpUsage(result);
@@ -268,6 +270,9 @@
result.append("[--similar|-s] <plan>\n");
result.append(" Prints the example layer names for similar stacks matching <plan>\n");
+
+ result.append("[--layers|-l]\n");
+ result.append(" Prints the current layers\n");
}
} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index fb8ffce..3adfe40 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <compositionengine/impl/HwcBufferCache.h>
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/CompositionEngine.h>
@@ -702,6 +703,7 @@
static constexpr ui::Dataspace kOverrideDataspace = static_cast<ui::Dataspace>(72);
static constexpr int kSupportedPerFrameMetadata = 101;
static constexpr int kExpectedHwcSlot = 0;
+ static constexpr int kOverrideHwcSlot = impl::HwcBufferCache::FLATTENER_CACHING_SLOT;
static constexpr bool kLayerGenericMetadata1Mandatory = true;
static constexpr bool kLayerGenericMetadata2Mandatory = true;
@@ -824,10 +826,11 @@
EXPECT_CALL(*mHwcLayer, setSidebandStream(kSidebandStreamHandle));
}
- void expectSetHdrMetadataAndBufferCalls(sp<GraphicBuffer> buffer = kBuffer,
+ void expectSetHdrMetadataAndBufferCalls(uint32_t hwcSlot = kExpectedHwcSlot,
+ sp<GraphicBuffer> buffer = kBuffer,
sp<Fence> fence = kFence) {
EXPECT_CALL(*mHwcLayer, setPerFrameMetadata(kSupportedPerFrameMetadata, kHdrMetadata));
- EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, buffer, fence));
+ EXPECT_CALL(*mHwcLayer, setBuffer(hwcSlot, buffer, fence));
}
void expectGenericLayerMetadataCalls() {
@@ -1060,15 +1063,75 @@
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
kOverrideSurfaceDamage);
- expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence);
+ expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
-
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
+TEST_F(OutputLayerWriteStateToHWCTest, peekThroughChangesBlendMode) {
+ auto peekThroughLayerFE = sp<compositionengine::mock::LayerFE>::make();
+ OutputLayer peekThroughLayer{mOutput, peekThroughLayerFE};
+
+ mOutputLayer.mState.overrideInfo.peekThroughLayer = &peekThroughLayer;
+
+ expectGeometryCommonCalls(kDisplayFrame, kSourceCrop, kBufferTransform,
+ Hwc2::IComposerClient::BlendMode::PREMULTIPLIED);
+ expectPerFrameCommonCalls();
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, isPeekingThroughSetsOverride) {
+ expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ true);
+ EXPECT_TRUE(mOutputLayer.getState().hwc->stateOverridden);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, zIsOverriddenSetsOverride) {
+ expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ true, /*isPeekingThrough*/
+ false);
+ EXPECT_TRUE(mOutputLayer.getState().hwc->stateOverridden);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersForceClientComposition) {
+ expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(true));
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/
+ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersPeekingThroughAllowsDeviceComposition) {
+ expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/
+ true);
+ EXPECT_EQ(Hwc2::IComposerClient::Composition::DEVICE,
+ mOutputLayer.getState().hwc->hwcCompositionType);
+}
+
/*
* OutputLayer::writeCursorPositionToHWC()
*/
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 7b71957..27980a0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -879,6 +879,64 @@
mOutput->writeCompositionState(args);
}
+TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) {
+ renderengine::mock::RenderEngine renderEngine;
+ InjectedLayer layer0;
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
+
+ InSequence seq;
+ EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+
+ uint32_t z = 0;
+ EXPECT_CALL(*layer0.outputLayer,
+ writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+
+ // After calling planComposition (which clears overrideInfo), this test sets
+ // layer3 to be the peekThroughLayer for layer1 and layer2. As a result, it
+ // comes first, setting isPeekingThrough to true and zIsOverridden to true
+ // for it and the following layers.
+ EXPECT_CALL(*layer3.outputLayer,
+ writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ true, /*isPeekingThrough*/
+ true));
+ EXPECT_CALL(*layer1.outputLayer,
+ writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
+ /*zIsOverridden*/ true, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer,
+ writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, z++,
+ /*zIsOverridden*/ true, /*isPeekingThrough*/ false));
+
+ injectOutputLayer(layer0);
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
+
+ mOutput->editState().isEnabled = true;
+
+ CompositionRefreshArgs args;
+ args.updatingGeometryThisFrame = true;
+ args.devOptForceClientComposition = false;
+ mOutput->updateCompositionState(args);
+ mOutput->planComposition();
+
+ std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(), renderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
+ layer1.outputLayerState.overrideInfo.buffer = buffer;
+ layer2.outputLayerState.overrideInfo.buffer = buffer;
+ layer1.outputLayerState.overrideInfo.peekThroughLayer = layer3.outputLayer;
+ layer2.outputLayerState.overrideInfo.peekThroughLayer = layer3.outputLayer;
+
+ mOutput->writeCompositionState(args);
+}
+
/*
* Output::prepareFrame()
*/
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 8884711..a39331c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -19,8 +19,12 @@
#include <compositionengine/impl/planner/LayerState.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/OutputLayer.h>
+#include <gmock/gmock-actions.h>
#include <gtest/gtest.h>
+#include <renderengine/ExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
+#include <ui/GraphicTypes.h>
+#include <memory>
namespace android::compositionengine {
using namespace std::chrono_literals;
@@ -105,7 +109,6 @@
}
void expectEqual(const CachedSet& cachedSet, const CachedSet::Layer& layer) {
- EXPECT_EQ(layer.getHash(), cachedSet.getFingerprint());
EXPECT_EQ(layer.getLastUpdate(), cachedSet.getLastUpdate());
EXPECT_EQ(layer.getDisplayFrame(), cachedSet.getBounds());
EXPECT_TRUE(layer.getVisibleRegion().hasSameRects(cachedSet.getVisibleRegion()));
@@ -154,7 +157,6 @@
CachedSet cachedSet(layer1);
cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
- EXPECT_EQ(layer1.getHash(), cachedSet.getFingerprint());
EXPECT_EQ(kStartTime, cachedSet.getLastUpdate());
EXPECT_EQ(Rect(0, 0, 2, 2), cachedSet.getBounds());
Region expectedRegion;
@@ -243,7 +245,6 @@
cachedSet1.addLayer(layer3.getState(), kStartTime + 10ms);
cachedSet1.append(cachedSet2);
- EXPECT_EQ(layer1.getHash(), cachedSet1.getFingerprint());
EXPECT_EQ(kStartTime, cachedSet1.getLastUpdate());
EXPECT_EQ(Rect(0, 0, 3, 3), cachedSet1.getBounds());
Region expectedRegion;
@@ -380,5 +381,191 @@
cachedSet.append(CachedSet(layer3));
}
+TEST_F(CachedSetTest, holePunch_requiresBuffer) {
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE1 = mTestLayers[0]->layerFE;
+
+ CachedSet cachedSet(layer1);
+ EXPECT_CALL(*layerFE1, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ EXPECT_FALSE(cachedSet.requiresHolePunch());
+}
+
+TEST_F(CachedSetTest, holePunch_requiresRoundedCorners) {
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+
+ CachedSet cachedSet(layer1);
+
+ EXPECT_FALSE(cachedSet.requiresHolePunch());
+}
+
+TEST_F(CachedSetTest, holePunch_requiresSingleLayer) {
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
+ EXPECT_CALL(*layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
+
+ CachedSet cachedSet(layer1);
+ cachedSet.append(layer2);
+
+ EXPECT_FALSE(cachedSet.requiresHolePunch());
+}
+
+TEST_F(CachedSetTest, requiresHolePunch) {
+ CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
+ mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
+
+ CachedSet cachedSet(layer);
+ EXPECT_CALL(*layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ EXPECT_TRUE(cachedSet.requiresHolePunch());
+}
+
+TEST_F(CachedSetTest, holePunch_requiresDeviceComposition) {
+ CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
+ auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ layerFECompositionState.forceClientComposition = true;
+
+ CachedSet cachedSet(layer);
+ EXPECT_CALL(*layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ EXPECT_FALSE(cachedSet.requiresHolePunch());
+}
+
+TEST_F(CachedSetTest, addHolePunch_requiresOverlap) {
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+
+ CachedSet cachedSet(layer1);
+ cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
+
+ cachedSet.addHolePunchLayerIfFeasible(layer3, true);
+
+ ASSERT_EQ(nullptr, cachedSet.getHolePunchLayer());
+}
+
+TEST_F(CachedSetTest, addHolePunch_requiresOpaque) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+ mTestLayers[0]->layerFECompositionState.isOpaque = false;
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+
+ CachedSet cachedSet(layer1);
+ cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
+
+ cachedSet.addHolePunchLayerIfFeasible(layer3, false);
+
+ ASSERT_EQ(nullptr, cachedSet.getHolePunchLayer());
+}
+
+TEST_F(CachedSetTest, addHolePunch_opaque) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+ mTestLayers[0]->layerFECompositionState.isOpaque = true;
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+
+ CachedSet cachedSet(layer1);
+ cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
+
+ cachedSet.addHolePunchLayerIfFeasible(layer3, false);
+
+ ASSERT_EQ(&mTestLayers[2]->outputLayer, cachedSet.getHolePunchLayer());
+}
+
+TEST_F(CachedSetTest, addHolePunch_firstLayer) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+ mTestLayers[0]->layerFECompositionState.isOpaque = false;
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+
+ CachedSet cachedSet(layer1);
+ cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
+
+ cachedSet.addHolePunchLayerIfFeasible(layer3, true);
+
+ ASSERT_EQ(&mTestLayers[2]->outputLayer, cachedSet.getHolePunchLayer());
+}
+
+TEST_F(CachedSetTest, addHolePunch) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE1 = mTestLayers[0]->layerFE;
+
+ CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE2 = mTestLayers[1]->layerFE;
+
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE3 = mTestLayers[2]->layerFE;
+
+ CachedSet cachedSet(layer1);
+ cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
+
+ cachedSet.addHolePunchLayerIfFeasible(layer3, true);
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
+ clientCompList1.push_back({});
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
+ clientCompList2.push_back({});
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3;
+ clientCompList3.push_back({});
+
+ clientCompList3[0].source.buffer.buffer = std::make_shared<
+ renderengine::ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
+ renderengine::ExternalTexture::READABLE);
+
+ EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
+ EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
+ EXPECT_CALL(*layerFE3, prepareClientCompositionList(_)).WillOnce(Return(clientCompList3));
+
+ const auto drawLayers = [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&, base::unique_fd*) -> size_t {
+ // If the highlight layer is enabled, it will increase the size by 1.
+ // We're interested in the third layer either way.
+ EXPECT_GE(layers.size(), 3u);
+ const auto* holePunchSettings = layers[2];
+ EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
+ EXPECT_TRUE(holePunchSettings->disableBlending);
+ EXPECT_EQ(0.0f, holePunchSettings->alpha);
+
+ return NO_ERROR;
+ };
+
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ cachedSet.render(mRenderEngine, mOutputState);
+}
+
+TEST_F(CachedSetTest, decompose_removesHolePunch) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+
+ CachedSet cachedSet(layer1);
+ cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
+
+ cachedSet.addHolePunchLayerIfFeasible(layer3, true);
+
+ ASSERT_EQ(&mTestLayers[2]->outputLayer, cachedSet.getHolePunchLayer());
+
+ std::vector<CachedSet> decomposed = cachedSet.decompose();
+ EXPECT_EQ(2u, decomposed.size());
+ for (const auto& set : decomposed) {
+ EXPECT_EQ(nullptr, set.getHolePunchLayer());
+ }
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 373b895..71757f6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -22,6 +22,8 @@
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/OutputLayer.h>
#include <gtest/gtest.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/LayerSettings.h>
#include <renderengine/mock/RenderEngine.h>
namespace android::compositionengine {
@@ -45,7 +47,7 @@
class FlattenerTest : public testing::Test {
public:
- FlattenerTest() : mFlattener(std::make_unique<Flattener>(mPredictor)) {}
+ FlattenerTest() : mFlattener(std::make_unique<Flattener>(mPredictor, true)) {}
void SetUp() override;
protected:
@@ -528,5 +530,123 @@
EXPECT_EQ(overrideBuffer4, overrideBuffer5);
}
+// Tests for a PIP
+TEST_F(FlattenerTest, flattenLayers_pipRequiresRoundedCorners) {
+ auto& layerState1 = mTestLayers[0]->layerState;
+ const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+
+ auto& layerState2 = mTestLayers[1]->layerState;
+ const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
+
+ auto& layerState3 = mTestLayers[2]->layerState;
+ const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
+
+ const std::vector<const LayerState*> layers = {
+ layerState1.get(),
+ layerState2.get(),
+ layerState3.get(),
+ };
+
+ initializeFlattener(layers);
+
+ // 3 has a buffer update, so it will not be merged, but it has no round
+ // corners, so it is not a PIP.
+ mTime += 200ms;
+ layerState3->resetFramesSinceBufferUpdate();
+
+ initializeOverrideBuffer(layers);
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+ // This will render a CachedSet.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+
+ // We've rendered a CachedSet, but we haven't merged it in.
+ EXPECT_EQ(nullptr, overrideBuffer1);
+ EXPECT_EQ(nullptr, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+
+ // This time we merge the CachedSet in, so we have a new hash, and we should
+ // only have two sets.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ initializeOverrideBuffer(layers);
+ EXPECT_NE(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+
+ EXPECT_NE(nullptr, overrideBuffer1);
+ EXPECT_EQ(overrideBuffer1, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+}
+
+TEST_F(FlattenerTest, flattenLayers_pip) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+ auto& layerState1 = mTestLayers[0]->layerState;
+ const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+
+ auto& layerState2 = mTestLayers[1]->layerState;
+ const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
+
+ auto& layerState3 = mTestLayers[2]->layerState;
+ const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
+
+ EXPECT_CALL(*mTestLayers[2]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ std::vector<LayerFE::LayerSettings> clientCompositionList = {
+ LayerFE::LayerSettings{},
+ };
+ clientCompositionList[0].source.buffer.buffer = std::make_shared<
+ renderengine::ExternalTexture>(mTestLayers[2]->layerFECompositionState.buffer,
+ mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE);
+ EXPECT_CALL(*mTestLayers[2]->layerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(clientCompositionList));
+
+ const std::vector<const LayerState*> layers = {
+ layerState1.get(),
+ layerState2.get(),
+ layerState3.get(),
+ };
+
+ initializeFlattener(layers);
+
+ // 3 has a buffer update, so it will not be merged, and it has round
+ // corners, so it is a PIP.
+ mTime += 200ms;
+ layerState3->resetFramesSinceBufferUpdate();
+
+ initializeOverrideBuffer(layers);
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+ // This will render a CachedSet.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+
+ // We've rendered a CachedSet, but we haven't merged it in.
+ EXPECT_EQ(nullptr, overrideBuffer1);
+ EXPECT_EQ(nullptr, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+
+ // This time we merge the CachedSet in, so we have a new hash, and we should
+ // only have two sets.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ initializeOverrideBuffer(layers);
+ EXPECT_NE(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+
+ EXPECT_NE(nullptr, overrideBuffer1);
+ EXPECT_EQ(overrideBuffer1, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+
+ const auto* peekThroughLayer1 =
+ layerState1->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+ const auto* peekThroughLayer2 =
+ layerState2->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+ EXPECT_EQ(&mTestLayers[2]->outputLayer, peekThroughLayer1);
+ EXPECT_EQ(peekThroughLayer1, peekThroughLayer2);
+}
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index fd70988..1cbcf59 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -25,7 +25,6 @@
#include "ComposerHal.h"
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
-#include <gui/BufferQueue.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/HidlTransportUtils.h>
#include <log/log.h>
@@ -266,15 +265,15 @@
Error Composer::createLayer(Display display, Layer* outLayer)
{
Error error = kDefaultError;
- mClient->createLayer(display, BufferQueue::NUM_BUFFER_SLOTS,
- [&](const auto& tmpError, const auto& tmpLayer) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
+ mClient->createLayer(display, kMaxLayerBufferCount,
+ [&](const auto& tmpError, const auto& tmpLayer) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
- *outLayer = tmpLayer;
- });
+ *outLayer = tmpLayer;
+ });
return error;
}
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index c756d65..0619b8c 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -32,6 +32,7 @@
#include <android/hardware/graphics/composer/2.4/IComposer.h>
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <gui/BufferQueue.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/DisplayedFrameStats.h>
@@ -491,6 +492,11 @@
// 64KiB minus a small space for metadata such as read/write pointers
static constexpr size_t kWriterInitialSize =
64 * 1024 / sizeof(uint32_t) - 16;
+ // Max number of buffers that may be cached for a given layer
+ // We obtain this number by:
+ // 1. Tightly coupling this cache to the max size of BufferQueue
+ // 2. Adding an additional slot for the layer caching feature in SurfaceFlinger (see: Planner.h)
+ static const constexpr uint32_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
CommandWriter mWriter;
CommandReader mReader;
};
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 0033dbe..f19e2a7 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -730,9 +730,11 @@
int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
ATRACE_CALL();
std::scoped_lock lock(mMutex);
+ while (mPredictions.size() >= kMaxTokens) {
+ mPredictions.erase(mPredictions.begin());
+ }
const int64_t assignedToken = mCurrentToken++;
- mPredictions[assignedToken] = {systemTime(), predictions};
- flushTokens(systemTime());
+ mPredictions[assignedToken] = predictions;
return assignedToken;
}
@@ -740,23 +742,11 @@
std::scoped_lock lock(mMutex);
auto predictionsIterator = mPredictions.find(token);
if (predictionsIterator != mPredictions.end()) {
- return predictionsIterator->second.predictions;
+ return predictionsIterator->second;
}
return {};
}
-void TokenManager::flushTokens(nsecs_t flushTime) {
- for (auto it = mPredictions.begin(); it != mPredictions.end();) {
- if (flushTime - it->second.timestamp >= kMaxRetentionTime) {
- it = mPredictions.erase(it);
- } else {
- // Tokens are ordered by time. If i'th token is within the retention time, then the
- // i+1'th token will also be within retention time.
- break;
- }
- }
-}
-
FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
JankClassificationThresholds thresholds)
: mMaxDisplayFrames(kDefaultMaxDisplayFrames),
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 0563a53..42be55a 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -92,11 +92,6 @@
bool operator!=(const TimelineItem& other) const { return !(*this == other); }
};
-struct TokenManagerPrediction {
- nsecs_t timestamp = 0;
- TimelineItem predictions;
-};
-
struct JankClassificationThresholds {
// The various thresholds for App and SF. If the actual timestamp falls within the threshold
// compared to prediction, we treat it as on time.
@@ -334,11 +329,10 @@
void flushTokens(nsecs_t flushTime) REQUIRES(mMutex);
- std::map<int64_t, TokenManagerPrediction> mPredictions GUARDED_BY(mMutex);
+ std::map<int64_t, TimelineItem> mPredictions GUARDED_BY(mMutex);
int64_t mCurrentToken GUARDED_BY(mMutex);
mutable std::mutex mMutex;
- static constexpr nsecs_t kMaxRetentionTime =
- std::chrono::duration_cast<std::chrono::nanoseconds>(120ms).count();
+ static constexpr size_t kMaxTokens = 500;
};
class FrameTimeline : public android::frametimeline::FrameTimeline {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7707aaf..d1426a8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -858,7 +858,7 @@
const State& s(getDrawingState());
State& c(getCurrentState());
- if (getActiveGeometry(c) != getActiveGeometry(s)) {
+ if (c.width != s.width || c.height != s.height || !(c.transform == s.transform)) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
}
@@ -933,20 +933,18 @@
}
bool Layer::setPosition(float x, float y) {
- if (mCurrentState.requested_legacy.transform.tx() == x &&
- mCurrentState.requested_legacy.transform.ty() == y)
- return false;
+ if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) return false;
mCurrentState.sequence++;
// We update the requested and active position simultaneously because
// we want to apply the position portion of the transform matrix immediately,
// but still delay scaling when resizing a SCALING_MODE_FREEZE layer.
- mCurrentState.requested_legacy.transform.set(x, y);
+ mCurrentState.transform.set(x, y);
// Here we directly update the active state
// unlike other setters, because we store it within
// the transform, but use different latching rules.
// b/38182305
- mCurrentState.active_legacy.transform.set(x, y);
+ mCurrentState.transform.set(x, y);
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -1065,6 +1063,7 @@
setDefaultBufferSize(mCurrentState.requested_legacy.w, mCurrentState.requested_legacy.h);
return true;
}
+
bool Layer::setAlpha(float alpha) {
if (mCurrentState.color.a == alpha) return false;
mCurrentState.sequence++;
@@ -1143,8 +1142,7 @@
return false;
}
mCurrentState.sequence++;
- mCurrentState.requested_legacy.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx,
- matrix.dsdy);
+ mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
@@ -1560,20 +1558,20 @@
info.mVisibleRegion = getVisibleRegion(display);
info.mSurfaceDamageRegion = surfaceDamageRegion;
info.mLayerStack = getLayerStack();
- info.mX = ds.active_legacy.transform.tx();
- info.mY = ds.active_legacy.transform.ty();
+ info.mX = ds.transform.tx();
+ info.mY = ds.transform.ty();
info.mZ = ds.z;
- info.mWidth = ds.active_legacy.w;
- info.mHeight = ds.active_legacy.h;
+ info.mWidth = ds.width;
+ info.mHeight = ds.height;
info.mCrop = ds.crop;
info.mColor = ds.color;
info.mFlags = ds.flags;
info.mPixelFormat = getPixelFormat();
info.mDataSpace = static_cast<android_dataspace>(getDataSpace());
- info.mMatrix[0][0] = ds.active_legacy.transform[0][0];
- info.mMatrix[0][1] = ds.active_legacy.transform[0][1];
- info.mMatrix[1][0] = ds.active_legacy.transform[1][0];
- info.mMatrix[1][1] = ds.active_legacy.transform[1][1];
+ info.mMatrix[0][0] = ds.transform[0][0];
+ info.mMatrix[0][1] = ds.transform[0][1];
+ info.mMatrix[1][0] = ds.transform[1][0];
+ info.mMatrix[1][1] = ds.transform[1][1];
{
sp<const GraphicBuffer> buffer = getBuffer();
if (buffer != 0) {
@@ -2449,6 +2447,8 @@
ui::Transform toPhysicalDisplay;
if (display) {
toPhysicalDisplay = display->getTransform();
+ info.displayWidth = display->getWidth();
+ info.displayHeight = display->getHeight();
}
fillInputFrameInfo(info, toPhysicalDisplay);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a83408b..284adbd 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -484,12 +484,9 @@
// to avoid grabbing the lock again to avoid deadlock
virtual bool isCreatedFromMainThread() const { return false; }
- virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
- virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
- virtual uint32_t getActiveHeight(const Layer::State& s) const { return s.active_legacy.h; }
- virtual ui::Transform getActiveTransform(const Layer::State& s) const {
- return s.active_legacy.transform;
- }
+ uint32_t getActiveWidth(const Layer::State& s) const { return s.width; }
+ uint32_t getActiveHeight(const Layer::State& s) const { return s.height; }
+ ui::Transform getActiveTransform(const Layer::State& s) const { return s.transform; }
virtual Region getActiveTransparentRegion(const Layer::State& s) const {
return s.activeTransparentRegion_legacy;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d6108c7..beda834 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3104,7 +3104,7 @@
void SurfaceFlinger::commitTransaction() {
commitTransactionLocked();
- signalSynchronousTransactions();
+ signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
mAnimTransactionPending = false;
}
@@ -3526,7 +3526,9 @@
// Generate a CountDownLatch pending state if this is a synchronous transaction.
if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) {
state.transactionCommittedSignal = std::make_shared<CountDownLatch>(
- (state.inputWindowCommands.syncInputWindows ? 2 : 1));
+ (state.inputWindowCommands.syncInputWindows
+ ? (CountDownLatch::eSyncInputWindows | CountDownLatch::eSyncTransaction)
+ : CountDownLatch::eSyncTransaction));
}
mTransactionQueue.emplace(state);
@@ -3551,10 +3553,10 @@
}
}
-void SurfaceFlinger::signalSynchronousTransactions() {
+void SurfaceFlinger::signalSynchronousTransactions(const uint32_t flag) {
for (auto it = mTransactionCommittedSignals.begin();
it != mTransactionCommittedSignals.end();) {
- if ((*it)->countDown() == 0) {
+ if ((*it)->countDown(flag)) {
it = mTransactionCommittedSignals.erase(it);
} else {
it++;
@@ -4986,6 +4988,13 @@
result.append("\n");
}
+ {
+ DumpArgs plannerArgs;
+ plannerArgs.add(); // first argument is ignored
+ plannerArgs.add(String16("--layers"));
+ dumpPlannerInfo(plannerArgs, result);
+ }
+
/*
* Dump HWComposer state
*/
@@ -6167,7 +6176,7 @@
void SurfaceFlinger::setInputWindowsFinished() {
Mutex::Autolock _l(mStateLock);
- signalSynchronousTransactions();
+ signalSynchronousTransactions(CountDownLatch::eSyncInputWindows);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index cf1a545..4bbdd48 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -467,24 +467,31 @@
class CountDownLatch {
public:
- explicit CountDownLatch(int32_t count) : mCount(count) {}
+ enum {
+ eSyncTransaction = 1 << 0,
+ eSyncInputWindows = 1 << 1,
+ };
+ explicit CountDownLatch(uint32_t flags) : mFlags(flags) {}
- int32_t countDown() {
+ // True if there is no waiting condition after count down.
+ bool countDown(uint32_t flag) {
std::unique_lock<std::mutex> lock(mMutex);
- if (mCount == 0) {
- return 0;
+ if (mFlags == 0) {
+ return true;
}
- if (--mCount == 0) {
+ mFlags &= ~flag;
+ if (mFlags == 0) {
mCountDownComplete.notify_all();
+ return true;
}
- return mCount;
+ return false;
}
// Return true if triggered.
bool wait_until(const std::chrono::seconds& timeout) const {
std::unique_lock<std::mutex> lock(mMutex);
const auto untilTime = std::chrono::system_clock::now() + timeout;
- while (mCount != 0) {
+ while (mFlags != 0) {
// Conditional variables can be woken up sporadically, so we check count
// to verify the wakeup was triggered by |countDown|.
if (std::cv_status::timeout == mCountDownComplete.wait_until(lock, untilTime)) {
@@ -495,7 +502,7 @@
}
private:
- int32_t mCount;
+ uint32_t mFlags;
mutable std::condition_variable mCountDownComplete;
mutable std::mutex mMutex;
};
@@ -1124,7 +1131,7 @@
// Add transaction to the Transaction Queue
void queueTransaction(TransactionState& state) EXCLUDES(mQueueLock);
void waitForSynchronousTransaction(const CountDownLatch& transactionCommittedSignal);
- void signalSynchronousTransactions();
+ void signalSynchronousTransactions(const uint32_t flag);
/*
* Generic Layer Metadata
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 113f463..c5f1598 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -130,8 +130,8 @@
transaction->set_animation(layerFlags & BnSurfaceComposer::eAnimation);
const int32_t layerId(getLayerId(layer));
- addPositionLocked(transaction, layerId, layer->mCurrentState.active_legacy.transform.tx(),
- layer->mCurrentState.active_legacy.transform.ty());
+ addPositionLocked(transaction, layerId, layer->mCurrentState.transform.tx(),
+ layer->mCurrentState.transform.ty());
addDepthLocked(transaction, layerId, layer->mCurrentState.z);
addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
addTransparentRegionLocked(transaction, layerId,
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 6ed6148..c6a4115 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -73,7 +73,7 @@
mTokenManager = &mFrameTimeline->mTokenManager;
mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
maxDisplayFrames = &mFrameTimeline->mMaxDisplayFrames;
- maxTokenRetentionTime = mTokenManager->kMaxRetentionTime;
+ maxTokens = mTokenManager->kMaxTokens;
}
// Each tracing session can be used for a single block of Start -> Stop.
@@ -111,9 +111,11 @@
mFrameTimeline->setSfPresent(2500, presentFence1);
}
- void flushTokens(nsecs_t flushTime) {
- std::lock_guard<std::mutex> lock(mTokenManager->mMutex);
- mTokenManager->flushTokens(flushTime);
+ void flushTokens() {
+ for (size_t i = 0; i < maxTokens; i++) {
+ mTokenManager->generateTokenForPredictions({});
+ }
+ EXPECT_EQ(getPredictions().size(), maxTokens);
}
SurfaceFrame& getSurfaceFrame(size_t displayFrameIdx, size_t surfaceFrameIdx) {
@@ -132,7 +134,7 @@
a.presentTime == b.presentTime;
}
- const std::map<int64_t, TokenManagerPrediction>& getPredictions() const {
+ const std::map<int64_t, TimelineItem>& getPredictions() const {
return mTokenManager->mPredictions;
}
@@ -155,7 +157,7 @@
TraceCookieCounter* mTraceCookieCounter;
FenceToFenceTimeMap fenceFactory;
uint32_t* maxDisplayFrames;
- nsecs_t maxTokenRetentionTime;
+ size_t maxTokens;
static constexpr pid_t kSurfaceFlingerPid = 666;
static constexpr nsecs_t kPresentThreshold = std::chrono::nanoseconds(2ns).count();
static constexpr nsecs_t kDeadlineThreshold = std::chrono::nanoseconds(2ns).count();
@@ -177,12 +179,11 @@
TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) {
int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
EXPECT_EQ(getPredictions().size(), 1u);
- flushTokens(systemTime() + maxTokenRetentionTime);
+ flushTokens();
int64_t token2 = mTokenManager->generateTokenForPredictions({10, 20, 30});
std::optional<TimelineItem> predictions = mTokenManager->getPredictionsForToken(token1);
// token1 should have expired
- EXPECT_EQ(getPredictions().size(), 1u);
EXPECT_EQ(predictions.has_value(), false);
predictions = mTokenManager->getPredictionsForToken(token2);
@@ -212,7 +213,7 @@
TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) {
int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
- flushTokens(systemTime() + maxTokenRetentionTime);
+ flushTokens();
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
sLayerIdOne, sLayerNameOne, sLayerNameOne,
@@ -707,7 +708,7 @@
sLayerNameOne, /*isBuffer*/ true);
surfaceFrame1->setAcquireFenceTime(45);
// Trigger a prediction expiry
- flushTokens(systemTime() + maxTokenRetentionTime);
+ flushTokens();
mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1065,7 +1066,7 @@
tracingSession->StartBlocking();
int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
// Flush the token so that it would expire
- flushTokens(systemTime() + maxTokenRetentionTime);
+ flushTokens();
// Set up the display frame
mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
@@ -1283,7 +1284,7 @@
mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
// Flush the token so that it would expire
- flushTokens(systemTime() + maxTokenRetentionTime);
+ flushTokens();
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
sPidOne, sUidOne, sLayerIdOne, sLayerNameOne,
@@ -1359,7 +1360,7 @@
mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
// Flush the token so that it would expire
- flushTokens(systemTime() + maxTokenRetentionTime);
+ flushTokens();
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
sPidOne, sUidOne, sLayerIdOne, sLayerNameOne,
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index eb24a22..80e9a3c 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -106,42 +106,6 @@
],
}
-cc_binary {
- name: "vr_hwc",
- enabled: false,
- system_ext_specific: true,
- vintf_fragments: ["manifest_vr_hwc.xml"],
- srcs: [
- "vr_hardware_composer_service.cpp",
- ],
- static_libs: [
- "libvr_hwc-impl",
- // NOTE: This needs to be included after the *-impl lib otherwise the
- // symbols in the *-binder library get optimized out.
- "libvr_hwc-binder",
- ],
- shared_libs: [
- "android.frameworks.vr.composer@2.0",
- "android.hardware.graphics.composer@2.3",
- "libbase",
- "libbinder",
- "liblog",
- "libhardware",
- "libhidlbase",
- "libui",
- "libutils",
- "libvr_hwc-hal",
- ],
- cflags: [
- "-DLOG_TAG=\"vr_hwc\"",
- "-Wall",
- "-Werror",
- ],
- init_rc: [
- "vr_hwc.rc",
- ],
-}
-
cc_test {
name: "vr_hwc_test",
gtest: true,
diff --git a/services/vr/hardware_composer/manifest_vr_hwc.xml b/services/vr/hardware_composer/manifest_vr_hwc.xml
deleted file mode 100644
index 1068cac..0000000
--- a/services/vr/hardware_composer/manifest_vr_hwc.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="framework">
- <hal>
- <name>android.hardware.graphics.composer</name>
- <transport>hwbinder</transport>
- <version>2.1</version>
- <interface>
- <name>IComposer</name>
- <instance>vr</instance>
- </interface>
- </hal>
-</manifest>
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
deleted file mode 100644
index 7701847..0000000
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <hwbinder/IPCThreadState.h>
-#include <impl/vr_hwc.h>
-#include <inttypes.h>
-
-#include "vr_composer.h"
-
-int main() {
- android::ProcessState::self()->startThreadPool();
-
- // Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
- // mode.
- android::sp<android::dvr::VrHwc> service = new android::dvr::VrHwc();
-
- LOG_ALWAYS_FATAL_IF(!service.get(), "Failed to get service");
- LOG_ALWAYS_FATAL_IF(service->isRemote(), "Service is remote");
-
- const char instance[] = "vr";
- LOG_ALWAYS_FATAL_IF(service->registerAsService(instance) != android::OK,
- "Failed to register service");
-
- android::sp<android::dvr::VrComposer> composer =
- new android::dvr::VrComposer(service.get());
-
- android::sp<android::IServiceManager> sm(android::defaultServiceManager());
-
- // Register the binder service used by VR Window Manager service to receive
- // frame information from VR HWC HAL.
- android::status_t status = sm->addService(
- android::dvr::VrComposer::SERVICE_NAME(), composer.get(),
- false /* allowIsolated */);
- LOG_ALWAYS_FATAL_IF(status != android::OK,
- "VrDisplay service failed to start: %" PRId32, status);
-
- android::hardware::ProcessState::self()->startThreadPool();
- android::hardware::IPCThreadState::self()->joinThreadPool();
-
- return 0;
-}
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
deleted file mode 100644
index 645ab80..0000000
--- a/services/vr/hardware_composer/vr_hwc.rc
+++ /dev/null
@@ -1,6 +0,0 @@
-service vr_hwc /system/bin/vr_hwc
- class hal animation
- user system
- group system graphics
- onrestart restart surfaceflinger
- writepid /dev/cpuset/system-background/tasks