[ANativeWindow] Support interception methods in apex
This is to support HWUI's ReliableSurface.
Test: builds
Test: Hook up with HWUI and manually verify with settings app
Change-Id: I3a1d75dbd993dde1771930ad25212d8e4e7d94a0
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index d5cf11d..e7880eb 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -50,6 +50,17 @@
using ui::ColorMode;
using ui::Dataspace;
+namespace {
+
+bool isInterceptorRegistrationOp(int op) {
+ return op == NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR ||
+ op == NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR ||
+ op == NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR ||
+ op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR;
+}
+
+} // namespace
+
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
@@ -366,18 +377,58 @@
int Surface::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer, int* fenceFd) {
Surface* c = getSelf(window);
+ {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mDequeueInterceptor != nullptr) {
+ auto interceptor = c->mDequeueInterceptor;
+ auto data = c->mDequeueInterceptorData;
+ return interceptor(window, Surface::dequeueBufferInternal, data, buffer, fenceFd);
+ }
+ }
+ return c->dequeueBuffer(buffer, fenceFd);
+}
+
+int Surface::dequeueBufferInternal(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd) {
+ Surface* c = getSelf(window);
return c->dequeueBuffer(buffer, fenceFd);
}
int Surface::hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd) {
Surface* c = getSelf(window);
+ {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mCancelInterceptor != nullptr) {
+ auto interceptor = c->mCancelInterceptor;
+ auto data = c->mCancelInterceptorData;
+ return interceptor(window, Surface::cancelBufferInternal, data, buffer, fenceFd);
+ }
+ }
+ return c->cancelBuffer(buffer, fenceFd);
+}
+
+int Surface::cancelBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ Surface* c = getSelf(window);
return c->cancelBuffer(buffer, fenceFd);
}
int Surface::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd) {
Surface* c = getSelf(window);
+ {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mQueueInterceptor != nullptr) {
+ auto interceptor = c->mQueueInterceptor;
+ auto data = c->mQueueInterceptorData;
+ return interceptor(window, Surface::queueBufferInternal, data, buffer, fenceFd);
+ }
+ }
+ return c->queueBuffer(buffer, fenceFd);
+}
+
+int Surface::queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ Surface* c = getSelf(window);
return c->queueBuffer(buffer, fenceFd);
}
@@ -420,21 +471,38 @@
return c->queueBuffer(buffer, -1);
}
-int Surface::hook_query(const ANativeWindow* window,
- int what, int* value) {
- const Surface* c = getSelf(window);
- return c->query(what, value);
-}
-
int Surface::hook_perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
Surface* c = getSelf(window);
- int result = c->perform(operation, args);
+ int result;
+ // Don't acquire shared ownership of the interceptor mutex if we're going to
+ // do interceptor registration, as otherwise we'll deadlock on acquiring
+ // exclusive ownership.
+ if (!isInterceptorRegistrationOp(operation)) {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mPerformInterceptor != nullptr) {
+ result = c->mPerformInterceptor(window, Surface::performInternal,
+ c->mPerformInterceptorData, operation, args);
+ va_end(args);
+ return result;
+ }
+ }
+ result = c->perform(operation, args);
va_end(args);
return result;
}
+int Surface::performInternal(ANativeWindow* window, int operation, va_list args) {
+ Surface* c = getSelf(window);
+ return c->perform(operation, args);
+}
+
+int Surface::hook_query(const ANativeWindow* window, int what, int* value) {
+ const Surface* c = getSelf(window);
+ return c->query(what, value);
+}
+
int Surface::setSwapInterval(int interval) {
ATRACE_CALL();
// EGL specification states:
@@ -1096,6 +1164,18 @@
case NATIVE_WINDOW_SET_FRAME_RATE:
res = dispatchSetFrameRate(args);
break;
+ case NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR:
+ res = dispatchAddCancelInterceptor(args);
+ break;
+ case NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR:
+ res = dispatchAddDequeueInterceptor(args);
+ break;
+ case NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR:
+ res = dispatchAddPerformInterceptor(args);
+ break;
+ case NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR:
+ res = dispatchAddQueueInterceptor(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1329,6 +1409,45 @@
return setFrameRate(frameRate);
}
+int Surface::dispatchAddCancelInterceptor(va_list args) {
+ ANativeWindow_cancelBufferInterceptor interceptor =
+ va_arg(args, ANativeWindow_cancelBufferInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mCancelInterceptor = interceptor;
+ mCancelInterceptorData = data;
+ return NO_ERROR;
+}
+
+int Surface::dispatchAddDequeueInterceptor(va_list args) {
+ ANativeWindow_dequeueBufferInterceptor interceptor =
+ va_arg(args, ANativeWindow_dequeueBufferInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mDequeueInterceptor = interceptor;
+ mDequeueInterceptorData = data;
+ return NO_ERROR;
+}
+
+int Surface::dispatchAddPerformInterceptor(va_list args) {
+ ANativeWindow_performInterceptor interceptor = va_arg(args, ANativeWindow_performInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mPerformInterceptor = interceptor;
+ mPerformInterceptorData = data;
+ return NO_ERROR;
+}
+
+int Surface::dispatchAddQueueInterceptor(va_list args) {
+ ANativeWindow_queueBufferInterceptor interceptor =
+ va_arg(args, ANativeWindow_queueBufferInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mQueueInterceptor = interceptor;
+ mQueueInterceptorData = data;
+ return NO_ERROR;
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 86cc61f..0139507 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -21,16 +21,15 @@
#include <gui/HdrMetadata.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
-
+#include <system/window.h>
#include <ui/ANativeObjectBase.h>
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
-
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
-#include <system/window.h>
+#include <shared_mutex>
namespace android {
@@ -205,6 +204,13 @@
ANativeWindowBuffer* buffer, int fenceFd);
static int hook_setSwapInterval(ANativeWindow* window, int interval);
+ static int cancelBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd);
+ static int dequeueBufferInternal(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd);
+ static int performInternal(ANativeWindow* window, int operation, va_list args);
+ static int queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+
static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer);
static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
@@ -252,6 +258,10 @@
int dispatchGetLastDequeueDuration(va_list args);
int dispatchGetLastQueueDuration(va_list args);
int dispatchSetFrameRate(va_list args);
+ int dispatchAddCancelInterceptor(va_list args);
+ int dispatchAddDequeueInterceptor(va_list args);
+ int dispatchAddPerformInterceptor(va_list args);
+ int dispatchAddQueueInterceptor(va_list args);
bool transformToDisplayInverse();
protected:
@@ -457,6 +467,18 @@
// member variables are accessed.
mutable Mutex mMutex;
+ // mInterceptorMutex is the mutex guarding interceptors.
+ std::shared_mutex mInterceptorMutex;
+
+ ANativeWindow_cancelBufferInterceptor mCancelInterceptor = nullptr;
+ void* mCancelInterceptorData = nullptr;
+ ANativeWindow_dequeueBufferInterceptor mDequeueInterceptor = nullptr;
+ void* mDequeueInterceptorData = nullptr;
+ ANativeWindow_performInterceptor mPerformInterceptor = nullptr;
+ void* mPerformInterceptorData = nullptr;
+ ANativeWindow_queueBufferInterceptor mQueueInterceptor = nullptr;
+ void* mQueueInterceptorData = nullptr;
+
// must be used from the lock/unlock thread
sp<GraphicBuffer> mLockedBuffer;
sp<GraphicBuffer> mPostedBuffer;
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 842af18..7fdbeb5 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -297,3 +297,26 @@
int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) {
return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, timeout);
}
+
+int ANativeWindow_setCancelBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_cancelBufferInterceptor interceptor,
+ void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR, interceptor, data);
+}
+
+int ANativeWindow_setDequeueBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_dequeueBufferInterceptor interceptor,
+ void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR, interceptor, data);
+}
+
+int ANativeWindow_setPerformInterceptor(ANativeWindow* window,
+ ANativeWindow_performInterceptor interceptor, void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR, interceptor, data);
+}
+
+int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_queueBufferInterceptor interceptor,
+ void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data);
+}
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 869b22e..2060d03 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -17,12 +17,159 @@
#pragma once
#include <nativebase/nativebase.h>
+#include <stdarg.h>
// apex is a superset of the NDK
#include <android/native_window.h>
__BEGIN_DECLS
+/*
+ * perform bits that can be used with ANativeWindow_perform()
+ *
+ * This is only to support the intercepting methods below - these should notbe
+ * used directly otherwise.
+ */
+enum ANativeWindowPerform {
+ // clang-format off
+ ANATIVEWINDOW_PERFORM_SET_USAGE = 0,
+ ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY = 5,
+ ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT = 9,
+ ANATIVEWINDOW_PERFORM_SET_USAGE64 = 30,
+ // clang-format on
+};
+
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_cancelBuffer is called.
+ */
+typedef int (*ANativeWindow_cancelBufferFn)(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_cancelBufferFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_cancelBufferFn if it were to be called.
+ */
+typedef int (*ANativeWindow_cancelBufferInterceptor)(ANativeWindow* window,
+ ANativeWindow_cancelBufferFn cancelBuffer,
+ void* data, ANativeWindowBuffer* buffer,
+ int fenceFd);
+
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_dequeueBuffer is called.
+ */
+typedef int (*ANativeWindow_dequeueBufferFn)(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_dequeueBufferFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_dequeueBufferFn if it were to be called.
+ */
+typedef int (*ANativeWindow_dequeueBufferInterceptor)(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer,
+ void* data, ANativeWindowBuffer** buffer,
+ int* fenceFd);
+
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_perform is called.
+ */
+typedef int (*ANativeWindow_performFn)(ANativeWindow* window, int operation, va_list args);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_performFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_performFn if it were to be called.
+ */
+typedef int (*ANativeWindow_performInterceptor)(ANativeWindow* window,
+ ANativeWindow_performFn perform, void* data,
+ int operation, va_list args);
+
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_queueBuffer is called.
+ */
+typedef int (*ANativeWindow_queueBufferFn)(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_queueBufferFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_queueBufferFn if it were to be called.
+ */
+typedef int (*ANativeWindow_queueBufferInterceptor)(ANativeWindow* window,
+ ANativeWindow_queueBufferFn queueBuffer,
+ void* data, ANativeWindowBuffer* buffer,
+ int fenceFd);
+
+/**
+ * Registers an interceptor for ANativeWindow_cancelBuffer. Instead of calling
+ * the underlying cancelBuffer function, instead the provided interceptor is
+ * called, which may optionally call the underlying cancelBuffer function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+int ANativeWindow_setCancelBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_cancelBufferInterceptor interceptor,
+ void* data);
+
+/**
+ * Registers an interceptor for ANativeWindow_dequeueBuffer. Instead of calling
+ * the underlying dequeueBuffer function, instead the provided interceptor is
+ * called, which may optionally call the underlying dequeueBuffer function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+int ANativeWindow_setDequeueBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_dequeueBufferInterceptor interceptor,
+ void* data);
+/**
+ * Registers an interceptor for ANativeWindow_perform. Instead of calling
+ * the underlying perform function, instead the provided interceptor is
+ * called, which may optionally call the underlying perform function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+int ANativeWindow_setPerformInterceptor(ANativeWindow* window,
+ ANativeWindow_performInterceptor interceptor, void* data);
+/**
+ * Registers an interceptor for ANativeWindow_queueBuffer. Instead of calling
+ * the underlying queueBuffer function, instead the provided interceptor is
+ * called, which may optionally call the underlying queueBuffer function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_queueBufferInterceptor interceptor,
+ void* data);
+
/**
* Retrieves how long it took for the last time a buffer was dequeued.
*
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 14f7214..a4e5afd 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -207,16 +207,16 @@
*/
enum {
// clang-format off
- NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
+ NATIVE_WINDOW_SET_USAGE = ANATIVEWINDOW_PERFORM_SET_USAGE, /* deprecated */
NATIVE_WINDOW_CONNECT = 1, /* deprecated */
NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
NATIVE_WINDOW_SET_CROP = 3, /* private */
NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
+ NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY, /* deprecated */
NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
- NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
+ NATIVE_WINDOW_SET_BUFFERS_FORMAT = ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT,
NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
NATIVE_WINDOW_LOCK = 11, /* private */
NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
@@ -237,7 +237,7 @@
NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
- NATIVE_WINDOW_SET_USAGE64 = 30,
+ NATIVE_WINDOW_SET_USAGE64 = ANATIVEWINDOW_PERFORM_SET_USAGE64,
NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
@@ -248,6 +248,10 @@
NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, /* private */
NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, /* private */
NATIVE_WINDOW_SET_FRAME_RATE = 40,
+ NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR = 41, /* private */
+ NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR = 42, /* private */
+ NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR = 43, /* private */
+ NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */
// clang-format on
};
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index f59e8f0..127e633 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -30,6 +30,10 @@
ANativeWindow_query; # llndk
ANativeWindow_queryf; # llndk
ANativeWindow_queueBuffer; # llndk
+ ANativeWindow_setCancelBufferInterceptor; # apex # introduced=30
+ ANativeWindow_setDequeueBufferInterceptor; # apex # introduced=30
+ ANativeWindow_setPerformInterceptor; # apex # introduced=30
+ ANativeWindow_setQueueBufferInterceptor; # apex # introduced=30
ANativeWindow_release;
ANativeWindow_setAutoPrerotation; # llndk
ANativeWindow_setAutoRefresh; # llndk