summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-20 14:03:34 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-20 14:03:34 +0000
commit170fbf309ac1ddcba3c7dafeafa22c225f3c62b5 (patch)
tree4ac2655af45af516376ec539e291ab6b521b7546
parent91d44995ac68f06b4a3010281bf90adaad6a473f (diff)
parent33da9468354b9b530712d4157298a8e0479cf2e5 (diff)
downloadnative-android13-frc-permission-release.tar.gz
Snap for 8745897 from 33da9468354b9b530712d4157298a8e0479cf2e5 to tm-frc-permission-releaset_frc_per_330444010android13-frc-permission-release
Change-Id: I33b7351be5fce1432058f1f7b57f7b081ed7a888
-rw-r--r--libs/gui/tests/EndToEndNativeInputTest.cpp49
-rw-r--r--services/surfaceflinger/Layer.cpp34
2 files changed, 82 insertions, 1 deletions
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 262987fd27..c6cdeb7706 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -566,6 +566,55 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) {
bgSurface->expectTap(12, 24);
}
+TEST_F(InputSurfacesTest, touchable_region) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+ surface->mInputInfo.touchableRegion.set(Rect{19, 29, 21, 31});
+
+ surface->showAt(11, 22);
+
+ // A tap within the surface but outside the touchable region should not be sent to the surface.
+ injectTap(20, 30);
+ EXPECT_EQ(surface->consumeEvent(200 /*timeoutMs*/), nullptr);
+
+ injectTap(31, 52);
+ surface->expectTap(20, 30);
+}
+
+TEST_F(InputSurfacesTest, input_respects_touchable_region_offset_overflow) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(100, 100);
+
+ // Set the touchable region to the values at the limit of its corresponding type.
+ // Since the surface is offset from the origin, the touchable region will be transformed into
+ // display space, which would trigger an overflow or an underflow. Ensure that we are protected
+ // against such a situation.
+ fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX});
+
+ fgSurface->showAt(100, 100);
+
+ // Expect no crash for overflow. The overflowed touchable region is ignored, so the background
+ // surface receives touch.
+ injectTap(112, 124);
+ bgSurface->expectTap(12, 24);
+}
+
+TEST_F(InputSurfacesTest, input_respects_scaled_touchable_region_overflow) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(0, 0);
+
+ fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX});
+ fgSurface->showAt(0, 0);
+
+ fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+ // Expect no crash for overflow.
+ injectTap(12, 24);
+ fgSurface->expectTap(6, 12);
+}
+
// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6ed4a94f25..be16942d40 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2194,6 +2194,37 @@ Rect Layer::getInputBounds() const {
return getCroppedBufferSize(getDrawingState());
}
+// Applies the given transform to the region, while protecting against overflows caused by any
+// offsets. If applying the offset in the transform to any of the Rects in the region would result
+// in an overflow, they are not added to the output Region.
+static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r,
+ const std::string& debugWindowName) {
+ // Round the translation using the same rounding strategy used by ui::Transform.
+ const auto tx = static_cast<int32_t>(t.tx() + 0.5);
+ const auto ty = static_cast<int32_t>(t.ty() + 0.5);
+
+ ui::Transform transformWithoutOffset = t;
+ transformWithoutOffset.set(0.f, 0.f);
+
+ const Region transformed = transformWithoutOffset.transform(r);
+
+ // Apply the translation to each of the Rects in the region while discarding any that overflow.
+ Region ret;
+ for (const auto& rect : transformed) {
+ Rect newRect;
+ if (__builtin_add_overflow(rect.left, tx, &newRect.left) ||
+ __builtin_add_overflow(rect.top, ty, &newRect.top) ||
+ __builtin_add_overflow(rect.right, tx, &newRect.right) ||
+ __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) {
+ ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.",
+ debugWindowName.c_str());
+ continue;
+ }
+ ret.orSelf(newRect);
+ }
+ return ret;
+}
+
void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
Rect tmpBounds = getInputBounds();
if (!tmpBounds.isValid()) {
@@ -2256,7 +2287,8 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDi
info.transform = inputToDisplay.inverse();
// The touchable region is specified in the input coordinate space. Change it to display space.
- info.touchableRegion = inputToDisplay.transform(info.touchableRegion);
+ info.touchableRegion =
+ transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName);
}
void Layer::fillTouchOcclusionMode(WindowInfo& info) {