[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