Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09d122a7 authored by Alec Mouri's avatar Alec Mouri
Browse files

[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
parent 329f126b
Loading
Loading
Loading
Loading
+126 −7
Original line number Diff line number Diff line
@@ -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,20 +471,37 @@ 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();
@@ -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;
+25 −3
Original line number Diff line number Diff line
@@ -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;
+23 −0
Original line number Diff line number Diff line
@@ -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);
}
+147 −0
Original line number Diff line number Diff line
@@ -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.
 *
+8 −4
Original line number Diff line number Diff line
@@ -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
};

Loading