Merge "Implement host service manager"
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index bc99f4d..a5f98c2 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -142,12 +142,10 @@
}
}
- PipeRelay relay(out, err, interfaceName, instanceName);
-
- if (relay.initCheck() != OK) {
- std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
- err << msg << std::endl;
- LOG(ERROR) << msg;
+ auto relay = PipeRelay::create(out, err, interfaceName + "/" + instanceName);
+ if (!relay.ok()) {
+ err << "Unable to create PipeRelay: " << relay.error() << std::endl;
+ LOG(ERROR) << "Unable to create PipeRelay: " << relay.error();
return IO_ERROR;
}
@@ -155,7 +153,7 @@
native_handle_create(1 /* numFds */, 0 /* numInts */),
native_handle_delete);
- fdHandle->data[0] = relay.fd();
+ fdHandle->data[0] = relay.value()->fd().get();
hardware::Return<void> ret = base->debug(fdHandle.get(), convert(options));
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 4e97636..0c3fb96 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -16,143 +16,93 @@
#include "PipeRelay.h"
-#include <sys/select.h>
-#include <sys/time.h>
+#include <sys/poll.h>
#include <sys/types.h>
#include <unistd.h>
-#include <atomic>
+#include <chrono>
+#include <optional>
-#include <utils/Thread.h>
+#include <android-base/unique_fd.h>
+
+using android::base::borrowed_fd;
+using android::base::Result;
+using android::base::unique_fd;
+using std::chrono_literals::operator""ms;
namespace android {
namespace lshal {
-
-static constexpr struct timeval READ_TIMEOUT { .tv_sec = 1, .tv_usec = 0 };
-
-static std::string getThreadName(std::string interfaceName, const std::string &instanceName) {
- auto dot = interfaceName.rfind(".");
- if (dot != std::string::npos) interfaceName = interfaceName.substr(dot + 1);
- return "RelayThread_" + interfaceName + "_" + instanceName;
+Result<std::unique_ptr<PipeRelay>> PipeRelay::create(std::ostream& os,
+ const NullableOStream<std::ostream>& err,
+ const std::string& fqName) {
+ auto pipeRelay = std::unique_ptr<PipeRelay>(new PipeRelay());
+ unique_fd rfd;
+ if (!android::base::Pipe(&rfd, &pipeRelay->mWrite)) {
+ return android::base::ErrnoError() << "pipe()";
+ }
+ // Workaround for b/111997867: need a separate FD trigger because rfd can't receive POLLHUP
+ // when the write end is closed after the write end was sent through hwbinder.
+ unique_fd rfdTrigger;
+ if (!android::base::Pipe(&rfdTrigger, &pipeRelay->mWriteTrigger)) {
+ return android::base::ErrnoError() << "pipe() for trigger";
+ }
+ pipeRelay->mThread =
+ std::make_unique<std::thread>(&PipeRelay::thread, std::move(rfd), std::move(rfdTrigger),
+ &os, &err, fqName);
+ return pipeRelay;
}
-struct PipeRelay::RelayThread : public Thread {
- explicit RelayThread(int fd, std::ostream &os, const NullableOStream<std::ostream> &err,
- const std::string &fqName);
+void PipeRelay::thread(unique_fd rfd, unique_fd rfdTrigger, std::ostream* out,
+ const NullableOStream<std::ostream>* err, std::string fqName) {
+ while (true) {
+ pollfd pfd[2];
+ pfd[0] = {.fd = rfd.get(), .events = POLLIN};
+ pfd[1] = {.fd = rfdTrigger.get(), .events = 0};
- bool threadLoop() override;
- void setFinished();
-
-private:
- int mFd;
- std::ostream &mOutStream;
- NullableOStream<std::ostream> mErrStream;
-
- // If we were to use requestExit() and exitPending() instead, threadLoop()
- // may not run at all by the time ~PipeRelay is called (i.e. debug() has
- // returned from HAL). By using our own flag, we ensure that select() and
- // read() are executed until data are drained.
- std::atomic_bool mFinished;
-
- std::string mFqName;
-
- DISALLOW_COPY_AND_ASSIGN(RelayThread);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os,
- const NullableOStream<std::ostream> &err,
- const std::string &fqName)
- : mFd(fd), mOutStream(os), mErrStream(err), mFinished(false), mFqName(fqName) {}
-
-bool PipeRelay::RelayThread::threadLoop() {
- char buffer[1024];
-
- fd_set set;
- FD_ZERO(&set);
- FD_SET(mFd, &set);
-
- struct timeval timeout = READ_TIMEOUT;
-
- int res = TEMP_FAILURE_RETRY(select(mFd + 1, &set, nullptr, nullptr, &timeout));
- if (res < 0) {
- mErrStream << "debug " << mFqName << ": select() failed";
- return false;
- }
-
- if (res == 0 || !FD_ISSET(mFd, &set)) {
- if (mFinished) {
- mErrStream << "debug " << mFqName
- << ": timeout reading from pipe, output may be truncated.";
- return false;
+ int pollRes = poll(pfd, arraysize(pfd), -1 /* infinite timeout */);
+ if (pollRes < 0) {
+ int savedErrno = errno;
+ (*err) << "debug " << fqName << ": poll() failed: " << strerror(savedErrno)
+ << std::endl;
+ break;
}
- // timeout, but debug() has not returned, so wait for HAL to finish.
- return true;
- }
- // FD_ISSET(mFd, &set) == true. Data available, start reading
- ssize_t n = TEMP_FAILURE_RETRY(read(mFd, buffer, sizeof(buffer)));
-
- if (n < 0) {
- mErrStream << "debug " << mFqName << ": read() failed";
- }
-
- if (n <= 0) {
- return false;
- }
-
- mOutStream.write(buffer, n);
-
- return true;
-}
-
-void PipeRelay::RelayThread::setFinished() {
- mFinished = true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-PipeRelay::PipeRelay(std::ostream &os, const NullableOStream<std::ostream> &err,
- const std::string &interfaceName, const std::string &instanceName)
- : mInitCheck(NO_INIT) {
- int res = pipe(mFds);
-
- if (res < 0) {
- mInitCheck = -errno;
- return;
- }
-
- mThread = new RelayThread(mFds[0], os, err, interfaceName + "/" + instanceName);
- mInitCheck = mThread->run(getThreadName(interfaceName, instanceName).c_str());
-}
-
-void PipeRelay::CloseFd(int *fd) {
- if (*fd >= 0) {
- close(*fd);
- *fd = -1;
+ if (pfd[0].revents & POLLIN) {
+ char buffer[1024];
+ ssize_t n = TEMP_FAILURE_RETRY(read(rfd.get(), buffer, sizeof(buffer)));
+ if (n < 0) {
+ int savedErrno = errno;
+ (*err) << "debug " << fqName << ": read() failed: " << strerror(savedErrno)
+ << std::endl;
+ break;
+ }
+ if (n == 0) {
+ (*err) << "Warning: debug " << fqName << ": poll() indicates POLLIN but no data"
+ << std::endl;
+ continue;
+ }
+ out->write(buffer, n);
+ }
+ if (pfd[0].revents & POLLHUP) {
+ break;
+ }
+ if (pfd[1].revents & POLLHUP) {
+ // ~PipeRelay is called on the main thread. |mWrite| has been flushed and closed.
+ // Ensure that our read end of the pipe doesn't have pending data, then exit.
+ if ((pfd[0].revents & POLLIN) == 0) {
+ break;
+ }
+ }
}
}
PipeRelay::~PipeRelay() {
- CloseFd(&mFds[1]);
-
- if (mThread != nullptr) {
- mThread->setFinished();
+ mWrite.reset();
+ mWriteTrigger.reset();
+ if (mThread != nullptr && mThread->joinable()) {
mThread->join();
- mThread.clear();
}
-
- CloseFd(&mFds[0]);
}
-status_t PipeRelay::initCheck() const {
- return mInitCheck;
-}
-
-int PipeRelay::fd() const {
- return mFds[1];
-}
-
-} // namespace lshal
-} // namespace android
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
index bd994b4..45ba982 100644
--- a/cmds/lshal/PipeRelay.h
+++ b/cmds/lshal/PipeRelay.h
@@ -16,42 +16,43 @@
#pragma once
+#include <thread>
+
#include <android-base/macros.h>
-#include <ostream>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <ostream>
#include "NullableOStream.h"
namespace android {
namespace lshal {
-/* Creates an AF_UNIX socketpair and spawns a thread that relays any data
+/**
+ * Creates a pipe and spawns a thread that relays any data
* written to the "write"-end of the pair to the specified output stream "os".
*/
struct PipeRelay {
- explicit PipeRelay(std::ostream& os,
- const NullableOStream<std::ostream>& err,
- const std::string& interfaceName,
- const std::string& instanceName);
+ static android::base::Result<std::unique_ptr<PipeRelay>> create(
+ std::ostream& os, const NullableOStream<std::ostream>& err, const std::string& fqName);
~PipeRelay();
- status_t initCheck() const;
-
// Returns the file descriptor corresponding to the "write"-end of the
// connection.
- int fd() const;
+ android::base::borrowed_fd fd() const { return mWrite; }
private:
- struct RelayThread;
-
- status_t mInitCheck;
- int mFds[2];
- sp<RelayThread> mThread;
-
- static void CloseFd(int *fd);
-
+ PipeRelay() = default;
DISALLOW_COPY_AND_ASSIGN(PipeRelay);
+ static void thread(android::base::unique_fd rfd, android::base::unique_fd rfdTrigger,
+ std::ostream* out, const NullableOStream<std::ostream>* err,
+ std::string fqName);
+
+ android::base::unique_fd mWrite;
+ android::base::unique_fd mWriteTrigger;
+ std::unique_ptr<std::thread> mThread;
};
} // namespace lshal
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index 6165911..f66993f 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -40,9 +40,9 @@
void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
- bool tryUnregister();
+ bool tryUnregisterLocked();
- void reRegister();
+ void reRegisterLocked();
protected:
Status onClients(const sp<IBinder>& service, bool clients) override;
@@ -59,6 +59,9 @@
bool registered = true;
};
+ bool registerServiceLocked(const sp<IBinder>& service, const std::string& name,
+ bool allowIsolated, int dumpFlags);
+
/**
* Looks up a service guaranteed to be registered (service from onClients).
*/
@@ -68,7 +71,7 @@
* Unregisters all services that we can. If we can't unregister all, re-register other
* services.
*/
- void tryShutdown();
+ void tryShutdownLocked();
/**
* Try to shutdown the process, unless:
@@ -76,7 +79,10 @@
* - The active services count callback returns 'true', or
* - Some services have clients.
*/
- void maybeTryShutdown();
+ void maybeTryShutdownLocked();
+
+ // for below
+ std::mutex mMutex;
// count of services with clients
size_t mNumConnectedServices;
@@ -117,6 +123,13 @@
bool ClientCounterCallbackImpl::registerService(const sp<IBinder>& service, const std::string& name,
bool allowIsolated, int dumpFlags) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return registerServiceLocked(service, name, allowIsolated, dumpFlags);
+}
+
+bool ClientCounterCallbackImpl::registerServiceLocked(const sp<IBinder>& service,
+ const std::string& name, bool allowIsolated,
+ int dumpFlags) {
auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
bool reRegister = mRegisteredServices.count(name) > 0;
@@ -164,14 +177,15 @@
}
void ClientCounterCallbackImpl::forcePersist(bool persist) {
+ std::lock_guard<std::mutex> lock(mMutex);
mForcePersist = persist;
if (!mForcePersist) {
// Attempt a shutdown in case the number of clients hit 0 while the flag was on
- maybeTryShutdown();
+ maybeTryShutdownLocked();
}
}
-bool ClientCounterCallbackImpl::tryUnregister() {
+bool ClientCounterCallbackImpl::tryUnregisterLocked() {
auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
for (auto& [name, entry] : mRegisteredServices) {
@@ -187,15 +201,14 @@
return true;
}
-void ClientCounterCallbackImpl::reRegister() {
+void ClientCounterCallbackImpl::reRegisterLocked() {
for (auto& [name, entry] : mRegisteredServices) {
// re-register entry if not already registered
if (entry.registered) {
continue;
}
- if (!registerService(entry.service, name, entry.allowIsolated,
- entry.dumpFlags)) {
+ if (!registerServiceLocked(entry.service, name, entry.allowIsolated, entry.dumpFlags)) {
// Must restart. Otherwise, clients will never be able to get a hold of this service.
LOG_ALWAYS_FATAL("Bad state: could not re-register services");
}
@@ -204,7 +217,7 @@
}
}
-void ClientCounterCallbackImpl::maybeTryShutdown() {
+void ClientCounterCallbackImpl::maybeTryShutdownLocked() {
if (mForcePersist) {
ALOGI("Shutdown prevented by forcePersist override flag.");
return;
@@ -223,15 +236,12 @@
// client count change event, try to shutdown the process if its services
// have no clients.
if (!handledInCallback && mNumConnectedServices == 0) {
- tryShutdown();
+ tryShutdownLocked();
}
}
-/**
- * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple
- * invocations could occur on different threads however.
- */
Status ClientCounterCallbackImpl::onClients(const sp<IBinder>& service, bool clients) {
+ std::lock_guard<std::mutex> lock(mMutex);
auto & [name, registered] = *assertRegisteredService(service);
if (registered.clients == clients) {
LOG_ALWAYS_FATAL("Process already thought %s had clients: %d but servicemanager has "
@@ -252,23 +262,24 @@
ALOGI("Process has %zu (of %zu available) client(s) in use after notification %s has clients: %d",
mNumConnectedServices, mRegisteredServices.size(), name.c_str(), clients);
- maybeTryShutdown();
+ maybeTryShutdownLocked();
return Status::ok();
}
- void ClientCounterCallbackImpl::tryShutdown() {
- ALOGI("Trying to shut down the service. No clients in use for any service in process.");
+void ClientCounterCallbackImpl::tryShutdownLocked() {
+ ALOGI("Trying to shut down the service. No clients in use for any service in process.");
- if (tryUnregister()) {
- ALOGI("Unregistered all clients and exiting");
- exit(EXIT_SUCCESS);
- }
+ if (tryUnregisterLocked()) {
+ ALOGI("Unregistered all clients and exiting");
+ exit(EXIT_SUCCESS);
+ }
- reRegister();
+ reRegisterLocked();
}
void ClientCounterCallbackImpl::setActiveServicesCallback(const std::function<bool(bool)>&
activeServicesCallback) {
+ std::lock_guard<std::mutex> lock(mMutex);
mActiveServicesCallback = activeServicesCallback;
}
@@ -291,11 +302,15 @@
}
bool ClientCounterCallback::tryUnregister() {
- return mImpl->tryUnregister();
+ // see comments in header, this should only be called from the active
+ // services callback, see also b/191781736
+ return mImpl->tryUnregisterLocked();
}
void ClientCounterCallback::reRegister() {
- mImpl->reRegister();
+ // see comments in header, this should only be called from the active
+ // services callback, see also b/191781736
+ mImpl->reRegisterLocked();
}
} // namespace internal
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index a8f3fa8..2a87ae4 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -278,7 +278,7 @@
return;
}
- RpcAddress sessionId = RpcAddress::zero();
+ sessionId = RpcAddress::zero();
size_t tries = 0;
do {
// don't block if there is some entropy issue
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 4f55eef..ee5e8bb 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -198,6 +198,8 @@
uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
uint8_t* end = buffer + size;
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
status_t status;
while ((status = triggerablePollRead(fd)) == OK) {
ssize_t readSize = TEMP_FAILURE_RETRY(recv(fd.get(), buffer, end - buffer, MSG_NOSIGNAL));
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index fd2eff6..b5eaaa3 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -26,12 +26,28 @@
#include "Debug.h"
#include "RpcWireFormat.h"
+#include <random>
+
#include <inttypes.h>
namespace android {
using base::ScopeGuard;
+#ifdef RPC_FLAKE_PRONE
+void rpcMaybeWaitToFlake() {
+ static std::random_device r;
+ static std::mutex m;
+
+ unsigned num;
+ {
+ std::lock_guard<std::mutex> lock(m);
+ num = r();
+ }
+ if (num % 10 == 0) usleep(num % 1000);
+}
+#endif
+
RpcState::RpcState() {}
RpcState::~RpcState() {}
@@ -260,6 +276,8 @@
LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, connection->fd.get(),
hexString(data, size).c_str());
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
if (size > std::numeric_limits<ssize_t>::max()) {
ALOGE("Cannot send %s at size %zu (too big)", what, size);
(void)session->shutdownAndWait(false);
@@ -483,7 +501,7 @@
delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data));
(void)dataSize;
LOG_ALWAYS_FATAL_IF(objects != nullptr);
- LOG_ALWAYS_FATAL_IF(objectsCount, 0);
+ LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
}
status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 529dee5..8201eba 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -42,6 +42,15 @@
#define LOG_RPC_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
#endif
+#define RPC_FLAKE_PRONE false
+
+#ifdef RPC_FLAKE_PRONE
+void rpcMaybeWaitToFlake();
+#define MAYBE_WAIT_IN_FLAKE_MODE rpcMaybeWaitToFlake()
+#else
+#define MAYBE_WAIT_IN_FLAKE_MODE do {} while (false)
+#endif
+
/**
* Abstracts away management of ref counts and the wire format from
* RpcSession
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 59f0ba6..e04e326 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -31,7 +31,7 @@
"name": "binderStabilityTest"
},
{
- "name": "binderUtilsTest"
+ "name": "binderUtilsHostTest"
},
{
"name": "libbinder_ndk_unit_test"
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index f3ba830..2e22b84 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -79,9 +79,10 @@
*/
void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
- /**
+ /**
* Try to unregister all services previously registered with 'registerService'.
- * Returns 'true' if successful.
+ * Returns 'true' if successful. This should only be called within the callback registered by
+ * setActiveServicesCallback.
*/
bool tryUnregister();
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index d5990f7..d5a2b61 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -342,4 +342,9 @@
"libgmock",
],
test_suites: ["general-tests"],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index a7cf39a..df308d8 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1621,6 +1621,26 @@
return NO_ERROR;
}
+status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
+ Rect* outRect, uint32_t* outTransform) {
+ ATRACE_CALL();
+ BQ_LOGV("getLastQueuedBuffer");
+
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+ if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) {
+ *outBuffer = nullptr;
+ *outFence = Fence::NO_FENCE;
+ return NO_ERROR;
+ }
+
+ *outBuffer = mSlots[mCore->mLastQueuedSlot].mGraphicBuffer;
+ *outFence = mLastQueueBufferFence;
+ *outRect = mLastQueuedCrop;
+ *outTransform = mLastQueuedTransform;
+
+ return NO_ERROR;
+}
+
void BufferQueueProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
addAndGetFrameTimestamps(nullptr, outDelta);
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index ad00939..6c48534 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -74,6 +74,7 @@
GET_CONSUMER_USAGE,
SET_LEGACY_BUFFER_DROP,
SET_AUTO_PREROTATION,
+ GET_LAST_QUEUED_BUFFER2,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -491,6 +492,56 @@
return result;
}
+ virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
+ Rect* outRect, uint32_t* outTransform) override {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ status_t result = remote()->transact(GET_LAST_QUEUED_BUFFER2, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getLastQueuedBuffer failed to transact: %d", result);
+ return result;
+ }
+ status_t remoteError = NO_ERROR;
+ result = reply.readInt32(&remoteError);
+ if (result != NO_ERROR) {
+ ALOGE("getLastQueuedBuffer failed to read status: %d", result);
+ return result;
+ }
+ if (remoteError != NO_ERROR) {
+ return remoteError;
+ }
+ bool hasBuffer = false;
+ result = reply.readBool(&hasBuffer);
+ if (result != NO_ERROR) {
+ ALOGE("getLastQueuedBuffer failed to read buffer: %d", result);
+ return result;
+ }
+ sp<GraphicBuffer> buffer;
+ if (hasBuffer) {
+ buffer = new GraphicBuffer();
+ result = reply.read(*buffer);
+ if (result == NO_ERROR) {
+ result = reply.read(*outRect);
+ }
+ if (result == NO_ERROR) {
+ result = reply.readUint32(outTransform);
+ }
+ }
+ if (result != NO_ERROR) {
+ ALOGE("getLastQueuedBuffer failed to read buffer: %d", result);
+ return result;
+ }
+ sp<Fence> fence(new Fence);
+ result = reply.read(*fence);
+ if (result != NO_ERROR) {
+ ALOGE("getLastQueuedBuffer failed to read fence: %d", result);
+ return result;
+ }
+ *outBuffer = buffer;
+ *outFence = fence;
+ return result;
+ }
+
virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
Parcel data, reply;
status_t result = data.writeInterfaceToken(
@@ -676,6 +727,11 @@
outBuffer, outFence, outTransformMatrix);
}
+ status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, Rect* outRect,
+ uint32_t* outTransform) override {
+ return mBase->getLastQueuedBuffer(outBuffer, outFence, outRect, outTransform);
+ }
+
void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override {
return mBase->getFrameTimestamps(outDelta);
}
@@ -1025,6 +1081,45 @@
}
return NO_ERROR;
}
+ case GET_LAST_QUEUED_BUFFER2: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ sp<GraphicBuffer> buffer(nullptr);
+ sp<Fence> fence(Fence::NO_FENCE);
+ Rect crop;
+ uint32_t transform;
+ status_t result = getLastQueuedBuffer(&buffer, &fence, &crop, &transform);
+ reply->writeInt32(result);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ if (!buffer.get()) {
+ reply->writeBool(false);
+ } else {
+ reply->writeBool(true);
+ result = reply->write(*buffer);
+ if (result == NO_ERROR) {
+ result = reply->write(crop);
+ }
+ if (result == NO_ERROR) {
+ result = reply->writeUint32(transform);
+ }
+ }
+ if (result != NO_ERROR) {
+ ALOGE("getLastQueuedBuffer failed to write buffer: %d", result);
+ return result;
+ }
+ if (fence == nullptr) {
+ ALOGE("getLastQueuedBuffer returned a NULL fence, setting to Fence::NO_FENCE");
+ fence = Fence::NO_FENCE;
+ }
+ result = reply->write(*fence);
+ if (result != NO_ERROR) {
+ ALOGE("getLastQueuedBuffer failed to write fence: %d", result);
+ return result;
+ }
+ return NO_ERROR;
+ }
+
case GET_FRAME_TIMESTAMPS: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
FrameEventHistoryDelta frameTimestamps;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index d6f9e63..8a64a4f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1207,6 +1207,9 @@
case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER:
res = dispatchGetLastQueuedBuffer(args);
break;
+ case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2:
+ res = dispatchGetLastQueuedBuffer2(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1513,6 +1516,39 @@
return result;
}
+int Surface::dispatchGetLastQueuedBuffer2(va_list args) {
+ AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**);
+ int* fence = va_arg(args, int*);
+ ARect* crop = va_arg(args, ARect*);
+ uint32_t* transform = va_arg(args, uint32_t*);
+ sp<GraphicBuffer> graphicBuffer;
+ sp<Fence> spFence;
+
+ Rect r;
+ int result =
+ mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, &r, transform);
+
+ if (graphicBuffer != nullptr) {
+ *buffer = graphicBuffer->toAHardwareBuffer();
+ AHardwareBuffer_acquire(*buffer);
+
+ // Avoid setting crop* unless buffer is valid (matches IGBP behavior)
+ crop->left = r.left;
+ crop->top = r.top;
+ crop->right = r.right;
+ crop->bottom = r.bottom;
+ } else {
+ *buffer = nullptr;
+ }
+
+ if (spFence != nullptr) {
+ *fence = spFence->dup();
+ } else {
+ *fence = -1;
+ }
+ return result;
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index a7f7d1d..0ad3075 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -186,6 +186,10 @@
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) override;
+ // See IGraphicBufferProducer::getLastQueuedBuffer
+ virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
+ Rect* outRect, uint32_t* outTransform) override;
+
// See IGraphicBufferProducer::getFrameTimestamps
virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 45e0a13..4905b74 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -619,6 +619,22 @@
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) = 0;
+ // Returns the last queued buffer along with a fence which must signal
+ // before the contents of the buffer are read. If there are no buffers in
+ // the queue, outBuffer will be populated with nullptr and outFence will be
+ // populated with Fence::NO_FENCE
+ //
+ // outRect & outTransform are not modified if outBuffer is null.
+ //
+ // Returns NO_ERROR or the status of the Binder transaction
+ virtual status_t getLastQueuedBuffer([[maybe_unused]] sp<GraphicBuffer>* outBuffer,
+ [[maybe_unused]] sp<Fence>* outFence,
+ [[maybe_unused]] Rect* outRect,
+ [[maybe_unused]] uint32_t* outTransform) {
+ // Too many things implement IGraphicBufferProducer...
+ return UNKNOWN_TRANSACTION;
+ }
+
// Gets the frame events that haven't already been retrieved.
virtual void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {}
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 55b4101..10f4df9 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -265,6 +265,7 @@
int dispatchAddQueueInterceptor(va_list args);
int dispatchAddQueryInterceptor(va_list args);
int dispatchGetLastQueuedBuffer(va_list args);
+ int dispatchGetLastQueuedBuffer2(va_list args);
bool transformToDisplayInverse();
protected:
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index b78fc5d..73b46b2 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -255,6 +255,7 @@
NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */
NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */
+ NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 50, /* private */
// clang-format on
};
@@ -1053,6 +1054,31 @@
}
/**
+ * Retrieves the last queued buffer for this window, along with the fence that
+ * fires when the buffer is ready to be read. The cropRect & transform should be applied to the
+ * buffer's content.
+ *
+ * If there was no buffer previously queued, then outBuffer will be NULL and
+ * the value of outFence will be -1.
+ *
+ * Note that if outBuffer is not NULL, then the caller will hold a reference
+ * onto the buffer. Accordingly, the caller must call AHardwareBuffer_release
+ * when the buffer is no longer needed so that the system may reclaim the
+ * buffer.
+ *
+ * \return NO_ERROR on success.
+ * \return NO_MEMORY if there was insufficient memory.
+ * \return STATUS_UNKNOWN_TRANSACTION if this ANativeWindow doesn't support this method, callers
+ * should fall back to ANativeWindow_getLastQueuedBuffer instead.
+ */
+static inline int ANativeWindow_getLastQueuedBuffer2(ANativeWindow* window,
+ AHardwareBuffer** outBuffer, int* outFence,
+ ARect* outCropRect, uint32_t* outTransform) {
+ return window->perform(window, NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2, outBuffer, outFence,
+ outCropRect, outTransform);
+}
+
+/**
* Retrieves an identifier for the next frame to be queued by this window.
*
* \return the next frame id.
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 18a2891..6b2d745 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -140,6 +140,11 @@
outTransformMatrix);
}
+status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
+ Rect* outRect, uint32_t* outTransform) {
+ return mProducer->getLastQueuedBuffer(outBuffer, outFence, outRect, outTransform);
+}
+
void MonitoredProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
mProducer->getFrameTimestamps(outDelta);
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 788919b..3778277 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -64,6 +64,8 @@
virtual status_t setLegacyBufferDrop(bool drop) override;
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) override;
+ virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
+ Rect* outRect, uint32_t* outTransform) override;
virtual IBinder* onAsBinder();
virtual status_t setSharedBufferMode(bool sharedBufferMode) override;
virtual status_t setAutoRefresh(bool autoRefresh) override;