[HWUI] Use ANativeWindow inteception methods in ReliableSurface
Test: boots
Test: manually test with opening and scrolling through settings app
Change-Id: I8d7a44d3ead0b2350318e1514153e256f97ccca5
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5993e17..096e253 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -143,10 +143,11 @@
ATRACE_CALL();
if (surface) {
- mNativeSurface = new ReliableSurface{std::move(surface)};
+ mNativeSurface = std::make_unique<ReliableSurface>(std::move(surface));
+ mNativeSurface->init();
if (enableTimeout) {
// TODO: Fix error handling & re-shorten timeout
- ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms);
+ ANativeWindow_setDequeueTimeout(mNativeSurface->getNativeWindow(), 4000_ms);
}
} else {
mNativeSurface = nullptr;
@@ -161,8 +162,9 @@
}
ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
- bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode,
- mRenderAheadCapacity);
+ bool hasSurface = mRenderPipeline->setSurface(
+ mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior, colorMode,
+ mRenderAheadCapacity);
mFrameNumber = -1;
@@ -428,7 +430,7 @@
presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
(frameIntervalNanos * (renderAhead + 1));
}
- native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
+ native_window_set_buffers_timestamp(mNativeSurface->getNativeWindow(), presentTime);
}
void CanvasContext::draw() {
@@ -489,16 +491,18 @@
swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
swap.vsyncTime = mRenderThread.timeLord().latestVsync();
if (didDraw) {
- nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface.get());
+ nsecs_t dequeueStart =
+ ANativeWindow_getLastDequeueStartTime(mNativeSurface->getNativeWindow());
if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) {
// Ignoring dequeue duration as it happened prior to frame render start
// and thus is not part of the frame.
swap.dequeueDuration = 0;
} else {
swap.dequeueDuration =
- ANativeWindow_getLastDequeueDuration(mNativeSurface.get());
+ ANativeWindow_getLastDequeueDuration(mNativeSurface->getNativeWindow());
}
- swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface.get());
+ swap.queueDuration =
+ ANativeWindow_getLastQueueDuration(mNativeSurface->getNativeWindow());
} else {
swap.dequeueDuration = 0;
swap.queueDuration = 0;
@@ -567,14 +571,16 @@
}
SkISize CanvasContext::getNextFrameSize() const {
- ReliableSurface* surface = mNativeSurface.get();
- if (surface) {
- SkISize size;
- size.fWidth = ANativeWindow_getWidth(surface);
- size.fHeight = ANativeWindow_getHeight(surface);
- return size;
+ static constexpr SkISize defaultFrameSize = {INT32_MAX, INT32_MAX};
+ if (mNativeSurface == nullptr) {
+ return defaultFrameSize;
}
- return {INT32_MAX, INT32_MAX};
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+
+ SkISize size;
+ size.fWidth = ANativeWindow_getWidth(anw);
+ size.fHeight = ANativeWindow_getHeight(anw);
+ return size;
}
void CanvasContext::prepareAndDraw(RenderNode* node) {
@@ -702,11 +708,9 @@
if (!mNativeSurface) return false;
if (mHaveNewSurface) return true;
- int width = -1;
- int height = -1;
- ReliableSurface* surface = mNativeSurface.get();
- surface->query(NATIVE_WINDOW_WIDTH, &width);
- surface->query(NATIVE_WINDOW_HEIGHT, &height);
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+ const int width = ANativeWindow_getWidth(anw);
+ const int height = ANativeWindow_getHeight(anw);
return width != mLastFrameWidth || height != mLastFrameHeight;
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4490f80..0967b20 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -220,7 +220,7 @@
int32_t mLastFrameHeight = 0;
RenderThread& mRenderThread;
- sp<ReliableSurface> mNativeSurface;
+ std::unique_ptr<ReliableSurface> mNativeSurface;
// stopped indicates the CanvasContext will reject actual redraw operations,
// and defer repaint until it is un-stopped
bool mStopped = false;
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index 864780f..e92500f 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -26,64 +26,38 @@
// to propagate this error back to the caller
constexpr bool DISABLE_BUFFER_PREFETCH = true;
-// TODO: Make surface less protected
-// This exists because perform is a varargs, and ANativeWindow has no va_list perform.
-// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do
-// that instead
-struct SurfaceExposer : Surface {
- // Make warnings happy
- SurfaceExposer() = delete;
-
- using Surface::cancelBuffer;
- using Surface::dequeueBuffer;
- using Surface::lockBuffer_DEPRECATED;
- using Surface::perform;
- using Surface::queueBuffer;
- using Surface::setBufferCount;
- using Surface::setSwapInterval;
-};
-
-#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
-
ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
-
- ANativeWindow::setSwapInterval = hook_setSwapInterval;
- ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
- ANativeWindow::cancelBuffer = hook_cancelBuffer;
- ANativeWindow::queueBuffer = hook_queueBuffer;
- ANativeWindow::query = hook_query;
- ANativeWindow::perform = hook_perform;
-
- ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
- ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
- ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
- ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
}
ReliableSurface::~ReliableSurface() {
clearReservedBuffer();
+ // Clear out the interceptors for proper hygiene.
+ // As a concrete example, if the underlying ANativeWindow is associated with
+ // an EGLSurface that is still in use, then if we don't clear out the
+ // interceptors then we walk into undefined behavior.
+ ANativeWindow_setCancelBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setQueueBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setPerformInterceptor(mSurface.get(), nullptr, nullptr);
}
-void ReliableSurface::perform(int operation, va_list args) {
- std::lock_guard _lock{mMutex};
+void ReliableSurface::init() {
+ int result = ANativeWindow_setCancelBufferInterceptor(mSurface.get(), hook_cancelBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set cancelBuffer interceptor: error = %d",
+ result);
- switch (operation) {
- case NATIVE_WINDOW_SET_USAGE:
- mUsage = va_arg(args, uint32_t);
- break;
- case NATIVE_WINDOW_SET_USAGE64:
- mUsage = va_arg(args, uint64_t);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- /* width */ va_arg(args, uint32_t);
- /* height */ va_arg(args, uint32_t);
- mFormat = va_arg(args, PixelFormat);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
- mFormat = va_arg(args, PixelFormat);
- break;
- }
+ result = ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), hook_dequeueBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set dequeueBuffer interceptor: error = %d",
+ result);
+
+ result = ANativeWindow_setQueueBufferInterceptor(mSurface.get(), hook_queueBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set queueBuffer interceptor: error = %d",
+ result);
+
+ result = ANativeWindow_setPerformInterceptor(mSurface.get(), hook_perform, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d",
+ result);
}
int ReliableSurface::reserveNext() {
@@ -111,7 +85,9 @@
int fenceFd = -1;
ANativeWindowBuffer* buffer = nullptr;
- int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
+
+ // Note that this calls back into our own hooked method.
+ int result = ANativeWindow_dequeueBuffer(mSurface.get(), &buffer, &fenceFd);
{
std::lock_guard _lock{mMutex};
@@ -138,61 +114,13 @@
mHasDequeuedBuffer = false;
}
if (buffer) {
- callProtected(mSurface, cancelBuffer, buffer, releaseFd);
+ // Note that clearReservedBuffer may be reentrant here, so
+ // mReservedBuffer must be cleared once we reach here to avoid recursing
+ // forever.
+ ANativeWindow_cancelBuffer(mSurface.get(), buffer, releaseFd);
}
}
-int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
- clearReservedBuffer();
- if (isFallbackBuffer(buffer)) {
- if (fenceFd > 0) {
- close(fenceFd);
- }
- return OK;
- }
- int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd);
- return result;
-}
-
-int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
- {
- std::lock_guard _lock{mMutex};
- if (mReservedBuffer) {
- *buffer = mReservedBuffer;
- *fenceFd = mReservedFenceFd.release();
- mReservedBuffer = nullptr;
- return OK;
- }
- }
-
-
- int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
- if (result != OK) {
- ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
- *buffer = acquireFallbackBuffer(result);
- *fenceFd = -1;
- return *buffer ? OK : INVALID_OPERATION;
- } else {
- std::lock_guard _lock{mMutex};
- mHasDequeuedBuffer = true;
- }
- return OK;
-}
-
-int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
- clearReservedBuffer();
-
- if (isFallbackBuffer(buffer)) {
- if (fenceFd > 0) {
- close(fenceFd);
- }
- return OK;
- }
-
- int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
- return result;
-}
-
bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
if (!mScratchBuffer || !windowBuffer) {
return false;
@@ -229,82 +157,95 @@
return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
}
-Surface* ReliableSurface::getWrapped(const ANativeWindow* window) {
- return getSelf(window)->mSurface.get();
-}
+int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
+ ANativeWindowBuffer** buffer, int* fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ {
+ std::lock_guard _lock{rs->mMutex};
+ if (rs->mReservedBuffer) {
+ *buffer = rs->mReservedBuffer;
+ *fenceFd = rs->mReservedFenceFd.release();
+ rs->mReservedBuffer = nullptr;
+ return OK;
+ }
+ }
-int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) {
- return callProtected(getWrapped(window), setSwapInterval, interval);
-}
-
-int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fenceFd) {
- return getSelf(window)->dequeueBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fenceFd) {
- return getSelf(window)->cancelBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fenceFd) {
- return getSelf(window)->queueBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
- ANativeWindowBuffer* buf;
- int fenceFd = -1;
- int result = window->dequeueBuffer(window, &buf, &fenceFd);
+ int result = dequeueBuffer(window, buffer, fenceFd);
if (result != OK) {
- return result;
+ ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
+ *buffer = rs->acquireFallbackBuffer(result);
+ *fenceFd = -1;
+ return *buffer ? OK : INVALID_OPERATION;
+ } else {
+ std::lock_guard _lock{rs->mMutex};
+ rs->mHasDequeuedBuffer = true;
}
- sp<Fence> fence(new Fence(fenceFd));
- int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
- if (waitResult != OK) {
- ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult);
- window->cancelBuffer(window, buf, -1);
- return waitResult;
- }
- *buffer = buf;
- return result;
-}
-
-int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return window->cancelBuffer(window, buffer, -1);
-}
-
-int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- // This method is a no-op in Surface as well
return OK;
}
-int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return window->queueBuffer(window, buffer, -1);
+int ReliableSurface::hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindow_cancelBufferFn cancelBuffer, void* data,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
+ if (rs->isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+ return cancelBuffer(window, buffer, fenceFd);
}
-int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
- return getWrapped(window)->query(what, value);
+int ReliableSurface::hook_queueBuffer(ANativeWindow* window,
+ ANativeWindow_queueBufferFn queueBuffer, void* data,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
+
+ if (rs->isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+
+ return queueBuffer(window, buffer, fenceFd);
}
-int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
+int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn perform,
+ void* data, int operation, va_list args) {
// Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
// TODO: Filter to things that only affect the reserved buffer
// TODO: Can we mutate the reserved buffer in some cases?
- getSelf(window)->clearReservedBuffer();
- va_list args;
- va_start(args, operation);
- int result = callProtected(getWrapped(window), perform, operation, args);
- va_end(args);
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
- va_start(args, operation);
- getSelf(window)->perform(operation, args);
- va_end(args);
+ va_list argsCopy;
+ va_copy(argsCopy, args);
+ int result = perform(window, operation, argsCopy);
+ {
+ std::lock_guard _lock{rs->mMutex};
+
+ switch (operation) {
+ case ANATIVEWINDOW_PERFORM_SET_USAGE:
+ rs->mUsage = va_arg(args, uint32_t);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_USAGE64:
+ rs->mUsage = va_arg(args, uint64_t);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY:
+ /* width */ va_arg(args, uint32_t);
+ /* height */ va_arg(args, uint32_t);
+ rs->mFormat = va_arg(args, PixelFormat);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT:
+ rs->mFormat = va_arg(args, PixelFormat);
+ break;
+ }
+ }
return result;
}
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index f768df3..a823d9d 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -16,6 +16,7 @@
#pragma once
+#include <apex/window.h>
#include <gui/Surface.h>
#include <utils/Macros.h>
#include <utils/StrongPointer.h>
@@ -24,13 +25,20 @@
namespace android::uirenderer::renderthread {
-class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> {
+class ReliableSurface {
PREVENT_COPY_AND_ASSIGN(ReliableSurface);
public:
ReliableSurface(sp<Surface>&& surface);
~ReliableSurface();
+ // Performs initialization that is not safe to do in the constructor.
+ // For instance, registering ANativeWindow interceptors with ReliableSurface
+ // passed as the data pointer is not safe.
+ void init();
+
+ ANativeWindow* getNativeWindow() { return mSurface.get(); }
+
int reserveNext();
void allocateBuffers() { mSurface->allocateBuffers(); }
@@ -61,7 +69,7 @@
}
private:
- const sp<Surface> mSurface;
+ sp<Surface> mSurface;
mutable std::mutex mMutex;
@@ -78,27 +86,20 @@
ANativeWindowBuffer* acquireFallbackBuffer(int error);
void clearReservedBuffer();
- void perform(int operation, va_list args);
- int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
- int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
- int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+ // ANativeWindow hooks. When an ANativeWindow_* method is called on the
+ // underlying ANativeWindow, these methods will intercept the original call.
+ // For example, an EGL driver would call into these hooks instead of the
+ // original methods.
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindow_cancelBufferFn cancelBuffer,
+ void* data, ANativeWindowBuffer* buffer, int fenceFd);
+ static int hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
+ ANativeWindowBuffer** buffer, int* fenceFd);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindow_queueBufferFn queueBuffer,
+ void* data, ANativeWindowBuffer* buffer, int fenceFd);
- static Surface* getWrapped(const ANativeWindow*);
-
- // ANativeWindow hooks
- static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
- static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fenceFd);
- static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
-
- static int hook_perform(ANativeWindow* window, int operation, ...);
- static int hook_query(const ANativeWindow* window, int what, int* value);
- static int hook_setSwapInterval(ANativeWindow* window, int interval);
-
- static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_perform(ANativeWindow* window, ANativeWindow_performFn perform, void* data,
+ int operation, va_list args);
};
}; // namespace android::uirenderer::renderthread