diff options
26 files changed, 762 insertions, 443 deletions
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index f0125868ae..270bfbdc64 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -477,9 +477,14 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, return NO_ERROR; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) +status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, + const sp<Fence>& releaseFence) { +#else status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, const sp<Fence>& releaseFence, EGLDisplay eglDisplay, EGLSyncKHR eglFence) { +#endif ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); @@ -493,27 +498,6 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, return BAD_VALUE; } -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) - if (eglFence != EGL_NO_SYNC_KHR) { - // Most platforms will be using native fences, so it's unlikely that we'll ever have to - // process an eglFence. Ideally we can remove this code eventually. In the mean time, do our - // best to wait for it so the buffer stays valid, otherwise return an error to the caller. - // - // EGL_SYNC_FLUSH_COMMANDS_BIT_KHR so that we don't wait forever on a fence that hasn't - // shown up on the GPU yet. - EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, - 1000000000); - if (result == EGL_FALSE) { - BQ_LOGE("releaseBuffer: error %#x waiting for fence", eglGetError()); - return UNKNOWN_ERROR; - } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - BQ_LOGE("releaseBuffer: timeout waiting for fence"); - return UNKNOWN_ERROR; - } - eglDestroySyncKHR(eglDisplay, eglFence); - } -#endif - sp<IProducerListener> listener; { // Autolock scope std::lock_guard<std::mutex> lock(mCore->mMutex); diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 504509dbec..3ad0e529a5 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -656,9 +656,13 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, return OK; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) +status_t ConsumerBase::releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer) { +#else status_t ConsumerBase::releaseBufferLocked( int slot, const sp<GraphicBuffer> graphicBuffer, EGLDisplay display, EGLSyncKHR eglFence) { +#endif if (mAbandoned) { CB_LOGE("releaseBufferLocked: ConsumerBase is abandoned!"); return NO_INIT; @@ -675,8 +679,12 @@ status_t ConsumerBase::releaseBufferLocked( CB_LOGV("releaseBufferLocked: slot=%d/%" PRIu64, slot, mSlots[slot].mFrameNumber); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence); +#else status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, display, eglFence, mSlots[slot].mFence); +#endif if (err == IGraphicBufferConsumer::STALE_BUFFER_SLOT) { freeBufferLocked(slot); } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 168129b1f7..052b8edfaa 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -417,18 +417,18 @@ void GLConsumer::onSlotCountChanged(int slotCount) { } #endif -status_t GLConsumer::releaseBufferLocked(int buf, - sp<GraphicBuffer> graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence) { +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) +status_t GLConsumer::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence) { // release the buffer if it hasn't already been discarded by the // BufferQueue. This can happen, for example, when the producer of this // buffer has reallocated the original buffer slot after this buffer // was acquired. - status_t err = ConsumerBase::releaseBufferLocked( - buf, graphicBuffer, display, eglFence); + status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence); mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; return err; } +#endif status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease) @@ -490,9 +490,14 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item, // release old buffer if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (pendingRelease == nullptr) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + status_t status = + releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer()); +#else status_t status = releaseBufferLocked( mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); +#endif if (status < NO_ERROR) { GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); @@ -501,10 +506,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item, } } else { pendingRelease->currentTexture = mCurrentTexture; - pendingRelease->graphicBuffer = - mCurrentTextureImage->graphicBuffer(); - pendingRelease->display = mEglDisplay; - pendingRelease->fence = mEglSlots[mCurrentTexture].mEglFence; + pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer(); pendingRelease->isPending = true; } } @@ -744,6 +746,11 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return err; } } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + // Basically all clients are using native fence syncs. If they aren't, we lose nothing + // by waiting here, because the alternative can cause deadlocks (b/339705065). + glFinish(); +#else EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence; if (fence != EGL_NO_SYNC_KHR) { // There is already a fence for the current slot. We need to @@ -773,6 +780,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { } glFlush(); mEglSlots[mCurrentTexture].mEglFence = fence; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) } } diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index c1b65689d6..e133532e02 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -85,6 +85,12 @@ public: return callRemote<Signature>(Tag::ATTACH_BUFFER, slot, buffer); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + status_t releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& releaseFence) override { + using Signature = status_t (IGraphicBufferConsumer::*)(int, uint64_t, const sp<Fence>&); + return callRemote<Signature>(Tag::RELEASE_BUFFER, buf, frameNumber, releaseFence); + } +#else status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)), @@ -92,6 +98,7 @@ public: using Signature = status_t (IGraphicBufferConsumer::*)(int, uint64_t, const sp<Fence>&); return callRemote<Signature>(Tag::RELEASE_BUFFER, buf, frameNumber, releaseFence); } +#endif status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override { using Signature = decltype(&IGraphicBufferConsumer::consumerConnect); diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h index e00c44eb70..f99b54beb1 100644 --- a/libs/gui/include/gui/BufferQueueConsumer.h +++ b/libs/gui/include/gui/BufferQueueConsumer.h @@ -65,13 +65,14 @@ public: // any references to the just-released buffer that it might have, as if it // had received a onBuffersReleased() call with a mask set for the released // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + virtual status_t releaseBuffer(int slot, uint64_t frameNumber, + const sp<Fence>& releaseFence) override; +#else virtual status_t releaseBuffer(int slot, uint64_t frameNumber, const sp<Fence>& releaseFence, EGLDisplay display, EGLSyncKHR fence); - +#endif // connect connects a consumer to the BufferQueue. Only one // consumer may be connected, and when that consumer disconnects the // BufferQueue is placed into the "abandoned" state, causing most @@ -167,6 +168,7 @@ public: // dump our state in a String status_t dumpState(const String8& prefix, String8* outResult) const override; +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) // Functions required for backwards compatibility. // These will be modified/renamed in IGraphicBufferConsumer and will be // removed from this class at that time. See b/13306289. @@ -176,6 +178,7 @@ public: const sp<Fence>& releaseFence) { return releaseBuffer(buf, frameNumber, releaseFence, display, fence); } +#endif virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) { diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index 5cd19c1583..acb0006754 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -245,10 +245,13 @@ protected: // must take place when a buffer is released back to the BufferQueue. If // it is overridden the derived class's implementation must call // ConsumerBase::releaseBufferLocked. +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer); +#else virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer, EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR); - +#endif // returns true iff the slot still has the graphicBuffer in it. bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer); diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 30cbfa2f9f..dbf707f35f 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -271,6 +271,7 @@ protected: #endif // releaseBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase. +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer, EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR) override; @@ -279,16 +280,14 @@ protected: const sp<GraphicBuffer> graphicBuffer, EGLSyncKHR eglFence) { return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } +#endif struct PendingRelease { - PendingRelease() : isPending(false), currentTexture(-1), - graphicBuffer(), display(nullptr), fence(nullptr) {} + PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {} bool isPending; int currentTexture; sp<GraphicBuffer> graphicBuffer; - EGLDisplay display; - EGLSyncKHR fence; }; // This releases the buffer in the slot referenced by mCurrentTexture, @@ -468,16 +467,18 @@ private: // EGLSlot contains the information and object references that // GLConsumer maintains about a BufferQueue buffer slot. struct EglSlot { +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {} - +#endif // mEglImage is the EGLImage created from mGraphicBuffer. sp<EglImage> mEglImage; - +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) // mFence is the EGL sync object that must signal before the buffer // associated with this buffer slot may be dequeued. It is initialized // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based // on a compile-time option) set to a new sync object in updateTexImage. EGLSyncKHR mEglFence; +#endif }; // mEglDisplay is the EGLDisplay with which this GLConsumer is currently diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h index 56eb291335..f6b3e894c2 100644 --- a/libs/gui/include/gui/IGraphicBufferConsumer.h +++ b/libs/gui/include/gui/IGraphicBufferConsumer.h @@ -139,12 +139,17 @@ public: // * the buffer slot was invalid // * the fence was NULL // * the buffer slot specified is not in the acquired state +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, + const sp<Fence>& releaseFence) = 0; +#else virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, const sp<Fence>& releaseFence) = 0; status_t releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& releaseFence) { return releaseBuffer(buf, frameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); } +#endif // consumerConnect connects a consumer to the BufferQueue. Only one consumer may be connected, // and when that consumer disconnects the BufferQueue is placed into the "abandoned" state, diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h index 98f24c2d44..8dfd3cb1f7 100644 --- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h +++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h @@ -18,6 +18,7 @@ #include <gmock/gmock.h> +#include <com_android_graphics_libgui_flags.h> #include <gui/IGraphicBufferConsumer.h> #include <utils/RefBase.h> @@ -33,7 +34,11 @@ public: MOCK_METHOD3(acquireBuffer, status_t(BufferItem*, nsecs_t, uint64_t)); MOCK_METHOD1(detachBuffer, status_t(int)); MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&)); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + MOCK_METHOD3(releaseBuffer, status_t(int, uint64_t, const sp<Fence>&)); +#else MOCK_METHOD5(releaseBuffer, status_t(int, uint64_t, EGLDisplay, EGLSyncKHR, const sp<Fence>&)); +#endif MOCK_METHOD2(consumerConnect, status_t(const sp<IConsumerListener>&, bool)); MOCK_METHOD0(consumerDisconnect, status_t()); MOCK_METHOD1(getReleasedBuffers, status_t(uint64_t*)); diff --git a/libs/nativedisplay/include/surfacetexture/EGLConsumer.h b/libs/nativedisplay/include/surfacetexture/EGLConsumer.h index 444722bf83..226a8a60af 100644 --- a/libs/nativedisplay/include/surfacetexture/EGLConsumer.h +++ b/libs/nativedisplay/include/surfacetexture/EGLConsumer.h @@ -113,18 +113,11 @@ public: protected: struct PendingRelease { - PendingRelease() - : isPending(false), - currentTexture(-1), - graphicBuffer(), - display(nullptr), - fence(nullptr) {} + PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {} bool isPending; int currentTexture; sp<GraphicBuffer> graphicBuffer; - EGLDisplay display; - EGLSyncKHR fence; }; /** @@ -250,13 +243,16 @@ protected: * EGLConsumer maintains about a BufferQueue buffer slot. */ struct EglSlot { - EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {} +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {} +#endif /** * mEglImage is the EGLImage created from mGraphicBuffer. */ sp<EglImage> mEglImage; +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) /** * mFence is the EGL sync object that must signal before the buffer * associated with this buffer slot may be dequeued. It is initialized @@ -264,6 +260,7 @@ protected: * on a compile-time option) set to a new sync object in updateTexImage. */ EGLSyncKHR mEglFence; +#endif }; /** diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h index 006a785cb7..253aa18a24 100644 --- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h +++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h @@ -343,9 +343,13 @@ protected: * releaseBufferLocked overrides the ConsumerBase method to update the * mEglSlots array in addition to the ConsumerBase. */ +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer) override; +#else virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer, EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR) override; +#endif /** * freeBufferLocked frees up the given buffer slot. If the slot has been diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp index 3959fce008..fad0f6cd0b 100644 --- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp +++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp @@ -221,7 +221,11 @@ void EGLConsumer::onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st) { } void EGLConsumer::onReleaseBufferLocked(int buf) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + (void)buf; +#else mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; +#endif } status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease, @@ -283,10 +287,15 @@ status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRele // release old buffer if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (pendingRelease == nullptr) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + status_t status = st.releaseBufferLocked(st.mCurrentTexture, + mCurrentTextureImage->graphicBuffer()); +#else status_t status = st.releaseBufferLocked(st.mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay, mEglSlots[st.mCurrentTexture].mEglFence); +#endif if (status < NO_ERROR) { EGC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); @@ -296,8 +305,6 @@ status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRele } else { pendingRelease->currentTexture = st.mCurrentTexture; pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer(); - pendingRelease->display = mEglDisplay; - pendingRelease->fence = mEglSlots[st.mCurrentTexture].mEglFence; pendingRelease->isPending = true; } } @@ -502,6 +509,11 @@ status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) { return err; } } else if (st.mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + // Basically all clients are using native fence syncs. If they aren't, we lose nothing + // by waiting here, because the alternative can cause deadlocks (b/339705065). + glFinish(); +#else EGLSyncKHR fence = mEglSlots[st.mCurrentTexture].mEglFence; if (fence != EGL_NO_SYNC_KHR) { // There is already a fence for the current slot. We need to @@ -531,6 +543,7 @@ status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) { } glFlush(); mEglSlots[st.mCurrentTexture].mEglFence = fence; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) } } diff --git a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp index 60e87b54d5..1ffd382b80 100644 --- a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp +++ b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +#define EGL_EGLEXT_PROTOTYPES +#include <EGL/egl.h> +#include <EGL/eglext.h> + #include <gui/BufferQueue.h> #include <surfacetexture/ImageConsumer.h> #include <surfacetexture/SurfaceTexture.h> @@ -95,10 +99,34 @@ sp<GraphicBuffer> ImageConsumer::dequeueBuffer(int* outSlotid, android_dataspace } // Finally release the old buffer. +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + EGLSyncKHR previousFence = mImageSlots[st.mCurrentTexture].eglFence(); + if (previousFence != EGL_NO_SYNC_KHR) { + // Most platforms will be using native fences, so it's unlikely that we'll ever have to + // process an eglFence. Ideally we can remove this code eventually. In the mean time, do + // our best to wait for it so the buffer stays valid, otherwise return an error to the + // caller. + // + // EGL_SYNC_FLUSH_COMMANDS_BIT_KHR so that we don't wait forever on a fence that hasn't + // shown up on the GPU yet. + EGLint result = eglClientWaitSyncKHR(display, previousFence, + EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 1000000000); + if (result == EGL_FALSE) { + IMG_LOGE("dequeueBuffer: error %#x waiting for fence", eglGetError()); + } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { + IMG_LOGE("dequeueBuffer: timeout waiting for fence"); + } + eglDestroySyncKHR(display, previousFence); + } + + status_t status = st.releaseBufferLocked(st.mCurrentTexture, + st.mSlots[st.mCurrentTexture].mGraphicBuffer); +#else status_t status = st.releaseBufferLocked(st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, display, mImageSlots[st.mCurrentTexture].eglFence()); +#endif if (status < NO_ERROR) { IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status); err = status; diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp index ce232cc4c7..c0a1cc5c36 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -178,13 +178,21 @@ status_t SurfaceTexture::acquireBufferLocked(BufferItem* item, nsecs_t presentWh return NO_ERROR; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) +status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer) { +#else status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer, EGLDisplay display, EGLSyncKHR eglFence) { +#endif // release the buffer if it hasn't already been discarded by the // BufferQueue. This can happen, for example, when the producer of this // buffer has reallocated the original buffer slot after this buffer // was acquired. +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP) + status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer); +#else status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence); +#endif // We could be releasing an EGL/Vulkan buffer, even if not currently // attached to a GL context. mImageConsumer.onReleaseBufferLocked(buf); diff --git a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp deleted file mode 100644 index 9039751959..0000000000 --- a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AndroidInputEventProtoConverter.h" - -#include <android-base/logging.h> -#include <perfetto/trace/android/android_input_event.pbzero.h> - -namespace android::inputdispatcher::trace { - -namespace { - -using namespace ftl::flag_operators; - -// The trace config to use for maximal tracing. -const impl::TraceConfig CONFIG_TRACE_ALL{ - .flags = impl::TraceFlag::TRACE_DISPATCHER_INPUT_EVENTS | - impl::TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH, - .rules = {impl::TraceRule{.level = impl::TraceLevel::TRACE_LEVEL_COMPLETE, - .matchAllPackages = {}, - .matchAnyPackages = {}, - .matchSecure{}, - .matchImeConnectionActive = {}}}, -}; - -} // namespace - -void AndroidInputEventProtoConverter::toProtoMotionEvent(const TracedMotionEvent& event, - proto::AndroidMotionEvent& outProto, - bool isRedacted) { - outProto.set_event_id(event.id); - outProto.set_event_time_nanos(event.eventTime); - outProto.set_down_time_nanos(event.downTime); - outProto.set_source(event.source); - outProto.set_action(event.action); - outProto.set_device_id(event.deviceId); - outProto.set_display_id(event.displayId.val()); - outProto.set_classification(static_cast<int32_t>(event.classification)); - outProto.set_flags(event.flags); - outProto.set_policy_flags(event.policyFlags); - outProto.set_button_state(event.buttonState); - outProto.set_action_button(event.actionButton); - - if (!isRedacted) { - outProto.set_cursor_position_x(event.xCursorPosition); - outProto.set_cursor_position_y(event.yCursorPosition); - outProto.set_meta_state(event.metaState); - outProto.set_precision_x(event.xPrecision); - outProto.set_precision_y(event.yPrecision); - } - - for (uint32_t i = 0; i < event.pointerProperties.size(); i++) { - auto* pointer = outProto.add_pointer(); - - const auto& props = event.pointerProperties[i]; - pointer->set_pointer_id(props.id); - pointer->set_tool_type(static_cast<int32_t>(props.toolType)); - - const auto& coords = event.pointerCoords[i]; - auto bits = BitSet64(coords.bits); - for (int32_t axisIndex = 0; !bits.isEmpty(); axisIndex++) { - const auto axis = bits.clearFirstMarkedBit(); - auto axisEntry = pointer->add_axis_value(); - axisEntry->set_axis(axis); - - if (!isRedacted) { - axisEntry->set_value(coords.values[axisIndex]); - } - } - } -} - -void AndroidInputEventProtoConverter::toProtoKeyEvent(const TracedKeyEvent& event, - proto::AndroidKeyEvent& outProto, - bool isRedacted) { - outProto.set_event_id(event.id); - outProto.set_event_time_nanos(event.eventTime); - outProto.set_down_time_nanos(event.downTime); - outProto.set_source(event.source); - outProto.set_action(event.action); - outProto.set_device_id(event.deviceId); - outProto.set_display_id(event.displayId.val()); - outProto.set_repeat_count(event.repeatCount); - outProto.set_flags(event.flags); - outProto.set_policy_flags(event.policyFlags); - - if (!isRedacted) { - outProto.set_key_code(event.keyCode); - outProto.set_scan_code(event.scanCode); - outProto.set_meta_state(event.metaState); - } -} - -void AndroidInputEventProtoConverter::toProtoWindowDispatchEvent( - const WindowDispatchArgs& args, proto::AndroidWindowInputDispatchEvent& outProto, - bool isRedacted) { - std::visit([&](auto entry) { outProto.set_event_id(entry.id); }, args.eventEntry); - outProto.set_vsync_id(args.vsyncId); - outProto.set_window_id(args.windowId); - outProto.set_resolved_flags(args.resolvedFlags); - - if (isRedacted) { - return; - } - if (auto* motion = std::get_if<TracedMotionEvent>(&args.eventEntry); motion != nullptr) { - for (size_t i = 0; i < motion->pointerProperties.size(); i++) { - auto* pointerProto = outProto.add_dispatched_pointer(); - pointerProto->set_pointer_id(motion->pointerProperties[i].id); - const auto& coords = motion->pointerCoords[i]; - const auto rawXY = - MotionEvent::calculateTransformedXY(motion->source, args.rawTransform, - coords.getXYValue()); - if (coords.getXYValue() != rawXY) { - // These values are only traced if they were modified by the raw transform - // to save space. Trace consumers should be aware of this optimization. - pointerProto->set_x_in_display(rawXY.x); - pointerProto->set_y_in_display(rawXY.y); - } - - const auto coordsInWindow = - MotionEvent::calculateTransformedCoords(motion->source, motion->flags, - args.transform, coords); - auto bits = BitSet64(coords.bits); - for (int32_t axisIndex = 0; !bits.isEmpty(); axisIndex++) { - const uint32_t axis = bits.clearFirstMarkedBit(); - const float axisValueInWindow = coordsInWindow.values[axisIndex]; - // Only values that are modified by the window transform are traced. - if (coords.values[axisIndex] != axisValueInWindow) { - auto* axisEntry = pointerProto->add_axis_value_in_window(); - axisEntry->set_axis(axis); - axisEntry->set_value(axisValueInWindow); - } - } - } - } -} - -impl::TraceConfig AndroidInputEventProtoConverter::parseConfig( - proto::AndroidInputEventConfig::Decoder& protoConfig) { - if (protoConfig.has_mode() && - protoConfig.mode() == proto::AndroidInputEventConfig::TRACE_MODE_TRACE_ALL) { - // User has requested the preset for maximal tracing - return CONFIG_TRACE_ALL; - } - - impl::TraceConfig config; - - // Parse trace flags - if (protoConfig.has_trace_dispatcher_input_events() && - protoConfig.trace_dispatcher_input_events()) { - config.flags |= impl::TraceFlag::TRACE_DISPATCHER_INPUT_EVENTS; - } - if (protoConfig.has_trace_dispatcher_window_dispatch() && - protoConfig.trace_dispatcher_window_dispatch()) { - config.flags |= impl::TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH; - } - - // Parse trace rules - auto rulesIt = protoConfig.rules(); - while (rulesIt) { - proto::AndroidInputEventConfig::TraceRule::Decoder protoRule{rulesIt->as_bytes()}; - config.rules.emplace_back(); - auto& rule = config.rules.back(); - - rule.level = protoRule.has_trace_level() - ? static_cast<impl::TraceLevel>(protoRule.trace_level()) - : impl::TraceLevel::TRACE_LEVEL_NONE; - - if (protoRule.has_match_all_packages()) { - auto pkgIt = protoRule.match_all_packages(); - while (pkgIt) { - rule.matchAllPackages.emplace_back(pkgIt->as_std_string()); - pkgIt++; - } - } - - if (protoRule.has_match_any_packages()) { - auto pkgIt = protoRule.match_any_packages(); - while (pkgIt) { - rule.matchAnyPackages.emplace_back(pkgIt->as_std_string()); - pkgIt++; - } - } - - if (protoRule.has_match_secure()) { - rule.matchSecure = protoRule.match_secure(); - } - - if (protoRule.has_match_ime_connection_active()) { - rule.matchImeConnectionActive = protoRule.match_ime_connection_active(); - } - - rulesIt++; - } - - return config; -} - -} // namespace android::inputdispatcher::trace diff --git a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.h b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.h index 887913f463..eb33e2b894 100644 --- a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.h +++ b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.h @@ -26,20 +26,198 @@ namespace proto = perfetto::protos::pbzero; namespace android::inputdispatcher::trace { +namespace internal { + +using namespace ftl::flag_operators; + +// The trace config to use for maximal tracing. +const impl::TraceConfig CONFIG_TRACE_ALL{ + .flags = impl::TraceFlag::TRACE_DISPATCHER_INPUT_EVENTS | + impl::TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH, + .rules = {impl::TraceRule{.level = impl::TraceLevel::TRACE_LEVEL_COMPLETE, + .matchAllPackages = {}, + .matchAnyPackages = {}, + .matchSecure{}, + .matchImeConnectionActive = {}}}, +}; + +} // namespace internal + /** * Write traced events into Perfetto protos. + * + * This class is templated so that the logic can be tested while substituting the proto classes + * auto-generated by Perfetto's pbzero library with mock implementations. */ +template <typename ProtoMotion, typename ProtoKey, typename ProtoDispatch, + typename ProtoConfigDecoder> class AndroidInputEventProtoConverter { public: - static void toProtoMotionEvent(const TracedMotionEvent& event, - proto::AndroidMotionEvent& outProto, bool isRedacted); - static void toProtoKeyEvent(const TracedKeyEvent& event, proto::AndroidKeyEvent& outProto, - bool isRedacted); - static void toProtoWindowDispatchEvent(const WindowDispatchArgs&, - proto::AndroidWindowInputDispatchEvent& outProto, - bool isRedacted); - - static impl::TraceConfig parseConfig(proto::AndroidInputEventConfig::Decoder& protoConfig); + static void toProtoMotionEvent(const TracedMotionEvent& event, ProtoMotion& outProto, + bool isRedacted) { + outProto.set_event_id(event.id); + outProto.set_event_time_nanos(event.eventTime); + outProto.set_down_time_nanos(event.downTime); + outProto.set_source(event.source); + outProto.set_action(event.action); + outProto.set_device_id(event.deviceId); + outProto.set_display_id(event.displayId.val()); + outProto.set_classification(static_cast<int32_t>(event.classification)); + outProto.set_flags(event.flags); + outProto.set_policy_flags(event.policyFlags); + outProto.set_button_state(event.buttonState); + outProto.set_action_button(event.actionButton); + + if (!isRedacted) { + outProto.set_cursor_position_x(event.xCursorPosition); + outProto.set_cursor_position_y(event.yCursorPosition); + outProto.set_meta_state(event.metaState); + outProto.set_precision_x(event.xPrecision); + outProto.set_precision_y(event.yPrecision); + } + + for (uint32_t i = 0; i < event.pointerProperties.size(); i++) { + auto* pointer = outProto.add_pointer(); + + const auto& props = event.pointerProperties[i]; + pointer->set_pointer_id(props.id); + pointer->set_tool_type(static_cast<int32_t>(props.toolType)); + + const auto& coords = event.pointerCoords[i]; + auto bits = BitSet64(coords.bits); + for (int32_t axisIndex = 0; !bits.isEmpty(); axisIndex++) { + const auto axis = bits.clearFirstMarkedBit(); + auto axisEntry = pointer->add_axis_value(); + axisEntry->set_axis(axis); + + if (!isRedacted) { + axisEntry->set_value(coords.values[axisIndex]); + } + } + } + } + + static void toProtoKeyEvent(const TracedKeyEvent& event, ProtoKey& outProto, bool isRedacted) { + outProto.set_event_id(event.id); + outProto.set_event_time_nanos(event.eventTime); + outProto.set_down_time_nanos(event.downTime); + outProto.set_source(event.source); + outProto.set_action(event.action); + outProto.set_device_id(event.deviceId); + outProto.set_display_id(event.displayId.val()); + outProto.set_repeat_count(event.repeatCount); + outProto.set_flags(event.flags); + outProto.set_policy_flags(event.policyFlags); + + if (!isRedacted) { + outProto.set_key_code(event.keyCode); + outProto.set_scan_code(event.scanCode); + outProto.set_meta_state(event.metaState); + } + } + + static void toProtoWindowDispatchEvent(const WindowDispatchArgs& args, ProtoDispatch& outProto, + bool isRedacted) { + std::visit([&](auto entry) { outProto.set_event_id(entry.id); }, args.eventEntry); + outProto.set_vsync_id(args.vsyncId); + outProto.set_window_id(args.windowId); + outProto.set_resolved_flags(args.resolvedFlags); + + if (isRedacted) { + return; + } + if (auto* motion = std::get_if<TracedMotionEvent>(&args.eventEntry); motion != nullptr) { + for (size_t i = 0; i < motion->pointerProperties.size(); i++) { + auto* pointerProto = outProto.add_dispatched_pointer(); + pointerProto->set_pointer_id(motion->pointerProperties[i].id); + const auto& coords = motion->pointerCoords[i]; + const auto rawXY = + MotionEvent::calculateTransformedXY(motion->source, args.rawTransform, + coords.getXYValue()); + if (coords.getXYValue() != rawXY) { + // These values are only traced if they were modified by the raw transform + // to save space. Trace consumers should be aware of this optimization. + pointerProto->set_x_in_display(rawXY.x); + pointerProto->set_y_in_display(rawXY.y); + } + + const auto coordsInWindow = + MotionEvent::calculateTransformedCoords(motion->source, motion->flags, + args.transform, coords); + auto bits = BitSet64(coords.bits); + for (int32_t axisIndex = 0; !bits.isEmpty(); axisIndex++) { + const uint32_t axis = bits.clearFirstMarkedBit(); + const float axisValueInWindow = coordsInWindow.values[axisIndex]; + // Only values that are modified by the window transform are traced. + if (coords.values[axisIndex] != axisValueInWindow) { + auto* axisEntry = pointerProto->add_axis_value_in_window(); + axisEntry->set_axis(axis); + axisEntry->set_value(axisValueInWindow); + } + } + } + } + } + + static impl::TraceConfig parseConfig(ProtoConfigDecoder& protoConfig) { + if (protoConfig.has_mode() && + protoConfig.mode() == proto::AndroidInputEventConfig::TRACE_MODE_TRACE_ALL) { + // User has requested the preset for maximal tracing + return internal::CONFIG_TRACE_ALL; + } + + impl::TraceConfig config; + + // Parse trace flags + if (protoConfig.has_trace_dispatcher_input_events() && + protoConfig.trace_dispatcher_input_events()) { + config.flags |= impl::TraceFlag::TRACE_DISPATCHER_INPUT_EVENTS; + } + if (protoConfig.has_trace_dispatcher_window_dispatch() && + protoConfig.trace_dispatcher_window_dispatch()) { + config.flags |= impl::TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH; + } + + // Parse trace rules + auto rulesIt = protoConfig.rules(); + while (rulesIt) { + proto::AndroidInputEventConfig::TraceRule::Decoder protoRule{rulesIt->as_bytes()}; + config.rules.emplace_back(); + auto& rule = config.rules.back(); + + rule.level = protoRule.has_trace_level() + ? static_cast<impl::TraceLevel>(protoRule.trace_level()) + : impl::TraceLevel::TRACE_LEVEL_NONE; + + if (protoRule.has_match_all_packages()) { + auto pkgIt = protoRule.match_all_packages(); + while (pkgIt) { + rule.matchAllPackages.emplace_back(pkgIt->as_std_string()); + pkgIt++; + } + } + + if (protoRule.has_match_any_packages()) { + auto pkgIt = protoRule.match_any_packages(); + while (pkgIt) { + rule.matchAnyPackages.emplace_back(pkgIt->as_std_string()); + pkgIt++; + } + } + + if (protoRule.has_match_secure()) { + rule.matchSecure = protoRule.match_secure(); + } + + if (protoRule.has_match_ime_connection_active()) { + rule.matchImeConnectionActive = protoRule.match_ime_connection_active(); + } + + rulesIt++; + } + + return config; + } }; } // namespace android::inputdispatcher::trace diff --git a/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h b/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h index 761d619cec..823f8a5882 100644 --- a/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h +++ b/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h @@ -70,7 +70,7 @@ struct TracedMotionEvent { uint32_t policyFlags; int32_t deviceId; uint32_t source; - ui::LogicalDisplayId displayId; + ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID; int32_t action; int32_t actionButton; int32_t flags; diff --git a/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp b/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp index 77b5c2ebcd..ebcd9c986e 100644 --- a/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp +++ b/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp @@ -34,6 +34,11 @@ namespace { constexpr auto INPUT_EVENT_TRACE_DATA_SOURCE_NAME = "android.input.inputevent"; +using ProtoConverter = + AndroidInputEventProtoConverter<proto::AndroidMotionEvent, proto::AndroidKeyEvent, + proto::AndroidWindowInputDispatchEvent, + proto::AndroidInputEventConfig::Decoder>; + bool isPermanentlyAllowed(gui::Uid uid) { switch (uid.val()) { case AID_SYSTEM: @@ -85,7 +90,7 @@ void PerfettoBackend::InputEventDataSource::OnSetup(const InputEventDataSource:: const auto rawConfig = args.config->android_input_event_config_raw(); auto protoConfig = perfetto::protos::pbzero::AndroidInputEventConfig::Decoder{rawConfig}; - mConfig = AndroidInputEventProtoConverter::parseConfig(protoConfig); + mConfig = ProtoConverter::parseConfig(protoConfig); } void PerfettoBackend::InputEventDataSource::OnStart(const InputEventDataSource::StartArgs&) { @@ -238,7 +243,7 @@ void PerfettoBackend::traceMotionEvent(const TracedMotionEvent& event, auto* inputEvent = winscopeExtensions->set_android_input_event(); auto* dispatchMotion = isRedacted ? inputEvent->set_dispatcher_motion_event_redacted() : inputEvent->set_dispatcher_motion_event(); - AndroidInputEventProtoConverter::toProtoMotionEvent(event, *dispatchMotion, isRedacted); + ProtoConverter::toProtoMotionEvent(event, *dispatchMotion, isRedacted); }); } @@ -266,7 +271,7 @@ void PerfettoBackend::traceKeyEvent(const TracedKeyEvent& event, auto* inputEvent = winscopeExtensions->set_android_input_event(); auto* dispatchKey = isRedacted ? inputEvent->set_dispatcher_key_event_redacted() : inputEvent->set_dispatcher_key_event(); - AndroidInputEventProtoConverter::toProtoKeyEvent(event, *dispatchKey, isRedacted); + ProtoConverter::toProtoKeyEvent(event, *dispatchKey, isRedacted); }); } @@ -295,8 +300,7 @@ void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs auto* dispatchEvent = isRedacted ? inputEvent->set_dispatcher_window_dispatch_event_redacted() : inputEvent->set_dispatcher_window_dispatch_event(); - AndroidInputEventProtoConverter::toProtoWindowDispatchEvent(dispatchArgs, *dispatchEvent, - isRedacted); + ProtoConverter::toProtoWindowDispatchEvent(dispatchArgs, *dispatchEvent, isRedacted); }); } diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 5b885889d1..18d47f648b 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -48,6 +48,7 @@ cc_test { ], srcs: [ ":inputdispatcher_common_test_sources", + "AndroidInputEventProtoConverter_test.cpp", "AnrTracker_test.cpp", "CapturedTouchpadEventConverter_test.cpp", "CursorInputMapper_test.cpp", diff --git a/services/inputflinger/tests/AndroidInputEventProtoConverter_test.cpp b/services/inputflinger/tests/AndroidInputEventProtoConverter_test.cpp new file mode 100644 index 0000000000..414da66cd2 --- /dev/null +++ b/services/inputflinger/tests/AndroidInputEventProtoConverter_test.cpp @@ -0,0 +1,261 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../dispatcher/trace/AndroidInputEventProtoConverter.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +namespace android::inputdispatcher::trace { + +namespace { + +using testing::Return, testing::_; + +class MockProtoAxisValue { +public: + MOCK_METHOD(void, set_axis, (int32_t)); + MOCK_METHOD(void, set_value, (float)); +}; + +class MockProtoPointer { +public: + MOCK_METHOD(void, set_pointer_id, (uint32_t)); + MOCK_METHOD(void, set_tool_type, (int32_t)); + MOCK_METHOD(MockProtoAxisValue*, add_axis_value, ()); +}; + +class MockProtoMotion { +public: + MOCK_METHOD(void, set_event_id, (uint32_t)); + MOCK_METHOD(void, set_event_time_nanos, (int64_t)); + MOCK_METHOD(void, set_down_time_nanos, (int64_t)); + MOCK_METHOD(void, set_source, (uint32_t)); + MOCK_METHOD(void, set_action, (int32_t)); + MOCK_METHOD(void, set_device_id, (uint32_t)); + MOCK_METHOD(void, set_display_id, (uint32_t)); + MOCK_METHOD(void, set_classification, (int32_t)); + MOCK_METHOD(void, set_flags, (uint32_t)); + MOCK_METHOD(void, set_policy_flags, (uint32_t)); + MOCK_METHOD(void, set_button_state, (uint32_t)); + MOCK_METHOD(void, set_action_button, (uint32_t)); + MOCK_METHOD(void, set_cursor_position_x, (float)); + MOCK_METHOD(void, set_cursor_position_y, (float)); + MOCK_METHOD(void, set_meta_state, (uint32_t)); + MOCK_METHOD(void, set_precision_x, (float)); + MOCK_METHOD(void, set_precision_y, (float)); + MOCK_METHOD(MockProtoPointer*, add_pointer, ()); +}; + +using TestProtoConverter = AndroidInputEventProtoConverter<MockProtoMotion, proto::AndroidKeyEvent, + proto::AndroidWindowInputDispatchEvent, + proto::AndroidInputEventConfig::Decoder>; + +TEST(AndroidInputEventProtoConverterTest, ToProtoMotionEvent) { + TracedMotionEvent event{}; + event.id = 1; + event.eventTime = 2; + event.downTime = 3; + event.source = AINPUT_SOURCE_MOUSE; + event.action = AMOTION_EVENT_ACTION_BUTTON_PRESS; + event.deviceId = 4; + event.displayId = ui::LogicalDisplayId(5); + event.classification = MotionClassification::PINCH; + event.flags = 6; + event.policyFlags = 7; + event.buttonState = 8; + event.actionButton = 9; + event.xCursorPosition = 10.0f; + event.yCursorPosition = 11.0f; + event.metaState = 12; + event.xPrecision = 13.0f; + event.yPrecision = 14.0f; + event.pointerProperties.emplace_back(PointerProperties{ + .id = 15, + .toolType = ToolType::MOUSE, + }); + event.pointerProperties.emplace_back(PointerProperties{ + .id = 16, + .toolType = ToolType::FINGER, + }); + event.pointerCoords.emplace_back(); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, 17.0f); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, 18.0f); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 19.0f); + event.pointerCoords.emplace_back(); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, 20.0f); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, 21.0f); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22.0f); + + testing::StrictMock<MockProtoMotion> proto; + testing::StrictMock<MockProtoPointer> pointer1; + testing::StrictMock<MockProtoPointer> pointer2; + testing::StrictMock<MockProtoAxisValue> axisValue1; + testing::StrictMock<MockProtoAxisValue> axisValue2; + testing::StrictMock<MockProtoAxisValue> axisValue3; + testing::StrictMock<MockProtoAxisValue> axisValue4; + testing::StrictMock<MockProtoAxisValue> axisValue5; + testing::StrictMock<MockProtoAxisValue> axisValue6; + + EXPECT_CALL(proto, set_event_id(1)); + EXPECT_CALL(proto, set_event_time_nanos(2)); + EXPECT_CALL(proto, set_down_time_nanos(3)); + EXPECT_CALL(proto, set_source(AINPUT_SOURCE_MOUSE)); + EXPECT_CALL(proto, set_action(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + EXPECT_CALL(proto, set_device_id(4)); + EXPECT_CALL(proto, set_display_id(5)); + EXPECT_CALL(proto, set_classification(AMOTION_EVENT_CLASSIFICATION_PINCH)); + EXPECT_CALL(proto, set_flags(6)); + EXPECT_CALL(proto, set_policy_flags(7)); + EXPECT_CALL(proto, set_button_state(8)); + EXPECT_CALL(proto, set_action_button(9)); + EXPECT_CALL(proto, set_cursor_position_x(10.0f)); + EXPECT_CALL(proto, set_cursor_position_y(11.0f)); + EXPECT_CALL(proto, set_meta_state(12)); + EXPECT_CALL(proto, set_precision_x(13.0f)); + EXPECT_CALL(proto, set_precision_y(14.0f)); + + EXPECT_CALL(proto, add_pointer()).WillOnce(Return(&pointer1)).WillOnce(Return(&pointer2)); + + EXPECT_CALL(pointer1, set_pointer_id(15)); + EXPECT_CALL(pointer1, set_tool_type(AMOTION_EVENT_TOOL_TYPE_MOUSE)); + EXPECT_CALL(pointer1, add_axis_value()) + .WillOnce(Return(&axisValue1)) + .WillOnce(Return(&axisValue2)) + .WillOnce(Return(&axisValue3)); + EXPECT_CALL(axisValue1, set_axis(AMOTION_EVENT_AXIS_X)); + EXPECT_CALL(axisValue1, set_value(17.0f)); + EXPECT_CALL(axisValue2, set_axis(AMOTION_EVENT_AXIS_Y)); + EXPECT_CALL(axisValue2, set_value(18.0f)); + EXPECT_CALL(axisValue3, set_axis(AMOTION_EVENT_AXIS_PRESSURE)); + EXPECT_CALL(axisValue3, set_value(19.0f)); + + EXPECT_CALL(pointer2, set_pointer_id(16)); + EXPECT_CALL(pointer2, set_tool_type(AMOTION_EVENT_TOOL_TYPE_FINGER)); + EXPECT_CALL(pointer2, add_axis_value()) + .WillOnce(Return(&axisValue4)) + .WillOnce(Return(&axisValue5)) + .WillOnce(Return(&axisValue6)); + EXPECT_CALL(axisValue4, set_axis(AMOTION_EVENT_AXIS_X)); + EXPECT_CALL(axisValue4, set_value(20.0f)); + EXPECT_CALL(axisValue5, set_axis(AMOTION_EVENT_AXIS_Y)); + EXPECT_CALL(axisValue5, set_value(21.0f)); + EXPECT_CALL(axisValue6, set_axis(AMOTION_EVENT_AXIS_PRESSURE)); + EXPECT_CALL(axisValue6, set_value(22.0f)); + + TestProtoConverter::toProtoMotionEvent(event, proto, /*isRedacted=*/false); +} + +TEST(AndroidInputEventProtoConverterTest, ToProtoMotionEvent_Redacted) { + TracedMotionEvent event{}; + event.id = 1; + event.eventTime = 2; + event.downTime = 3; + event.source = AINPUT_SOURCE_MOUSE; + event.action = AMOTION_EVENT_ACTION_BUTTON_PRESS; + event.deviceId = 4; + event.displayId = ui::LogicalDisplayId(5); + event.classification = MotionClassification::PINCH; + event.flags = 6; + event.policyFlags = 7; + event.buttonState = 8; + event.actionButton = 9; + event.xCursorPosition = 10.0f; + event.yCursorPosition = 11.0f; + event.metaState = 12; + event.xPrecision = 13.0f; + event.yPrecision = 14.0f; + event.pointerProperties.emplace_back(PointerProperties{ + .id = 15, + .toolType = ToolType::MOUSE, + }); + event.pointerProperties.emplace_back(PointerProperties{ + .id = 16, + .toolType = ToolType::FINGER, + }); + event.pointerCoords.emplace_back(); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, 17.0f); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, 18.0f); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 19.0f); + event.pointerCoords.emplace_back(); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, 20.0f); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, 21.0f); + event.pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22.0f); + + testing::StrictMock<MockProtoMotion> proto; + testing::StrictMock<MockProtoPointer> pointer1; + testing::StrictMock<MockProtoPointer> pointer2; + testing::StrictMock<MockProtoAxisValue> axisValue1; + testing::StrictMock<MockProtoAxisValue> axisValue2; + testing::StrictMock<MockProtoAxisValue> axisValue3; + testing::StrictMock<MockProtoAxisValue> axisValue4; + testing::StrictMock<MockProtoAxisValue> axisValue5; + testing::StrictMock<MockProtoAxisValue> axisValue6; + + EXPECT_CALL(proto, set_event_id(1)); + EXPECT_CALL(proto, set_event_time_nanos(2)); + EXPECT_CALL(proto, set_down_time_nanos(3)); + EXPECT_CALL(proto, set_source(AINPUT_SOURCE_MOUSE)); + EXPECT_CALL(proto, set_action(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + EXPECT_CALL(proto, set_device_id(4)); + EXPECT_CALL(proto, set_display_id(5)); + EXPECT_CALL(proto, set_classification(AMOTION_EVENT_CLASSIFICATION_PINCH)); + EXPECT_CALL(proto, set_flags(6)); + EXPECT_CALL(proto, set_policy_flags(7)); + EXPECT_CALL(proto, set_button_state(8)); + EXPECT_CALL(proto, set_action_button(9)); + + EXPECT_CALL(proto, add_pointer()).WillOnce(Return(&pointer1)).WillOnce(Return(&pointer2)); + + EXPECT_CALL(pointer1, set_pointer_id(15)); + EXPECT_CALL(pointer1, set_tool_type(AMOTION_EVENT_TOOL_TYPE_MOUSE)); + EXPECT_CALL(pointer1, add_axis_value()) + .WillOnce(Return(&axisValue1)) + .WillOnce(Return(&axisValue2)) + .WillOnce(Return(&axisValue3)); + EXPECT_CALL(axisValue1, set_axis(AMOTION_EVENT_AXIS_X)); + EXPECT_CALL(axisValue2, set_axis(AMOTION_EVENT_AXIS_Y)); + EXPECT_CALL(axisValue3, set_axis(AMOTION_EVENT_AXIS_PRESSURE)); + + EXPECT_CALL(pointer2, set_pointer_id(16)); + EXPECT_CALL(pointer2, set_tool_type(AMOTION_EVENT_TOOL_TYPE_FINGER)); + EXPECT_CALL(pointer2, add_axis_value()) + .WillOnce(Return(&axisValue4)) + .WillOnce(Return(&axisValue5)) + .WillOnce(Return(&axisValue6)); + EXPECT_CALL(axisValue4, set_axis(AMOTION_EVENT_AXIS_X)); + EXPECT_CALL(axisValue5, set_axis(AMOTION_EVENT_AXIS_Y)); + EXPECT_CALL(axisValue6, set_axis(AMOTION_EVENT_AXIS_PRESSURE)); + + // Redacted fields + EXPECT_CALL(proto, set_meta_state(_)).Times(0); + EXPECT_CALL(proto, set_cursor_position_x(_)).Times(0); + EXPECT_CALL(proto, set_cursor_position_y(_)).Times(0); + EXPECT_CALL(proto, set_precision_x(_)).Times(0); + EXPECT_CALL(proto, set_precision_y(_)).Times(0); + EXPECT_CALL(axisValue1, set_value(_)).Times(0); + EXPECT_CALL(axisValue2, set_value(_)).Times(0); + EXPECT_CALL(axisValue3, set_value(_)).Times(0); + EXPECT_CALL(axisValue4, set_value(_)).Times(0); + EXPECT_CALL(axisValue5, set_value(_)).Times(0); + EXPECT_CALL(axisValue6, set_value(_)).Times(0); + + TestProtoConverter::toProtoMotionEvent(event, proto, /*isRedacted=*/true); +} + +} // namespace + +} // namespace android::inputdispatcher::trace diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index 67b1e8c249..5a14f4bdfe 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -31,6 +31,30 @@ static const int HW_TIMEOUT_MULTIPLIER = base::GetIntProperty("ro.hw_timeout_mul } // namespace +DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height, + ui::Rotation orientation, bool isActive, const std::string& uniqueId, + std::optional<uint8_t> physicalPort, ViewportType type) { + const bool isRotated = orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270; + DisplayViewport v; + v.displayId = displayId; + v.orientation = orientation; + v.logicalLeft = 0; + v.logicalTop = 0; + v.logicalRight = isRotated ? height : width; + v.logicalBottom = isRotated ? width : height; + v.physicalLeft = 0; + v.physicalTop = 0; + v.physicalRight = isRotated ? height : width; + v.physicalBottom = isRotated ? width : height; + v.deviceWidth = isRotated ? height : width; + v.deviceHeight = isRotated ? width : height; + v.isActive = isActive; + v.uniqueId = uniqueId; + v.physicalPort = physicalPort; + v.type = type; + return v; +}; + void FakeInputReaderPolicy::assertInputDevicesChanged() { waitForInputDevices( [](bool devicesChanged) { @@ -115,33 +139,6 @@ void FakeInputReaderPolicy::addDisplayViewport(DisplayViewport viewport) { mConfig.setDisplayViewports(mViewports); } -void FakeInputReaderPolicy::addDisplayViewport(ui::LogicalDisplayId displayId, int32_t width, - int32_t height, ui::Rotation orientation, - bool isActive, const std::string& uniqueId, - std::optional<uint8_t> physicalPort, - ViewportType type) { - const bool isRotated = orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270; - DisplayViewport v; - v.displayId = displayId; - v.orientation = orientation; - v.logicalLeft = 0; - v.logicalTop = 0; - v.logicalRight = isRotated ? height : width; - v.logicalBottom = isRotated ? width : height; - v.physicalLeft = 0; - v.physicalTop = 0; - v.physicalRight = isRotated ? height : width; - v.physicalBottom = isRotated ? width : height; - v.deviceWidth = isRotated ? height : width; - v.deviceHeight = isRotated ? width : height; - v.isActive = isActive; - v.uniqueId = uniqueId; - v.physicalPort = physicalPort; - v.type = type; - - addDisplayViewport(v); -} - bool FakeInputReaderPolicy::updateViewport(const DisplayViewport& viewport) { size_t count = mViewports.size(); for (size_t i = 0; i < count; i++) { diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h index 42c956789b..9dce31a8a6 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -31,6 +31,10 @@ namespace android { +DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height, + ui::Rotation orientation, bool isActive, const std::string& uniqueId, + std::optional<uint8_t> physicalPort, ViewportType type); + class FakeInputReaderPolicy : public InputReaderPolicyInterface { protected: virtual ~FakeInputReaderPolicy() {} @@ -50,9 +54,6 @@ public: std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const; std::optional<DisplayViewport> getDisplayViewportByPort(uint8_t displayPort) const; void addDisplayViewport(DisplayViewport viewport); - void addDisplayViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height, - ui::Rotation orientation, bool isActive, const std::string& uniqueId, - std::optional<uint8_t> physicalPort, ViewportType type); bool updateViewport(const DisplayViewport& viewport); void addExcludedDeviceName(const std::string& deviceName); void addInputPortAssociation(const std::string& inputPort, uint8_t displayPort); diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp index 77f42f2e72..652a6580dc 100644 --- a/services/inputflinger/tests/InputMapperTest.cpp +++ b/services/inputflinger/tests/InputMapperTest.cpp @@ -186,8 +186,10 @@ void InputMapperTest::setDisplayInfoAndReconfigure(ui::LogicalDisplayId displayI const std::string& uniqueId, std::optional<uint8_t> physicalPort, ViewportType viewportType) { - mFakePolicy->addDisplayViewport(displayId, width, height, orientation, /* isActive= */ true, - uniqueId, physicalPort, viewportType); + DisplayViewport viewport = + createViewport(displayId, width, height, orientation, /* isActive= */ true, uniqueId, + physicalPort, viewportType); + mFakePolicy->addDisplayViewport(viewport); configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 50cbedf407..a8e4736aea 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -385,30 +385,29 @@ TEST_F(InputReaderPolicyTest, Viewports_GetCleared) { static const std::string uniqueId = "local:0"; // We didn't add any viewports yet, so there shouldn't be any. - std::optional<DisplayViewport> internalViewport = - mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); - ASSERT_FALSE(internalViewport); + ASSERT_FALSE(mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL)); // Add an internal viewport, then clear it - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, uniqueId, NO_PORT, ViewportType::INTERNAL); - + DisplayViewport internalViewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, uniqueId, NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(internalViewport); // Check matching by uniqueId - internalViewport = mFakePolicy->getDisplayViewportByUniqueId(uniqueId); - ASSERT_TRUE(internalViewport); - ASSERT_EQ(ViewportType::INTERNAL, internalViewport->type); + std::optional<DisplayViewport> receivedInternalViewport = + mFakePolicy->getDisplayViewportByUniqueId(uniqueId); + ASSERT_TRUE(receivedInternalViewport.has_value()); + ASSERT_EQ(internalViewport, *receivedInternalViewport); // Check matching by viewport type - internalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); - ASSERT_TRUE(internalViewport); - ASSERT_EQ(uniqueId, internalViewport->uniqueId); + receivedInternalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); + ASSERT_TRUE(receivedInternalViewport.has_value()); + ASSERT_EQ(internalViewport, *receivedInternalViewport); mFakePolicy->clearViewports(); + // Make sure nothing is found after clear - internalViewport = mFakePolicy->getDisplayViewportByUniqueId(uniqueId); - ASSERT_FALSE(internalViewport); - internalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); - ASSERT_FALSE(internalViewport); + ASSERT_FALSE(mFakePolicy->getDisplayViewportByUniqueId(uniqueId)); + ASSERT_FALSE(mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL)); } TEST_F(InputReaderPolicyTest, Viewports_GetByType) { @@ -420,49 +419,49 @@ TEST_F(InputReaderPolicyTest, Viewports_GetByType) { constexpr ui::LogicalDisplayId virtualDisplayId2 = ui::LogicalDisplayId{3}; // Add an internal viewport - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, internalUniqueId, NO_PORT, - ViewportType::INTERNAL); + DisplayViewport internalViewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, internalUniqueId, NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(internalViewport); // Add an external viewport - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, externalUniqueId, NO_PORT, - ViewportType::EXTERNAL); + DisplayViewport externalViewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, externalUniqueId, NO_PORT, ViewportType::EXTERNAL); + mFakePolicy->addDisplayViewport(externalViewport); // Add an virtual viewport - mFakePolicy->addDisplayViewport(virtualDisplayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /*isActive=*/true, virtualUniqueId1, NO_PORT, - ViewportType::VIRTUAL); + DisplayViewport virtualViewport1 = + createViewport(virtualDisplayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, virtualUniqueId1, NO_PORT, ViewportType::VIRTUAL); + mFakePolicy->addDisplayViewport(virtualViewport1); // Add another virtual viewport - mFakePolicy->addDisplayViewport(virtualDisplayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /*isActive=*/true, virtualUniqueId2, NO_PORT, - ViewportType::VIRTUAL); + DisplayViewport virtualViewport2 = + createViewport(virtualDisplayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, virtualUniqueId2, NO_PORT, ViewportType::VIRTUAL); + mFakePolicy->addDisplayViewport(virtualViewport2); // Check matching by type for internal - std::optional<DisplayViewport> internalViewport = + std::optional<DisplayViewport> receivedInternalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); - ASSERT_TRUE(internalViewport); - ASSERT_EQ(internalUniqueId, internalViewport->uniqueId); + ASSERT_TRUE(receivedInternalViewport.has_value()); + ASSERT_EQ(internalViewport, *receivedInternalViewport); // Check matching by type for external - std::optional<DisplayViewport> externalViewport = + std::optional<DisplayViewport> receivedExternalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::EXTERNAL); - ASSERT_TRUE(externalViewport); - ASSERT_EQ(externalUniqueId, externalViewport->uniqueId); + ASSERT_TRUE(receivedExternalViewport.has_value()); + ASSERT_EQ(externalViewport, *receivedExternalViewport); // Check matching by uniqueId for virtual viewport #1 - std::optional<DisplayViewport> virtualViewport1 = + std::optional<DisplayViewport> receivedVirtualViewport1 = mFakePolicy->getDisplayViewportByUniqueId(virtualUniqueId1); - ASSERT_TRUE(virtualViewport1); - ASSERT_EQ(ViewportType::VIRTUAL, virtualViewport1->type); - ASSERT_EQ(virtualUniqueId1, virtualViewport1->uniqueId); - ASSERT_EQ(virtualDisplayId1, virtualViewport1->displayId); + ASSERT_TRUE(receivedVirtualViewport1.has_value()); + ASSERT_EQ(virtualViewport1, *receivedVirtualViewport1); // Check matching by uniqueId for virtual viewport #2 - std::optional<DisplayViewport> virtualViewport2 = + std::optional<DisplayViewport> receivedVirtualViewport2 = mFakePolicy->getDisplayViewportByUniqueId(virtualUniqueId2); - ASSERT_TRUE(virtualViewport2); - ASSERT_EQ(ViewportType::VIRTUAL, virtualViewport2->type); - ASSERT_EQ(virtualUniqueId2, virtualViewport2->uniqueId); - ASSERT_EQ(virtualDisplayId2, virtualViewport2->displayId); + ASSERT_TRUE(receivedVirtualViewport2.has_value()); + ASSERT_EQ(virtualViewport2, *receivedVirtualViewport2); } @@ -482,24 +481,26 @@ TEST_F(InputReaderPolicyTest, Viewports_TwoOfSameType) { for (const ViewportType& type : types) { mFakePolicy->clearViewports(); // Add a viewport - mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, uniqueId1, NO_PORT, type); + DisplayViewport viewport1 = + createViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, uniqueId1, NO_PORT, type); + mFakePolicy->addDisplayViewport(viewport1); // Add another viewport - mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, uniqueId2, NO_PORT, type); + DisplayViewport viewport2 = + createViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, uniqueId2, NO_PORT, type); + mFakePolicy->addDisplayViewport(viewport2); // Check that correct display viewport was returned by comparing the display IDs. - std::optional<DisplayViewport> viewport1 = + std::optional<DisplayViewport> receivedViewport1 = mFakePolicy->getDisplayViewportByUniqueId(uniqueId1); - ASSERT_TRUE(viewport1); - ASSERT_EQ(displayId1, viewport1->displayId); - ASSERT_EQ(type, viewport1->type); + ASSERT_TRUE(receivedViewport1.has_value()); + ASSERT_EQ(viewport1, *receivedViewport1); - std::optional<DisplayViewport> viewport2 = + std::optional<DisplayViewport> receivedViewport2 = mFakePolicy->getDisplayViewportByUniqueId(uniqueId2); - ASSERT_TRUE(viewport2); - ASSERT_EQ(displayId2, viewport2->displayId); - ASSERT_EQ(type, viewport2->type); + ASSERT_TRUE(receivedViewport2.has_value()); + ASSERT_EQ(viewport2, *receivedViewport2); // When there are multiple viewports of the same kind, and uniqueId is not specified // in the call to getDisplayViewport, then that situation is not supported. @@ -525,32 +526,27 @@ TEST_F(InputReaderPolicyTest, Viewports_ByTypeReturnsDefaultForInternal) { // Add the default display first and ensure it gets returned. mFakePolicy->clearViewports(); - mFakePolicy->addDisplayViewport(ui::LogicalDisplayId::DEFAULT, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /*isActive=*/true, uniqueId1, NO_PORT, - ViewportType::INTERNAL); - mFakePolicy->addDisplayViewport(nonDefaultDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /*isActive=*/true, uniqueId2, NO_PORT, - ViewportType::INTERNAL); - - std::optional<DisplayViewport> viewport = + DisplayViewport viewport1 = createViewport(ui::LogicalDisplayId::DEFAULT, DISPLAY_WIDTH, + DISPLAY_HEIGHT, ui::ROTATION_0, /*isActive=*/true, + uniqueId1, NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(viewport1); + DisplayViewport viewport2 = + createViewport(nonDefaultDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, uniqueId2, NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(viewport2); + std::optional<DisplayViewport> receivedViewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); - ASSERT_TRUE(viewport); - ASSERT_EQ(ui::LogicalDisplayId::DEFAULT, viewport->displayId); - ASSERT_EQ(ViewportType::INTERNAL, viewport->type); + ASSERT_TRUE(receivedViewport.has_value()); + ASSERT_EQ(viewport1, *receivedViewport); // Add the default display second to make sure order doesn't matter. mFakePolicy->clearViewports(); - mFakePolicy->addDisplayViewport(nonDefaultDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /*isActive=*/true, uniqueId2, NO_PORT, - ViewportType::INTERNAL); - mFakePolicy->addDisplayViewport(ui::LogicalDisplayId::DEFAULT, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /*isActive=*/true, uniqueId1, NO_PORT, - ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(viewport2); + mFakePolicy->addDisplayViewport(viewport1); - viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); - ASSERT_TRUE(viewport); - ASSERT_EQ(ui::LogicalDisplayId::DEFAULT, viewport->displayId); - ASSERT_EQ(ViewportType::INTERNAL, viewport->type); + receivedViewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); + ASSERT_TRUE(receivedViewport.has_value()); + ASSERT_EQ(viewport1, *receivedViewport); } /** @@ -568,28 +564,27 @@ TEST_F(InputReaderPolicyTest, Viewports_GetByPort) { mFakePolicy->clearViewports(); // Add a viewport that's associated with some display port that's not of interest. - mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, uniqueId1, hdmi3, type); + DisplayViewport viewport1 = + createViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, uniqueId1, hdmi3, type); + mFakePolicy->addDisplayViewport(viewport1); // Add another viewport, connected to HDMI1 port - mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, uniqueId2, hdmi1, type); - + DisplayViewport viewport2 = + createViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, uniqueId2, hdmi1, type); + mFakePolicy->addDisplayViewport(viewport2); // Check that correct display viewport was returned by comparing the display ports. std::optional<DisplayViewport> hdmi1Viewport = mFakePolicy->getDisplayViewportByPort(hdmi1); - ASSERT_TRUE(hdmi1Viewport); - ASSERT_EQ(displayId2, hdmi1Viewport->displayId); - ASSERT_EQ(uniqueId2, hdmi1Viewport->uniqueId); + ASSERT_TRUE(hdmi1Viewport.has_value()); + ASSERT_EQ(viewport2, *hdmi1Viewport); // Check that we can still get the same viewport using the uniqueId hdmi1Viewport = mFakePolicy->getDisplayViewportByUniqueId(uniqueId2); - ASSERT_TRUE(hdmi1Viewport); - ASSERT_EQ(displayId2, hdmi1Viewport->displayId); - ASSERT_EQ(uniqueId2, hdmi1Viewport->uniqueId); - ASSERT_EQ(type, hdmi1Viewport->type); + ASSERT_TRUE(hdmi1Viewport.has_value()); + ASSERT_EQ(viewport2, *hdmi1Viewport); // Check that we cannot find a port with "HDMI2", because we never added one - std::optional<DisplayViewport> hdmi2Viewport = mFakePolicy->getDisplayViewportByPort(hdmi2); - ASSERT_FALSE(hdmi2Viewport); + ASSERT_FALSE(mFakePolicy->getDisplayViewportByPort(hdmi2)); } // --- InputReaderTest --- @@ -1046,11 +1041,14 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { // Add default and second display. mFakePolicy->clearViewports(); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, "local:0", NO_PORT, ViewportType::INTERNAL); - mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /*isActive=*/true, "local:1", hdmi1, - ViewportType::EXTERNAL); + DisplayViewport internalViewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, "local:0", NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(internalViewport); + DisplayViewport externalViewport = + createViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, "local:1", hdmi1, ViewportType::EXTERNAL); + mFakePolicy->addDisplayViewport(externalViewport); mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::DISPLAY_INFO); mReader->loopOnce(); @@ -1653,7 +1651,7 @@ protected: mDevice = createUinputDevice<UinputTouchScreen>(Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); const auto info = waitForDevice(mDevice->getName()); - ASSERT_TRUE(info); + ASSERT_TRUE(info.has_value()); mDeviceInfo = *info; } @@ -1661,8 +1659,10 @@ protected: ui::Rotation orientation, const std::string& uniqueId, std::optional<uint8_t> physicalPort, ViewportType viewportType) { - mFakePolicy->addDisplayViewport(displayId, width, height, orientation, /*isActive=*/true, - uniqueId, physicalPort, viewportType); + DisplayViewport viewport = + createViewport(displayId, width, height, orientation, /*isActive=*/true, uniqueId, + physicalPort, viewportType); + mFakePolicy->addDisplayViewport(viewport); mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::DISPLAY_INFO); } @@ -1721,7 +1721,7 @@ protected: ViewportType::INTERNAL); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); const auto info = waitForDevice(mDevice->getName()); - ASSERT_TRUE(info); + ASSERT_TRUE(info.has_value()); mDeviceInfo = *info; } }; @@ -2053,7 +2053,7 @@ TEST_P(TouchIntegrationTest, ExternalStylusConnectedDuringTouchGesture) { auto externalStylus = createUinputDevice<UinputExternalStylus>(); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); const auto stylusInfo = waitForDevice(externalStylus->getName()); - ASSERT_TRUE(stylusInfo); + ASSERT_TRUE(stylusInfo.has_value()); // Move mDevice->sendMove(centerPoint + Point(2, 2)); @@ -2122,7 +2122,7 @@ private: mStylus = mStylusDeviceLifecycleTracker.get(); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); const auto info = waitForDevice(mStylus->getName()); - ASSERT_TRUE(info); + ASSERT_TRUE(info.has_value()); mStylusInfo = *info; } @@ -2395,7 +2395,7 @@ TEST_F(ExternalStylusIntegrationTest, ExternalStylusConnectionChangesTouchscreen // Connecting an external stylus changes the source of the touchscreen. const auto deviceInfo = waitForDevice(mDevice->getName()); - ASSERT_TRUE(deviceInfo); + ASSERT_TRUE(deviceInfo.has_value()); ASSERT_TRUE(isFromSource(deviceInfo->getSources(), STYLUS_FUSION_SOURCE)); } @@ -2408,7 +2408,7 @@ TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) { createUinputDevice<UinputExternalStylusWithPressure>(); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); const auto stylusInfo = waitForDevice(stylus->getName()); - ASSERT_TRUE(stylusInfo); + ASSERT_TRUE(stylusInfo.has_value()); ASSERT_EQ(AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_KEYBOARD, stylusInfo->getSources()); @@ -2453,7 +2453,7 @@ TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) { createUinputDevice<UinputExternalStylusWithPressure>(); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); const auto stylusInfo = waitForDevice(stylus->getName()); - ASSERT_TRUE(stylusInfo); + ASSERT_TRUE(stylusInfo.has_value()); ASSERT_EQ(AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_KEYBOARD, stylusInfo->getSources()); @@ -2880,9 +2880,10 @@ TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) { ASSERT_FALSE(mDevice->isEnabled()); // Prepare displays. - mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /*isActive=*/true, UNIQUE_ID, hdmi, - ViewportType::INTERNAL); + DisplayViewport viewport = + createViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, UNIQUE_ID, hdmi, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(viewport); unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::Change::DISPLAY_INFO); ASSERT_TRUE(mDevice->isEnabled()); @@ -2917,9 +2918,12 @@ TEST_F(InputDeviceTest, Configure_AssignsDisplayUniqueId) { ASSERT_FALSE(mDevice->isEnabled()); // Device should be enabled when a display is found. - mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID, - NO_PORT, ViewportType::INTERNAL); + + DisplayViewport secondViewport = + createViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /* isActive= */ true, DISPLAY_UNIQUE_ID, NO_PORT, + ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(secondViewport); unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::Change::DISPLAY_INFO); ASSERT_TRUE(mDevice->isEnabled()); @@ -2945,9 +2949,12 @@ TEST_F(InputDeviceTest, Configure_UniqueId_CorrectlyMatches) { /*changes=*/{}); mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID); - mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, - ui::ROTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID, - NO_PORT, ViewportType::INTERNAL); + + DisplayViewport secondViewport = + createViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /* isActive= */ true, DISPLAY_UNIQUE_ID, NO_PORT, + ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(secondViewport); const auto initialGeneration = mDevice->getGeneration(); unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::Change::DISPLAY_INFO); @@ -7594,8 +7601,10 @@ TEST_F(MultiTouchInputMapperTest, Process_SendsReadTime) { TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreDropped) { addConfigurationProperty("touch.deviceType", "touchScreen"); // Don't set touch.enableForInactiveViewport to verify the default behavior. - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/false, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + DisplayViewport viewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/false, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(viewport); configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); prepareAxes(POSITION); MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>(); @@ -7614,8 +7623,10 @@ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreDropped) { TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreProcessed) { addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.enableForInactiveViewport", "1"); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/false, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + DisplayViewport viewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/false, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(viewport); configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); prepareAxes(POSITION); MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>(); @@ -7636,8 +7647,10 @@ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreProcessed) { TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_AbortTouches) { addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.enableForInactiveViewport", "0"); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + DisplayViewport viewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(viewport); std::optional<DisplayViewport> optionalDisplayViewport = mFakePolicy->getDisplayViewportByUniqueId(UNIQUE_ID); ASSERT_TRUE(optionalDisplayViewport.has_value()); @@ -7692,12 +7705,10 @@ TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_AbortTouches) { TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_TouchesNotAborted) { addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.enableForInactiveViewport", "1"); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); - std::optional<DisplayViewport> optionalDisplayViewport = - mFakePolicy->getDisplayViewportByUniqueId(UNIQUE_ID); - ASSERT_TRUE(optionalDisplayViewport.has_value()); - DisplayViewport displayViewport = *optionalDisplayViewport; + DisplayViewport displayViewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(displayViewport); configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); prepareAxes(POSITION); diff --git a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp index 0ea22d4175..b7cb348236 100644 --- a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp +++ b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp @@ -109,9 +109,10 @@ protected: mockSlotValues({}); mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, "local:0", NO_PORT, - ViewportType::INTERNAL); + DisplayViewport internalViewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, "local:0", NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(internalViewport); mMapper = createInputMapper<MultiTouchInputMapper>(*mDeviceContext, mFakePolicy->getReaderConfiguration()); } diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp index 07891145bf..5f5aa63704 100644 --- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp +++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp @@ -124,9 +124,10 @@ protected: */ TEST_F(TouchpadInputMapperTest, HoverAndLeftButtonPress) { mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID); - mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, - /*isActive=*/true, "local:0", NO_PORT, ViewportType::INTERNAL); - + DisplayViewport viewport = + createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, "local:0", NO_PORT, ViewportType::INTERNAL); + mFakePolicy->addDisplayViewport(viewport); std::list<NotifyArgs> args; args += mMapper->reconfigure(systemTime(SYSTEM_TIME_MONOTONIC), mReaderConfiguration, |