Merge "Use the correct dataspace in shaders.cpp" into tm-dev
diff --git a/include/input/Input.h b/include/input/Input.h
index b23a951..e7d68fc 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -837,6 +837,8 @@
     std::vector<PointerCoords> mSamplePointerCoords;
 };
 
+std::ostream& operator<<(std::ostream& out, const MotionEvent& event);
+
 /*
  * Focus events.
  */
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index fe1754c..13ca9ec 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -22,7 +22,9 @@
 #include <inttypes.h>
 #include <string.h>
 
+#include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <cutils/compiler.h>
 #include <gui/constants.h>
 #include <input/DisplayViewport.h>
 #include <input/Input.h>
@@ -542,7 +544,14 @@
 }
 
 const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
-    return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
+    if (CC_UNLIKELY(pointerIndex < 0 || pointerIndex >= getPointerCount())) {
+        LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for " << *this;
+    }
+    const size_t position = getHistorySize() * getPointerCount() + pointerIndex;
+    if (CC_UNLIKELY(position < 0 || position >= mSamplePointerCoords.size())) {
+        LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << *this;
+    }
+    return &mSamplePointerCoords[position];
 }
 
 float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
@@ -555,7 +564,18 @@
 
 const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
         size_t pointerIndex, size_t historicalIndex) const {
-    return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
+    if (CC_UNLIKELY(pointerIndex < 0 || pointerIndex >= getPointerCount())) {
+        LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for " << *this;
+    }
+    if (CC_UNLIKELY(historicalIndex < 0 || historicalIndex > getHistorySize())) {
+        LOG(FATAL) << __func__ << ": Invalid historical index " << historicalIndex << " for "
+                   << *this;
+    }
+    const size_t position = historicalIndex * getPointerCount() + pointerIndex;
+    if (CC_UNLIKELY(position < 0 || position >= mSamplePointerCoords.size())) {
+        LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << *this;
+    }
+    return &mSamplePointerCoords[position];
 }
 
 float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
@@ -903,6 +923,53 @@
     return out;
 }
 
+std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
+    out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction());
+    if (event.getActionButton() != 0) {
+        out << ", actionButton=" << std::to_string(event.getActionButton());
+    }
+    const size_t pointerCount = event.getPointerCount();
+    for (size_t i = 0; i < pointerCount; i++) {
+        out << ", id[" << i << "]=" << event.getPointerId(i);
+        float x = event.getX(i);
+        float y = event.getY(i);
+        if (x != 0 || y != 0) {
+            out << ", x[" << i << "]=" << x;
+            out << ", y[" << i << "]=" << y;
+        }
+        int toolType = event.getToolType(i);
+        if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) {
+            out << ", toolType[" << i << "]=" << toolType;
+        }
+    }
+    if (event.getButtonState() != 0) {
+        out << ", buttonState=" << event.getButtonState();
+    }
+    if (event.getClassification() != MotionClassification::NONE) {
+        out << ", classification=" << motionClassificationToString(event.getClassification());
+    }
+    if (event.getMetaState() != 0) {
+        out << ", metaState=" << event.getMetaState();
+    }
+    if (event.getEdgeFlags() != 0) {
+        out << ", edgeFlags=" << event.getEdgeFlags();
+    }
+    if (pointerCount != 1) {
+        out << ", pointerCount=" << pointerCount;
+    }
+    if (event.getHistorySize() != 0) {
+        out << ", historySize=" << event.getHistorySize();
+    }
+    out << ", eventTime=" << event.getEventTime();
+    out << ", downTime=" << event.getDownTime();
+    out << ", deviceId=" << event.getDeviceId();
+    out << ", source=" << inputEventSourceToString(event.getSource());
+    out << ", displayId=" << event.getDisplayId();
+    out << ", eventId=" << event.getId();
+    out << "}";
+    return out;
+}
+
 // --- FocusEvent ---
 
 void FocusEvent::initialize(int32_t id, bool hasFocus) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4d25c59..5e9427a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2507,7 +2507,7 @@
 }
 
 void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
-    if (!mDragState) {
+    if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId) {
         return;
     }
 
@@ -4765,9 +4765,11 @@
 
         // If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We
         // could just clear the state here.
-        if (mDragState &&
+        if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId &&
             std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) ==
                     windowHandles.end()) {
+            ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str());
+            sendDropWindowCommandLocked(nullptr, 0, 0);
             mDragState.reset();
         }
     }
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 91a666c..df43071 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -6407,6 +6407,58 @@
     mSecondWindow->consumeMotionMove();
 }
 
+TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
+    performDrag();
+
+    // Update window of second display.
+    sp<FakeWindowHandle> windowInSecondary =
+            new FakeWindowHandle(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
+    mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
+
+    // Let second display has a touch state.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher,
+                                MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
+                                                   AINPUT_SOURCE_TOUCHSCREEN)
+                                        .displayId(SECOND_DISPLAY_ID)
+                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+                                                         .x(100)
+                                                         .y(100))
+                                        .build()));
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN,
+                                    SECOND_DISPLAY_ID, 0 /* expectedFlag */);
+    // Update window again.
+    mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
+
+    // Move on window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT, {50, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+    mWindow->consumeDragEvent(false, 50, 50);
+    mSecondWindow->assertNoEvents();
+
+    // Move to another window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT, {150, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+    mWindow->consumeDragEvent(true, 150, 50);
+    mSecondWindow->consumeDragEvent(false, 50, 50);
+
+    // drop to another window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                             {150, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+    mFakePolicy->assertDropTargetEquals(mSecondWindow->getToken());
+    mWindow->assertNoEvents();
+    mSecondWindow->assertNoEvents();
+}
+
 class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
 
 TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f8c53c3..d9c89cd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -358,8 +358,6 @@
     // composition.
     if (!mBufferInfo.mFrameLatencyNeeded) return;
 
-    mAlreadyDisplayedThisCompose = false;
-
     // Update mFrameEventHistory.
     finalizeFrameEventHistory(glDoneFence, compositorTiming);
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1a5b925..fecf5ae 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -79,10 +79,10 @@
     //  For example we can only use it if all the displays are client comp, and we need
     //  to merge all the client comp fences. We could do this, but for now we just
     // disable the optimization when a layer is composed on multiple displays.
-    if (mAlreadyDisplayedThisCompose) {
+    if (mClearClientCompositionFenceOnLayerDisplayed) {
         mLastClientCompositionFence = nullptr;
     } else {
-        mAlreadyDisplayedThisCompose = true;
+        mClearClientCompositionFenceOnLayerDisplayed = true;
     }
 
     // The previous release fence notifies the client that SurfaceFlinger is done with the previous
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2e7a377..e65aa73 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -147,6 +147,8 @@
 
     bool hasProtectedLayers() const;
 
+    bool hasSolidColorLayers() const;
+
 private:
     CachedSet() = default;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 29d3366..5aec7c2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -248,6 +248,12 @@
     bool isProtected() const {
         return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
     }
+
+    bool hasSolidColorCompositionType() const {
+        return getOutputLayer()->getLayerFE().getCompositionState()->compositionType ==
+                aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
+    }
+
     float getFps() const { return getOutputLayer()->getLayerFE().getCompositionState()->fps; }
 
     void dump(std::string& result) const;
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index aac478d..c3385a8 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1300,6 +1300,7 @@
         const auto& layerState = layer->getState();
         const auto* layerFEState = layer->getLayerFE().getCompositionState();
         auto& layerFE = layer->getLayerFE();
+        layerFE.setWasClientComposed(nullptr);
 
         const Region clip(viewportRegion.intersect(layerState.visibleRegion));
         ALOGV("Layer: %s", layerFE.getDebugName());
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 742af58..1bb9d0eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -377,6 +377,7 @@
     auto requestedCompositionType = outputIndependentState->compositionType;
 
     if (requestedCompositionType == Composition::SOLID_COLOR && state.overrideInfo.buffer) {
+        // this should never happen, as SOLID_COLOR is skipped from caching, b/230073351
         requestedCompositionType = Composition::DEVICE;
     }
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index d15b0a7..641b806 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -388,6 +388,12 @@
                        [](const Layer& layer) { return layer.getState()->isProtected(); });
 }
 
+bool CachedSet::hasSolidColorLayers() const {
+    return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
+        return layer.getState()->hasSolidColorCompositionType();
+    });
+}
+
 void CachedSet::dump(std::string& result) const {
     const auto now = std::chrono::steady_clock::now();
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 250f648..1062b70 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -498,6 +498,13 @@
         }
     }
 
+    for (const CachedSet& layer : mLayers) {
+        if (layer.hasSolidColorLayers()) {
+            ATRACE_NAME("layer->hasSolidColorLayers()");
+            return;
+        }
+    }
+
     std::vector<Run> runs = findCandidateRuns(now);
 
     std::optional<Run> bestRun = findBestRun(runs);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3988e51..24abad9 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -620,6 +620,7 @@
 
     void setWasClientComposed(const sp<Fence>& fence) override {
         mLastClientCompositionFence = fence;
+        mClearClientCompositionFenceOnLayerDisplayed = false;
     }
 
     const char* getDebugName() const override;
@@ -1035,7 +1036,7 @@
     mutable bool mDrawingStateModified = false;
 
     sp<Fence> mLastClientCompositionFence;
-    bool mAlreadyDisplayedThisCompose = false;
+    bool mClearClientCompositionFenceOnLayerDisplayed = false;
 private:
     virtual void setTransformHint(ui::Transform::RotationFlags) {}
 
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index cbea77e..639ba5a 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -177,6 +177,11 @@
 }
 
 binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
+    std::scoped_lock lock(mLock);
+    if (mChannel.initCheck() != NO_ERROR) {
+        return binder::Status::fromStatusT(NAME_NOT_FOUND);
+    }
+
     outChannel->setReceiveFd(mChannel.moveReceiveFd());
     outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
     return binder::Status::ok();
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index c406478..adb96fd 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -112,7 +112,8 @@
 private:
     virtual void onFirstRef();
     EventThread* const mEventThread;
-    gui::BitTube mChannel;
+    std::mutex mLock;
+    gui::BitTube mChannel GUARDED_BY(mLock);
 
     std::vector<DisplayEventReceiver::Event> mPendingEvents;
 };