diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-15 10:17:08 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-15 10:17:08 +0000 |
commit | d9b393d46ca9672359fd651c58d4d4bb6b289eea (patch) | |
tree | 294c1d0486e7c4444a8ae1349d0116db41a39559 | |
parent | 809fc17d906fa00f2b48e0fff41937994c4096ee (diff) | |
parent | ce8fbd20ed87349d96f6d4cb1da75227bce7275c (diff) |
Snap for 10323517 from ce8fbd20ed87349d96f6d4cb1da75227bce7275c to t-keystone-qcom-release
Change-Id: I1df2de1837335c1b5eb97a0d3c1488afa4e81565
-rw-r--r-- | cmds/atrace/atrace.rc | 6 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.cpp | 9 | ||||
-rw-r--r-- | libs/binder/tests/Android.bp | 5 | ||||
-rw-r--r-- | libs/gui/BLASTBufferQueue.cpp | 144 | ||||
-rw-r--r-- | libs/gui/Surface.cpp | 6 | ||||
-rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 5 | ||||
-rw-r--r-- | libs/gui/include/gui/BLASTBufferQueue.h | 8 | ||||
-rw-r--r-- | libs/gui/include/gui/Surface.h | 2 | ||||
-rw-r--r-- | libs/gui/include/gui/TraceUtils.h | 16 | ||||
-rw-r--r-- | libs/nativewindow/include/system/window.h | 5 | ||||
-rw-r--r-- | services/gpuservice/vts/OWNERS | 1 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 187 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 20 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 201 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.cpp | 4 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/RegionSamplingThread.cpp | 19 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp | 18 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp | 34 |
19 files changed, 455 insertions, 239 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 5267b0294c..d0b5d598c9 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -295,8 +295,12 @@ on late-init write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size" # allow creating event triggers - chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger + chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger + + # allow enabling rss_stat_throttled + chmod 0666 /sys/kernel/tracing/events/synthetic/rss_stat_throttled/enable + chmod 0666 /sys/kernel/debug/tracing/events/synthetic/rss_stat_throttled/enable # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 2b94b71a7f..ec1e89bce1 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -3172,6 +3172,15 @@ void Dumpstate::MaybeSnapshotWinTrace() { "", {"cmd", service, "tracing", "save-for-bugreport"}, CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); } + // Additionally, include the proto logging from WMShell. + RunCommand( + // Empty name because it's not intended to be classified as a bugreport section. + // Actual logging files can be found as "/data/misc/wmtrace/shell_log.winscope" + // in the bugreport. + "", {"dumpsys", "activity", "service", "SystemUIService", + "WMShell", "protolog", "save-for-bugreport"}, + CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); + } void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) { diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index a3533d831b..9ebeca0006 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -187,6 +187,11 @@ cc_library_static { cc_test { name: "binderRpcTest", + // b/269799024 + test_options: { + unit_test: false, + }, + host_supported: true, target: { darwin: { diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 9915f6a9ea..afd9d20e4f 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -548,20 +548,26 @@ void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId, mSyncedFrameNumbers.erase(callbackId.framenumber); } -void BLASTBufferQueue::acquireNextBufferLocked( +status_t BLASTBufferQueue::acquireNextBufferLocked( const std::optional<SurfaceComposerClient::Transaction*> transaction) { - // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't - // include the extra buffer when checking if we can acquire the next buffer. - const bool includeExtraAcquire = !transaction; - const bool maxAcquired = maxBuffersAcquired(includeExtraAcquire); - if (mNumFrameAvailable == 0 || maxAcquired) { - BQA_LOGV("Can't process next buffer maxBuffersAcquired=%s", boolToString(maxAcquired)); - return; + // Check if we have frames available and we have not acquired the maximum number of buffers. + // Even with this check, the consumer can fail to acquire an additional buffer if the consumer + // has already acquired (mMaxAcquiredBuffers + 1) and the new buffer is not droppable. In this + // case mBufferItemConsumer->acquireBuffer will return with NO_BUFFER_AVAILABLE. + if (mNumFrameAvailable == 0) { + BQA_LOGV("Can't acquire next buffer. No available frames"); + return BufferQueue::NO_BUFFER_AVAILABLE; + } + + if (mNumAcquired >= (mMaxAcquiredBuffers + 2)) { + BQA_LOGV("Can't acquire next buffer. Already acquired max frames %d max:%d + 2", + mNumAcquired, mMaxAcquiredBuffers); + return BufferQueue::NO_BUFFER_AVAILABLE; } if (mSurfaceControl == nullptr) { BQA_LOGE("ERROR : surface control is null"); - return; + return NAME_NOT_FOUND; } SurfaceComposerClient::Transaction localTransaction; @@ -578,10 +584,10 @@ void BLASTBufferQueue::acquireNextBufferLocked( mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false); if (status == BufferQueue::NO_BUFFER_AVAILABLE) { BQA_LOGV("Failed to acquire a buffer, err=NO_BUFFER_AVAILABLE"); - return; + return status; } else if (status != OK) { BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str()); - return; + return status; } auto buffer = bufferItem.mGraphicBuffer; @@ -591,7 +597,7 @@ void BLASTBufferQueue::acquireNextBufferLocked( if (buffer == nullptr) { mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); BQA_LOGE("Buffer was empty"); - return; + return BAD_VALUE; } if (rejectBuffer(bufferItem)) { @@ -600,8 +606,7 @@ void BLASTBufferQueue::acquireNextBufferLocked( mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform); mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); - acquireNextBufferLocked(transaction); - return; + return acquireNextBufferLocked(transaction); } mNumAcquired++; @@ -655,9 +660,23 @@ void BLASTBufferQueue::acquireNextBufferLocked( t->setDesiredPresentTime(bufferItem.mTimestamp); } - if (!mNextFrameTimelineInfoQueue.empty()) { - t->setFrameTimelineInfo(mNextFrameTimelineInfoQueue.front()); - mNextFrameTimelineInfoQueue.pop(); + // Drop stale frame timeline infos + while (!mPendingFrameTimelines.empty() && + mPendingFrameTimelines.front().first < bufferItem.mFrameNumber) { + ATRACE_FORMAT_INSTANT("dropping stale frameNumber: %" PRIu64 " vsyncId: %" PRId64, + mPendingFrameTimelines.front().first, + mPendingFrameTimelines.front().second.vsyncId); + mPendingFrameTimelines.pop(); + } + + if (!mPendingFrameTimelines.empty() && + mPendingFrameTimelines.front().first == bufferItem.mFrameNumber) { + ATRACE_FORMAT_INSTANT("Transaction::setFrameTimelineInfo frameNumber: %" PRIu64 + " vsyncId: %" PRId64, + bufferItem.mFrameNumber, + mPendingFrameTimelines.front().second.vsyncId); + t->setFrameTimelineInfo(mPendingFrameTimelines.front().second); + mPendingFrameTimelines.pop(); } { @@ -693,6 +712,7 @@ void BLASTBufferQueue::acquireNextBufferLocked( bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(), bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform); + return OK; } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { @@ -715,44 +735,19 @@ void BLASTBufferQueue::acquireAndReleaseBuffer() { mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence); } -void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) { - if (!mSyncedFrameNumbers.empty() && mNumFrameAvailable > 0) { - // We are waiting on a previous sync's transaction callback so allow another sync - // transaction to proceed. - // - // We need to first flush out the transactions that were in between the two syncs. - // We do this by merging them into mSyncTransaction so any buffer merging will get - // a release callback invoked. The release callback will be async so we need to wait - // on max acquired to make sure we have the capacity to acquire another buffer. - if (maxBuffersAcquired(false /* includeExtraAcquire */)) { - BQA_LOGD("waiting to flush shadow queue..."); - mCallbackCV.wait(lock); - } - while (mNumFrameAvailable > 0) { - // flush out the shadow queue - acquireAndReleaseBuffer(); - } - } - - while (maxBuffersAcquired(false /* includeExtraAcquire */)) { - BQA_LOGD("waiting for free buffer."); - mCallbackCV.wait(lock); - } -} - void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr; SurfaceComposerClient::Transaction* prevTransaction = nullptr; - bool waitForTransactionCallback = !mSyncedFrameNumbers.empty(); { - BBQ_TRACE(); std::unique_lock _lock{mMutex}; + BBQ_TRACE(); + + bool waitForTransactionCallback = !mSyncedFrameNumbers.empty(); const bool syncTransactionSet = mTransactionReadyCallback != nullptr; BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet)); if (syncTransactionSet) { - bool mayNeedToWaitForBuffer = true; // If we are going to re-use the same mSyncTransaction, release the buffer that may // already be set in the Transaction. This is to allow us a free slot early to continue // processing a new buffer. @@ -763,14 +758,29 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { bufferData->frameNumber); releaseBuffer(bufferData->generateReleaseCallbackId(), bufferData->acquireFence); - // Because we just released a buffer, we know there's no need to wait for a free - // buffer. - mayNeedToWaitForBuffer = false; } } - if (mayNeedToWaitForBuffer) { - flushAndWaitForFreeBuffer(_lock); + if (waitForTransactionCallback) { + // We are waiting on a previous sync's transaction callback so allow another sync + // transaction to proceed. + // + // We need to first flush out the transactions that were in between the two syncs. + // We do this by merging them into mSyncTransaction so any buffer merging will get + // a release callback invoked. + while (mNumFrameAvailable > 0) { + // flush out the shadow queue + acquireAndReleaseBuffer(); + } + } else { + // Make sure the frame available count is 0 before proceeding with a sync to ensure + // the correct frame is used for the sync. The only way mNumFrameAvailable would be + // greater than 0 is if we already ran out of buffers previously. This means we + // need to flush the buffers before proceeding with the sync. + while (mNumFrameAvailable > 0) { + BQA_LOGD("waiting until no queued buffers"); + mCallbackCV.wait(_lock); + } } } @@ -786,14 +796,23 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { item.mFrameNumber, boolToString(syncTransactionSet)); if (syncTransactionSet) { - acquireNextBufferLocked(mSyncTransaction); + // Add to mSyncedFrameNumbers before waiting in case any buffers are released + // while waiting for a free buffer. The release and commit callback will try to + // acquire buffers if there are any available, but we don't want it to acquire + // in the case where a sync transaction wants the buffer. + mSyncedFrameNumbers.emplace(item.mFrameNumber); + // If there's no available buffer and we're in a sync transaction, we need to wait + // instead of returning since we guarantee a buffer will be acquired for the sync. + while (acquireNextBufferLocked(mSyncTransaction) == BufferQueue::NO_BUFFER_AVAILABLE) { + BQA_LOGD("waiting for available buffer"); + mCallbackCV.wait(_lock); + } // Only need a commit callback when syncing to ensure the buffer that's synced has been // sent to SF incStrong((void*)transactionCommittedCallbackThunk); mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk, static_cast<void*>(this)); - mSyncedFrameNumbers.emplace(item.mFrameNumber); if (mAcquireSingleBuffer) { prevCallback = mTransactionReadyCallback; prevTransaction = mSyncTransaction; @@ -897,15 +916,6 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { return mSize != bufferSize; } -// Check if we have acquired the maximum number of buffers. -// Consumer can acquire an additional buffer if that buffer is not droppable. Set -// includeExtraAcquire is true to include this buffer to the count. Since this depends on the state -// of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. -bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { - int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1); - return mNumAcquired >= maxAcquiredBuffers; -} - class BBQSurface : public Surface { private: std::mutex mMutex; @@ -942,12 +952,13 @@ public: return mBbq->setFrameRate(frameRate, compatibility, changeFrameRateStrategy); } - status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { + status_t setFrameTimelineInfo(uint64_t frameNumber, + const FrameTimelineInfo& frameTimelineInfo) override { std::unique_lock _lock{mMutex}; if (mDestroyed) { return DEAD_OBJECT; } - return mBbq->setFrameTimelineInfo(frameTimelineInfo); + return mBbq->setFrameTimelineInfo(frameNumber, frameTimelineInfo); } void destroy() override { @@ -969,9 +980,12 @@ status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility, return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply(); } -status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { +status_t BLASTBufferQueue::setFrameTimelineInfo(uint64_t frameNumber, + const FrameTimelineInfo& frameTimelineInfo) { + ATRACE_FORMAT("%s(%s) frameNumber: %" PRIu64 " vsyncId: %" PRId64, __func__, mName.c_str(), + frameNumber, frameTimelineInfo.vsyncId); std::unique_lock _lock{mMutex}; - mNextFrameTimelineInfoQueue.push(frameTimelineInfo); + mPendingFrameTimelines.push({frameNumber, frameTimelineInfo}); return OK; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 5b16e7bb08..78807e4ed6 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1881,12 +1881,13 @@ int Surface::dispatchGetLastQueuedBuffer2(va_list args) { int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); + auto frameNumber = static_cast<uint64_t>(va_arg(args, uint64_t)); auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t)); auto inputEventId = static_cast<int32_t>(va_arg(args, int32_t)); auto startTimeNanos = static_cast<int64_t>(va_arg(args, int64_t)); ALOGV("Surface::%s", __func__); - return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId, startTimeNanos}); + return setFrameTimelineInfo(frameNumber, {frameTimelineVsyncId, inputEventId, startTimeNanos}); } bool Surface::transformToDisplayInverse() const { @@ -2656,7 +2657,8 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility, changeFrameRateStrategy); } -status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { +status_t Surface::setFrameTimelineInfo(uint64_t /*frameNumber*/, + const FrameTimelineInfo& frameTimelineInfo) { return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8a54082113..01a8949751 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1274,8 +1274,11 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha mStatus = BAD_INDEX; return *this; } + if (alpha < 0.0f || alpha > 1.0f) { + ALOGE("SurfaceComposerClient::Transaction::setAlpha: invalid alpha %f, clamping", alpha); + } s->what |= layer_state_t::eAlphaChanged; - s->alpha = alpha; + s->alpha = std::clamp(alpha, 0.f, 1.f); registerSurfaceControlForCallback(sc); return *this; diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 91bf51ef58..0adfc86a4c 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -116,7 +116,7 @@ public: void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format); status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); - status_t setFrameTimelineInfo(const FrameTimelineInfo& info); + status_t setFrameTimelineInfo(uint64_t frameNumber, const FrameTimelineInfo& info); void setSidebandStream(const sp<NativeHandle>& stream); @@ -143,12 +143,11 @@ private: void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer); - void acquireNextBufferLocked( + status_t acquireNextBufferLocked( const std::optional<SurfaceComposerClient::Transaction*> transaction) REQUIRES(mMutex); Rect computeCrop(const BufferItem& item) REQUIRES(mMutex); // Return true if we need to reject the buffer based on the scaling mode and the buffer size. bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex); - bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex); static PixelFormat convertBufferFormat(PixelFormat& format); void mergePendingTransactions(SurfaceComposerClient::Transaction* t, uint64_t frameNumber) REQUIRES(mMutex); @@ -157,7 +156,6 @@ private: void acquireAndReleaseBuffer() REQUIRES(mMutex); void releaseBuffer(const ReleaseCallbackId& callbackId, const sp<Fence>& releaseFence) REQUIRES(mMutex); - void flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock); std::string mName; // Represents the queued buffer count from buffer queue, @@ -247,7 +245,7 @@ private: std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>> mPendingTransactions GUARDED_BY(mMutex); - std::queue<FrameTimelineInfo> mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); + std::queue<std::pair<uint64_t, FrameTimelineInfo>> mPendingFrameTimelines GUARDED_BY(mMutex); // Tracks the last acquired frame number uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index ab9ebaa882..8d4e15bb40 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -193,7 +193,7 @@ public: virtual status_t setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy); - virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); + virtual status_t setFrameTimelineInfo(uint64_t frameNumber, const FrameTimelineInfo& info); protected: virtual ~Surface(); diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h index e5d268445c..00096158e7 100644 --- a/libs/gui/include/gui/TraceUtils.h +++ b/libs/gui/include/gui/TraceUtils.h @@ -27,6 +27,8 @@ #define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__) +#define ATRACE_FORMAT_INSTANT(fmt, ...) TraceUtils::intantFormat(fmt, ##__VA_ARGS__) + namespace android { class TraceUtils { @@ -50,6 +52,20 @@ public: ATRACE_BEGIN(buf); } + static void intantFormat(const char* fmt, ...) { + if (CC_LIKELY(!ATRACE_ENABLED())) return; + + const int BUFFER_SIZE = 256; + va_list ap; + char buf[BUFFER_SIZE]; + + va_start(ap, fmt); + vsnprintf(buf, BUFFER_SIZE, fmt, ap); + va_end(ap); + + ATRACE_INSTANT(buf); + } + }; // class TraceUtils } /* namespace android */ diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index a54af1fa62..86e76c4f2c 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1043,11 +1043,12 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo } static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window, + uint64_t frameNumber, int64_t frameTimelineVsyncId, int32_t inputEventId, int64_t startTimeNanos) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameTimelineVsyncId, - inputEventId, startTimeNanos); + return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameNumber, + frameTimelineVsyncId, inputEventId, startTimeNanos); } // ------------------------------------------------------------------------------------------------ diff --git a/services/gpuservice/vts/OWNERS b/services/gpuservice/vts/OWNERS index e789052fa3..a63de1c306 100644 --- a/services/gpuservice/vts/OWNERS +++ b/services/gpuservice/vts/OWNERS @@ -1,4 +1,5 @@ # Bug component: 653544 +kocdemir@google.com paulthomson@google.com pbaiget@google.com lfy@google.com diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 5c47be9be0..c6dd6217d3 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -27,6 +27,7 @@ #include <ftl/enum.h> #include <gui/SurfaceComposerClient.h> #include <input/InputDevice.h> +#include <openssl/mem.h> #include <powermanager/PowerManager.h> #include <unistd.h> #include <utils/Trace.h> @@ -2196,8 +2197,31 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Update the temporary touch state. BitSet32 pointerIds; pointerIds.markBit(entry.pointerProperties[pointerIndex].id); - tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds); + + // If this is the pointer going down and the touched window has a wallpaper + // then also add the touched wallpaper windows so they are locked in for the duration + // of the touch gesture. + // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper + // engine only supports touch events. We would need to add a mechanism similar + // to View.onGenericMotionEvent to enable wallpapers to handle these events. + if (maskedAction == AMOTION_EVENT_ACTION_DOWN || + maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { + if ((targetFlags & InputTarget::FLAG_FOREGROUND) && + windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { + sp<WindowInfoHandle> wallpaper = findWallpaperWindowBelow(windowHandle); + if (wallpaper != nullptr) { + int32_t wallpaperFlags = InputTarget::FLAG_WINDOW_IS_OBSCURED | + InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED | + InputTarget::FLAG_DISPATCH_AS_IS; + if (isSplit) { + wallpaperFlags |= InputTarget::FLAG_SPLIT; + } + tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, pointerIds); + } + } + } } } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ @@ -2274,6 +2298,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( BitSet32 pointerIds; pointerIds.markBit(entry.pointerProperties[0].id); tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); + + // Check if the wallpaper window should deliver the corresponding event. + slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, + tempTouchState, pointerIds); } } @@ -2379,39 +2407,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } - // If this is the first pointer going down and the touched window has a wallpaper - // then also add the touched wallpaper windows so they are locked in for the duration - // of the touch gesture. - // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper - // engine only supports touch events. We would need to add a mechanism similar - // to View.onGenericMotionEvent to enable wallpapers to handle these events. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp<WindowInfoHandle> foregroundWindowHandle = - tempTouchState.getFirstForegroundWindowHandle(); - if (foregroundWindowHandle && - foregroundWindowHandle->getInfo()->inputConfig.test( - WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { - const std::vector<sp<WindowInfoHandle>>& windowHandles = - getWindowHandlesLocked(displayId); - for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { - const WindowInfo* info = windowHandle->getInfo(); - if (info->displayId == displayId && - windowHandle->getInfo()->inputConfig.test( - WindowInfo::InputConfig::IS_WALLPAPER)) { - BitSet32 pointerIds; - pointerIds.markBit(entry.pointerProperties[0].id); - tempTouchState - .addOrUpdateWindow(windowHandle, - InputTarget::FLAG_WINDOW_IS_OBSCURED | - InputTarget:: - FLAG_WINDOW_IS_PARTIALLY_OBSCURED | - InputTarget::FLAG_DISPATCH_AS_IS, - pointerIds); - } - } - } - } - // Success! Output targets. injectionResult = InputEventInjectionResult::SUCCEEDED; @@ -3685,7 +3680,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( - const sp<Connection>& connection) { + const sp<Connection>& connection, int32_t targetFlags) { if (connection->status == Connection::Status::BROKEN) { return; } @@ -3713,7 +3708,7 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( target.globalScaleFactor = windowInfo->globalScaleFactor; } target.inputChannel = connection->inputChannel; - target.flags = InputTarget::FLAG_DISPATCH_AS_IS; + target.flags = targetFlags; for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) { switch (downEventEntry->type) { @@ -3744,6 +3739,16 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( startDispatchCycleLocked(currentTime, connection); } +void InputDispatcher::synthesizeCancelationEventsForWindowLocked( + const sp<WindowInfoHandle>& windowHandle, const CancelationOptions& options) { + if (windowHandle != nullptr) { + sp<Connection> wallpaperConnection = getConnectionLocked(windowHandle->getToken()); + if (wallpaperConnection != nullptr) { + synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, options); + } + } +} + std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( const MotionEntry& originalMotionEntry, BitSet32 pointerIds) { ALOG_ASSERT(pointerIds.value != 0); @@ -4429,7 +4434,7 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu if (calculatedHmac == INVALID_HMAC) { return nullptr; } - if (calculatedHmac != event.getHmac()) { + if (0 != CRYPTO_memcmp(calculatedHmac.data(), event.getHmac().data(), calculatedHmac.size())) { return nullptr; } return result; @@ -4762,14 +4767,7 @@ void InputDispatcher::setInputWindowsLocked( touchedWindow.windowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow(); - if (wallpaper != nullptr) { - sp<Connection> wallpaperConnection = - getConnectionLocked(wallpaper->getToken()); - if (wallpaperConnection != nullptr) { - synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, - options); - } - } + synthesizeCancelationEventsForWindowLocked(wallpaper, options); } } state.windows.erase(state.windows.begin() + i); @@ -5082,6 +5080,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< // Erase old window. int32_t oldTargetFlags = touchedWindow->targetFlags; BitSet32 pointerIds = touchedWindow->pointerIds; + sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle; state->removeWindowByToken(fromToken); // Add new window. @@ -5113,7 +5112,10 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< options(CancelationOptions::CANCEL_POINTER_EVENTS, "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); - synthesizePointerDownEventsForConnectionLocked(toConnection); + synthesizePointerDownEventsForConnectionLocked(toConnection, newTargetFlags); + // Check if the wallpaper window should deliver the corresponding event. + transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle, + *state, pointerIds); } if (DEBUG_FOCUS) { @@ -6398,4 +6400,97 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon mMonitorDispatchingTimeout = timeout; } +void InputDispatcher::slipWallpaperTouch(int32_t targetFlags, + const sp<WindowInfoHandle>& oldWindowHandle, + const sp<WindowInfoHandle>& newWindowHandle, + TouchState& state, const BitSet32& pointerIds) { + const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); + const bool newHasWallpaper = (targetFlags & InputTarget::FLAG_FOREGROUND) && + newWindowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); + const sp<WindowInfoHandle> oldWallpaper = + oldHasWallpaper ? state.getWallpaperWindow() : nullptr; + const sp<WindowInfoHandle> newWallpaper = + newHasWallpaper ? findWallpaperWindowBelow(newWindowHandle) : nullptr; + if (oldWallpaper == newWallpaper) { + return; + } + + if (oldWallpaper != nullptr) { + state.addOrUpdateWindow(oldWallpaper, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, + BitSet32(0)); + } + + if (newWallpaper != nullptr) { + state.addOrUpdateWindow(newWallpaper, + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER | + InputTarget::FLAG_WINDOW_IS_OBSCURED | + InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED, + pointerIds); + } +} + +void InputDispatcher::transferWallpaperTouch(int32_t oldTargetFlags, int32_t newTargetFlags, + const sp<WindowInfoHandle> fromWindowHandle, + const sp<WindowInfoHandle> toWindowHandle, + TouchState& state, const BitSet32& pointerIds) { + const bool oldHasWallpaper = (oldTargetFlags & InputTarget::FLAG_FOREGROUND) && + fromWindowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); + const bool newHasWallpaper = (newTargetFlags & InputTarget::FLAG_FOREGROUND) && + toWindowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); + + const sp<WindowInfoHandle> oldWallpaper = + oldHasWallpaper ? state.getWallpaperWindow() : nullptr; + const sp<WindowInfoHandle> newWallpaper = + newHasWallpaper ? findWallpaperWindowBelow(toWindowHandle) : nullptr; + if (oldWallpaper == newWallpaper) { + return; + } + + if (oldWallpaper != nullptr) { + CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + "transferring touch focus to another window"); + state.removeWindowByToken(oldWallpaper->getToken()); + synthesizeCancelationEventsForWindowLocked(oldWallpaper, options); + } + + if (newWallpaper != nullptr) { + int32_t wallpaperFlags = + oldTargetFlags & (InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); + wallpaperFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED | + InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + state.addOrUpdateWindow(newWallpaper, wallpaperFlags, pointerIds); + sp<Connection> wallpaperConnection = getConnectionLocked(newWallpaper->getToken()); + if (wallpaperConnection != nullptr) { + sp<Connection> toConnection = getConnectionLocked(toWindowHandle->getToken()); + toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState); + synthesizePointerDownEventsForConnectionLocked(wallpaperConnection, wallpaperFlags); + } + } +} + +sp<WindowInfoHandle> InputDispatcher::findWallpaperWindowBelow( + const sp<WindowInfoHandle>& windowHandle) const { + const std::vector<sp<WindowInfoHandle>>& windowHandles = + getWindowHandlesLocked(windowHandle->getInfo()->displayId); + bool foundWindow = false; + for (const sp<WindowInfoHandle>& otherHandle : windowHandles) { + if (!foundWindow && otherHandle != windowHandle) { + continue; + } + if (windowHandle == otherHandle) { + foundWindow = true; + continue; + } + + if (otherHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::IS_WALLPAPER)) { + return otherHandle; + } + } + return nullptr; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index ed89ed0b0f..0df589480d 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -621,8 +621,12 @@ private: const CancelationOptions& options) REQUIRES(mLock); - void synthesizePointerDownEventsForConnectionLocked(const sp<Connection>& connection) - REQUIRES(mLock); + void synthesizePointerDownEventsForConnectionLocked(const sp<Connection>& connection, + int32_t targetFlags) REQUIRES(mLock); + + void synthesizeCancelationEventsForWindowLocked( + const sp<android::gui::WindowInfoHandle>& windowHandle, + const CancelationOptions& options) REQUIRES(mLock); // Splitting motion events across windows. std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry, @@ -684,6 +688,18 @@ private: bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock); sp<InputReporterInterface> mReporter; + + void slipWallpaperTouch(int32_t targetFlags, + const sp<android::gui::WindowInfoHandle>& oldWindowHandle, + const sp<android::gui::WindowInfoHandle>& newWindowHandle, + TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock); + void transferWallpaperTouch(int32_t oldTargetFlags, int32_t newTargetFlags, + const sp<android::gui::WindowInfoHandle> fromWindowHandle, + const sp<android::gui::WindowInfoHandle> toWindowHandle, + TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock); + + sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow( + const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock); }; } // namespace android::inputdispatcher diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 49caefa5bb..51cb1bd082 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -58,6 +58,8 @@ static constexpr int32_t POINTER_1_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_2_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr int32_t POINTER_0_UP = + AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_1_UP = AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); @@ -73,6 +75,9 @@ static constexpr int32_t MONITOR_PID = 2001; static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; +static constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + struct PointF { float x; float y; @@ -1673,8 +1678,6 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance sp<FakeWindowHandle> wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1717,8 +1720,6 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { sp<FakeWindowHandle> wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1748,24 +1749,27 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { foregroundWindow->consumeMotionCancel(); } +class ShouldSplitTouchFixture : public InputDispatcherTest, + public ::testing::WithParamInterface<bool> {}; +INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture, + ::testing::Values(true, false)); /** * A single window that receives touch (on top), and a wallpaper window underneath it. * The top window gets a multitouch gesture. * Ensure that wallpaper gets the same gesture. */ -TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { +TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - window->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> foregroundWindow = + new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + foregroundWindow->setDupTouchToWallpaper(true); + foregroundWindow->setPreventSplitting(GetParam()); sp<FakeWindowHandle> wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); // Touch down on top window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1774,7 +1778,7 @@ TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Both top window and its wallpaper should receive the touch down - window->consumeMotionDown(); + foregroundWindow->consumeMotionDown(); wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Second finger down on the top window @@ -1793,11 +1797,34 @@ TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionPointerDown(1 /* pointerIndex */); + foregroundWindow->consumeMotionPointerDown(1 /* pointerIndex */); wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); - window->assertNoEvents(); - wallpaperWindow->assertNoEvents(); + + const MotionEvent secondFingerUpEvent = + MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + foregroundWindow->consumeMotionPointerUp(0); + wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 100})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); + wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); } /** @@ -1824,8 +1851,6 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; mDispatcher->setInputWindows( {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}}); @@ -1890,62 +1915,49 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { wallpaperWindow->assertNoEvents(); } -TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) { +/** + * Two windows: a window on the left with dup touch to wallpaper and window on the right without it. + * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL + * The right window should receive ACTION_DOWN. + */ +TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - window->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> leftWindow = + new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 200, 200)); + leftWindow->setDupTouchToWallpaper(true); + leftWindow->setSlippery(true); + + sp<FakeWindowHandle> rightWindow = + new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + rightWindow->setFrame(Rect(200, 0, 400, 200)); sp<FakeWindowHandle> wallpaperWindow = - sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; - wallpaperWindow->setPreventSplitting(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}}); + // Touch down on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {50, 50})) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionDown(ADISPLAY_ID_DEFAULT); - wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); - - const MotionEvent secondFingerDownEvent = - MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .displayId(ADISPLAY_ID_DEFAULT) - .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) - .build(); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, - InputEventInjectionSync::WAIT_FOR_RESULT)) + {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionPointerDown(1); - wallpaperWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + // Both foreground window and its wallpaper should receive the touch down + leftWindow->consumeMotionDown(); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); - const MotionEvent secondFingerUpEvent = - MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) - .displayId(ADISPLAY_ID_DEFAULT) - .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) - .build(); + // Move to right window, the left window should receive cancel. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, - InputEventInjectionSync::WAIT_FOR_RESULT)) + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {201, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionPointerUp(1); - wallpaperWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionUp(ADISPLAY_ID_DEFAULT); - wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + leftWindow->consumeMotionCancel(); + rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); } /** @@ -2570,20 +2582,26 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { // Create a couple of windows sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + firstWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); - + sp<FakeWindowHandle> wallpaper = + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaper->setIsWallpaper(true); // Add the windows to the dispatcher - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow, wallpaper}}}); // Send down to the first window NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&downMotionArgs); + // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); + wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Transfer touch to the second window TransferFunction f = GetParam(); @@ -2592,6 +2610,7 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { // The first window gets cancel and the second gets down firstWindow->consumeMotionCancel(); secondWindow->consumeMotionDown(); + wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Send up event to the second window NotifyMotionArgs upMotionArgs = @@ -2601,6 +2620,7 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { // The first window gets no events and the second gets up firstWindow->assertNoEvents(); secondWindow->consumeMotionUp(); + wallpaper->assertNoEvents(); } /** @@ -2722,6 +2742,65 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { secondWindow->consumeMotionUp(); } +TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + + // Create a couple of windows + sp<FakeWindowHandle> firstWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", + ADISPLAY_ID_DEFAULT); + firstWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> secondWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); + secondWindow->setDupTouchToWallpaper(true); + + sp<FakeWindowHandle> wallpaper1 = + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT); + wallpaper1->setIsWallpaper(true); + + sp<FakeWindowHandle> wallpaper2 = + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT); + wallpaper2->setIsWallpaper(true); + // Add the windows to the dispatcher + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {firstWindow, wallpaper1, secondWindow, wallpaper2}}}); + + // Send down to the first window + NotifyMotionArgs downMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&downMotionArgs); + + // Only the first window should get the down event + firstWindow->consumeMotionDown(); + secondWindow->assertNoEvents(); + wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaper2->assertNoEvents(); + + // Transfer touch focus to the second window + TransferFunction f = GetParam(); + bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken()); + ASSERT_TRUE(success); + + // The first window gets cancel and the second gets down + firstWindow->consumeMotionCancel(); + secondWindow->consumeMotionDown(); + wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Send up event to the second window + NotifyMotionArgs upMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&upMotionArgs); + // The first window gets no events and the second gets up + firstWindow->assertNoEvents(); + secondWindow->consumeMotionUp(); + wallpaper1->assertNoEvents(); + wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); +} + // For the cases of single pointer touch and two pointers non-split touch, the api's // 'transferTouch' and 'transferTouchFocus' are equivalent in behaviour. They only differ // for the case where there are multiple pointers split across several windows. diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index e08e61118f..957f38e4a6 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -175,7 +175,7 @@ auto DisplayDevice::getInputInfo() const -> InputInfo { void DisplayDevice::setPowerMode(hal::PowerMode mode) { if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) { - if (mStagedBrightness && mBrightness != *mStagedBrightness) { + if (mStagedBrightness && mBrightness != mStagedBrightness) { getCompositionDisplay()->setNextBrightness(*mStagedBrightness); mBrightness = *mStagedBrightness; } @@ -366,7 +366,7 @@ void DisplayDevice::stageBrightness(float brightness) { } void DisplayDevice::persistBrightness(bool needsComposite) { - if (mStagedBrightness && mBrightness != *mStagedBrightness) { + if (mStagedBrightness && mBrightness != mStagedBrightness) { if (needsComposite) { getCompositionDisplay()->setNextBrightness(*mStagedBrightness); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index c11a896953..3ed26a73c4 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -288,8 +288,8 @@ private: // allow initial power mode as null. std::optional<hardware::graphics::composer::hal::PowerMode> mPowerMode; DisplayModePtr mActiveMode; - std::optional<float> mStagedBrightness = std::nullopt; - float mBrightness = -1.f; + std::optional<float> mStagedBrightness; + std::optional<float> mBrightness; const DisplayModes mSupportedModes; std::atomic<nsecs_t> mLastHwVsync = 0; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 2487dbd793..e126931e6c 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -203,25 +203,14 @@ float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t st return 0.0f; } - // (b/133849373) ROT_90 screencap images produced upside down - auto area = sample_area; - if (orientation & ui::Transform::ROT_90) { - area.top = height - area.top; - area.bottom = height - area.bottom; - std::swap(area.top, area.bottom); - - area.left = width - area.left; - area.right = width - area.right; - std::swap(area.left, area.right); - } - - const uint32_t pixelCount = (area.bottom - area.top) * (area.right - area.left); + const uint32_t pixelCount = + (sample_area.bottom - sample_area.top) * (sample_area.right - sample_area.left); uint32_t accumulatedLuma = 0; // Calculates luma with approximation of Rec. 709 primaries - for (int32_t row = area.top; row < area.bottom; ++row) { + for (int32_t row = sample_area.top; row < sample_area.bottom; ++row) { const uint32_t* rowBase = data + row * stride; - for (int32_t column = area.left; column < area.right; ++column) { + for (int32_t column = sample_area.left; column < sample_area.right; ++column) { uint32_t pixel = rowBase[column]; const uint32_t r = pixel & 0xFF; const uint32_t g = (pixel >> 8) & 0xFF; diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp index 225ad163d9..ac5e9274bb 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp @@ -96,5 +96,23 @@ TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircu EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness); } +TEST_F(SetDisplayBrightnessTest, firstDisplayBrightnessWithComposite) { + ftl::FakeGuard guard(kMainThreadContext); + sp<DisplayDevice> displayDevice = getDisplayDevice(); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + + constexpr float kDisplayBrightness = -1.0f; + displayDevice->stageBrightness(kDisplayBrightness); + + EXPECT_EQ(-1.0f, displayDevice->getStagedBrightness()); + + displayDevice->persistBrightness(true); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(kDisplayBrightness, + displayDevice->getCompositionDisplay()->getState().displayBrightness); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp index f19e55409c..409e1ef5d7 100644 --- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp +++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp @@ -106,40 +106,6 @@ TEST_F(RegionSamplingTest, bounds_checking) { testing::Eq(0.0)); } -// workaround for b/133849373 -TEST_F(RegionSamplingTest, orientation_90) { - std::generate(buffer.begin(), buffer.end(), - [n = 0]() mutable { return (n++ > (kStride * kHeight >> 1)) ? kBlack : kWhite; }); - - Rect tl_region{0, 0, 4, 4}; - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_0, - tl_region), - testing::Eq(1.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_180, - tl_region), - testing::Eq(1.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_90, - tl_region), - testing::Eq(0.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_270, - tl_region), - testing::Eq(0.0)); - - Rect br_region{kWidth - 4, kHeight - 4, kWidth, kHeight}; - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_0, - br_region), - testing::Eq(0.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_180, - br_region), - testing::Eq(0.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_90, - br_region), - testing::Eq(1.0)); - EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_270, - br_region), - testing::Eq(1.0)); -} - } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues |