Merge "Add eglErrorCode to eglInitialize fatal" into sc-dev
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..95eba87 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,28 @@
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::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 +152,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,
@@ -373,6 +176,12 @@
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
@@ -385,7 +194,7 @@
return true;
}
-bool RpcConnection::setupOneSocketClient(const SocketAddress& addr) {
+bool RpcConnection::setupOneSocketClient(const RpcSocketAddress& addr) {
unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
if (serverFd == -1) {
@@ -406,14 +215,19 @@
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..5f024ca 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,30 +119,36 @@
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);
+ LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join.");
+ // TODO(b/185167543): support more than one client at once
+ mConnection = RpcConnection::make();
+ mConnection->setForServer(sp<RpcServer>::fromExisting(this), 42 /*placeholder id*/);
+
mStarted = true;
- for (const sp<RpcConnection>& connection : mConnections) {
for (size_t i = 0; i < mMaxThreads; i++) {
- pool.push_back(std::thread([=] { connection->join(); }));
+ pool.push_back(std::thread([=] {
+ // 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;
+ }
+
+ LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
+ mConnection->join(std::move(clientFd));
+ }));
}
- }
}
// TODO(b/185167543): don't waste extra thread for join, and combine threads
@@ -98,4 +156,39 @@
for (auto& t : pool) t.join();
}
+std::vector<sp<RpcConnection>> RpcServer::listConnections() {
+ std::lock_guard<std::mutex> _l(mLock);
+ if (mConnection == nullptr) return {};
+ return {mConnection};
+}
+
+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..56af0d3 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -48,6 +48,7 @@
enum : uint32_t {
RPC_SPECIAL_TRANSACT_GET_ROOT = 0,
RPC_SPECIAL_TRANSACT_GET_MAX_THREADS = 1,
+ RPC_SPECIAL_TRANSACT_GET_CONNECTION_ID = 2,
};
// serialization is like:
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..7e31e8a 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -32,6 +32,7 @@
class Parcel;
class RpcServer;
+class RpcSocketAddress;
class RpcState;
/**
@@ -43,19 +44,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 +51,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 +88,32 @@
~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 join(base::unique_fd client);
struct ConnectionSocket : public RefBase {
base::unique_fd fd;
@@ -145,11 +123,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);
+ 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,9 +173,10 @@
wp<RpcServer> mForServer; // maybe null, for client connections
- std::unique_ptr<RpcState> mState;
+ // TODO(b/183988761): this shouldn't be guessable
+ std::optional<int32_t> mId;
- base::unique_fd mServer; // socket we are accepting connections on
+ std::unique_ptr<RpcState> mState;
std::mutex mSocketMutex; // for all below
std::condition_variable mSocketCv; // for mWaitingThreads
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 9247128..5535d8a 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,31 @@
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.
*/
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
+ sp<RpcConnection> mConnection;
};
} // namespace android
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..d23df8e 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;
@@ -89,13 +89,23 @@
return Status::ok();
}
Status countBinders(int32_t* out) override {
- if (connection == nullptr) {
+ 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();
+ size_t count = 0;
+ for (auto connection : spServer->listConnections()) {
+ count += connection->state()->countBinders();
}
+ // help debugging if we don't have one binder (this call is always made
+ // in this test when exactly one binder is held, which is held only to
+ // call this method - all other binders should be cleaned up)
+ if (count != 1) {
+ for (auto connection : spServer->listConnections()) {
+ connection->state()->dump();
+ }
+ }
+ *out = count;
return Status::ok();
}
Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
@@ -296,8 +306,7 @@
// 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, const std::function<void(const sp<RpcServer>&)>& configure) {
SocketType socketType = GetParam();
std::string addr = allocateSocketAddress();
@@ -312,21 +321,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,7 +342,7 @@
LOG_ALWAYS_FATAL("Unknown socket type");
}
- configure(server, connection);
+ configure(server);
server->join();
}),
@@ -379,13 +385,11 @@
BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
BinderRpcTestProcessConnection ret{
.proc = createRpcTestSocketServerProcess(numThreads,
- [&](const sp<RpcServer>& server,
- const sp<RpcConnection>& connection) {
+ [&](const sp<RpcServer>& server) {
sp<MyBinderRpcTest> service =
new MyBinderRpcTest;
server->setRootObject(service);
- service->connection =
- connection; // for testing only
+ service->server = server;
}),
};
@@ -397,12 +401,10 @@
};
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, [](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);
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/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 39103df..85322a9 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -969,7 +969,7 @@
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 */);
}
}
@@ -1438,8 +1438,7 @@
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>();
}
@@ -1519,8 +1518,7 @@
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>>();
}
@@ -1600,8 +1598,7 @@
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>>();
}
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/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 0d673ea..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) {
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 6497919..df98eb6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3105,7 +3105,7 @@
void SurfaceFlinger::commitTransaction() {
commitTransactionLocked();
- signalSynchronousTransactions();
+ signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
mAnimTransactionPending = false;
}
@@ -3527,7 +3527,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);
@@ -3552,10 +3554,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++;
@@ -6175,7 +6177,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,