diff options
author | 2019-11-25 10:00:53 -0800 | |
---|---|---|
committer | 2020-01-23 18:36:43 -0800 | |
commit | 09d122a798c8436a7e32ab4ca49a0e73398cf106 (patch) | |
tree | e218d34b0382dc26e9f462fa7355d0e426b34fdb | |
parent | 329f126bd5a78f66620dd0b113681e88192d51ed (diff) |
[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
-rw-r--r-- | libs/gui/Surface.cpp | 133 | ||||
-rw-r--r-- | libs/gui/include/gui/Surface.h | 28 | ||||
-rw-r--r-- | libs/nativewindow/ANativeWindow.cpp | 23 | ||||
-rw-r--r-- | libs/nativewindow/include/apex/window.h | 147 | ||||
-rw-r--r-- | libs/nativewindow/include/system/window.h | 12 | ||||
-rw-r--r-- | libs/nativewindow/libnativewindow.map.txt | 4 |
6 files changed, 333 insertions, 14 deletions
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index d5cf11d305..e7880ebc39 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -50,6 +50,17 @@ namespace android { 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_setSwapInterval(ANativeWindow* window, int interval) { 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 @@ int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, 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 @@ int Surface::perform(int operation, va_list args) 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 @@ int Surface::dispatchSetFrameRate(va_list args) { 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 86cc61f3ec..0139507101 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 @@ private: 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 @@ private: 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 @@ protected: // 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 842af18c8c..7fdbeb5a06 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -297,3 +297,26 @@ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) { 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 869b22ec19..2060d037e2 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 14f7214882..a4e5afd38d 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -207,16 +207,16 @@ enum { */ 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 @@ enum { 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 @@ enum { 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 f59e8f0546..127e633247 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -30,6 +30,10 @@ LIBNATIVEWINDOW { 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 |