Merge "Add focusTransferTarget in WindowInfo" into udc-dev
diff --git a/libs/binder/trusty/binderRpcTest/rules.mk b/libs/binder/trusty/binderRpcTest/rules.mk
index ae39492..975f689 100644
--- a/libs/binder/trusty/binderRpcTest/rules.mk
+++ b/libs/binder/trusty/binderRpcTest/rules.mk
@@ -32,4 +32,8 @@
trusty/user/base/lib/googletest \
trusty/user/base/lib/libstdc++-trusty \
+# TEST_P tests from binderRpcUniversalTests.cpp don't get linked in
+# unless we pass in --whole-archive to the linker (b/275620340).
+MODULE_USE_WHOLE_ARCHIVE := true
+
include make/trusted_app.mk
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 841c914..1750c64 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -149,6 +149,9 @@
/* Get the Bluetooth address of an input device, if known. */
virtual std::optional<std::string> getBluetoothAddress(int32_t deviceId) const = 0;
+
+ /* Sysfs node change reported. Recreate device if required to incorporate the new sysfs nodes */
+ virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0;
};
// --- InputReaderConfiguration ---
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index e65f3af..ee8dde1 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1531,6 +1531,20 @@
return associatedDevice;
}
+bool EventHub::AssociatedDevice::isChanged() const {
+ std::unordered_map<int32_t, RawBatteryInfo> newBatteryInfos =
+ readBatteryConfiguration(sysfsRootPath);
+ std::unordered_map<int32_t, RawLightInfo> newLightInfos =
+ readLightsConfiguration(sysfsRootPath);
+ std::optional<RawLayoutInfo> newLayoutInfo = readLayoutConfiguration(sysfsRootPath);
+
+ if (newBatteryInfos == batteryInfos && newLightInfos == lightInfos &&
+ newLayoutInfo == layoutInfo) {
+ return false;
+ }
+ return true;
+}
+
void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
@@ -2536,6 +2550,42 @@
return device->disable();
}
+// TODO(b/274755573): Shift to uevent handling on native side and remove this method
+// Currently using Java UEventObserver to trigger this which uses UEvent infrastructure that uses a
+// NETLINK socket to observe UEvents. We can create similar infrastructure on Eventhub side to
+// directly observe UEvents instead of triggering from Java side.
+void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) {
+ std::scoped_lock _l(mLock);
+
+ // Check in opening devices
+ for (auto it = mOpeningDevices.begin(); it != mOpeningDevices.end(); it++) {
+ std::unique_ptr<Device>& device = *it;
+ if (device->associatedDevice &&
+ sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
+ std::string::npos &&
+ device->associatedDevice->isChanged()) {
+ it = mOpeningDevices.erase(it);
+ openDeviceLocked(device->path);
+ }
+ }
+
+ // Check in already added device
+ std::vector<Device*> devicesToReopen;
+ for (const auto& [id, device] : mDevices) {
+ if (device->associatedDevice &&
+ sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
+ std::string::npos &&
+ device->associatedDevice->isChanged()) {
+ devicesToReopen.push_back(device.get());
+ }
+ }
+ for (const auto& device : devicesToReopen) {
+ closeDeviceLocked(*device);
+ openDeviceLocked(device->path);
+ }
+ devicesToReopen.clear();
+}
+
void EventHub::createVirtualKeyboardLocked() {
InputDeviceIdentifier identifier;
identifier.name = "Virtual";
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 9080cc1..81ac03b 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -928,6 +928,10 @@
return *associatedDisplayId == displayId;
}
+void InputReader::sysfsNodeChanged(const std::string& sysfsNodePath) {
+ mEventHub->sysfsNodeChanged(sysfsNodePath);
+}
+
void InputReader::dump(std::string& dump) {
std::scoped_lock _l(mLock);
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 0b15efe..20612c7 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -388,6 +388,10 @@
/* Disable an input device. Closes file descriptor to that device. */
virtual status_t disableDevice(int32_t deviceId) = 0;
+
+ /* Sysfs node changed. Reopen the Eventhub device if any new Peripheral like Light, Battery,
+ * etc. is detected. */
+ virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0;
};
template <std::size_t BITS>
@@ -567,6 +571,8 @@
status_t disableDevice(int32_t deviceId) override final;
+ void sysfsNodeChanged(const std::string& sysfsNodePath) override final;
+
~EventHub() override;
private:
@@ -578,6 +584,7 @@
std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos;
std::optional<RawLayoutInfo> layoutInfo;
+ bool isChanged() const;
bool operator==(const AssociatedDevice&) const = default;
bool operator!=(const AssociatedDevice&) const = default;
std::string dump() const;
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index e9c989a..120e150 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -117,6 +117,8 @@
std::optional<std::string> getBluetoothAddress(int32_t deviceId) const override;
+ void sysfsNodeChanged(const std::string& sysfsNodePath) override;
+
protected:
// These members are protected so they can be instrumented by test cases.
virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t deviceId,
diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp
index ff6d584..4626f5a 100644
--- a/services/inputflinger/tests/FakeEventHub.cpp
+++ b/services/inputflinger/tests/FakeEventHub.cpp
@@ -594,4 +594,33 @@
return lightIt->second;
};
+void FakeEventHub::setSysfsRootPath(int32_t deviceId, std::string sysfsRootPath) const {
+ Device* device = getDevice(deviceId);
+ if (device == nullptr) {
+ return;
+ }
+ device->sysfsRootPath = sysfsRootPath;
+}
+
+void FakeEventHub::sysfsNodeChanged(const std::string& sysfsNodePath) {
+ int32_t foundDeviceId = -1;
+ Device* foundDevice = nullptr;
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ Device* d = mDevices.valueAt(i);
+ if (sysfsNodePath.find(d->sysfsRootPath) != std::string::npos) {
+ foundDeviceId = mDevices.keyAt(i);
+ foundDevice = d;
+ }
+ }
+ if (foundDevice == nullptr) {
+ return;
+ }
+ // If device sysfs changed -> reopen the device
+ if (!mRawLightInfos.empty() && !foundDevice->classes.test(InputDeviceClass::LIGHT)) {
+ removeDevice(foundDeviceId);
+ addDevice(foundDeviceId, foundDevice->identifier.name,
+ foundDevice->classes | InputDeviceClass::LIGHT, foundDevice->identifier.bus);
+ }
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h
index e0a3f9e..8e06940 100644
--- a/services/inputflinger/tests/FakeEventHub.h
+++ b/services/inputflinger/tests/FakeEventHub.h
@@ -64,6 +64,7 @@
std::vector<VirtualKeyDefinition> virtualKeys;
bool enabled;
std::optional<RawLayoutInfo> layoutInfo;
+ std::string sysfsRootPath;
status_t enable() {
enabled = true;
@@ -152,6 +153,7 @@
void enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, int32_t code,
int32_t value);
void assertQueueIsEmpty();
+ void setSysfsRootPath(int32_t deviceId, std::string sysfsRootPath) const;
private:
Device* getDevice(int32_t deviceId) const;
@@ -212,7 +214,7 @@
std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override;
std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
int32_t deviceId, int32_t lightId) const override;
-
+ void sysfsNodeChanged(const std::string& sysfsNodePath) override;
void dump(std::string&) const override {}
void monitor() const override {}
void requestReopenDevices() override {}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 92d5357..3d0fbb4 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -644,6 +644,30 @@
ASSERT_EQ(0U, inputDevices[0].getMotionRanges().size());
}
+TEST_F(InputReaderTest, InputDeviceRecreatedOnSysfsNodeChanged) {
+ ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard", InputDeviceClass::KEYBOARD, nullptr));
+ mFakeEventHub->setSysfsRootPath(1, "xyz");
+
+ // Should also have received a notification describing the new input device.
+ ASSERT_EQ(1U, mFakePolicy->getInputDevices().size());
+ InputDeviceInfo inputDevice = mFakePolicy->getInputDevices()[0];
+ ASSERT_EQ(0U, inputDevice.getLights().size());
+
+ RawLightInfo infoMonolight = {.id = 123,
+ .name = "mono_keyboard_backlight",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(/*rawId=*/123, std::move(infoMonolight));
+ mReader->sysfsNodeChanged("xyz");
+ mReader->loopOnce();
+
+ // Should also have received a notification describing the new recreated input device.
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ inputDevice = mFakePolicy->getInputDevices()[0];
+ ASSERT_EQ(1U, inputDevice.getLights().size());
+}
+
TEST_F(InputReaderTest, GetMergedInputDevices) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index 20242b1..baece3c 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -165,6 +165,10 @@
return reader->getBluetoothAddress(deviceId);
}
+ void sysfsNodeChanged(const std::string& sysfsNodePath) {
+ reader->sysfsNodeChanged(sysfsNodePath);
+ }
+
private:
std::unique_ptr<InputReaderInterface> reader;
};
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index d9a07b9..9f4aa5c 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -225,6 +225,7 @@
bool isDeviceEnabled(int32_t deviceId) const override { return mFdp->ConsumeBool(); }
status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
+ void sysfsNodeChanged(const std::string& sysfsNodePath) override {}
};
class FuzzPointerController : public PointerControllerInterface {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index a8322d8..d93e25e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -83,12 +83,9 @@
// If set, causes the dirty regions to flash with the delay
std::optional<std::chrono::microseconds> devOptFlashDirtyRegionsDelay;
- // The earliest time to send the present command to the HAL
- std::chrono::steady_clock::time_point earliestPresentTime;
-
- // The previous present fence. Used together with earliestPresentTime
- // to prevent an early presentation of a frame.
- std::shared_ptr<FenceTime> previousPresentFence;
+ // Optional.
+ // The earliest time to send the present command to the HAL.
+ std::optional<std::chrono::steady_clock::time_point> earliestPresentTime;
// The expected time for the next present
nsecs_t expectedPresentTime{0};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index c291652..a3fda61 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -122,12 +122,9 @@
bool previousDeviceRequestedSuccess = false;
+ // Optional.
// The earliest time to send the present command to the HAL
- std::chrono::steady_clock::time_point earliestPresentTime;
-
- // The previous present fence. Used together with earliestPresentTime
- // to prevent an early presentation of a frame.
- std::shared_ptr<FenceTime> previousPresentFence;
+ std::optional<std::chrono::steady_clock::time_point> earliestPresentTime;
// The expected time for the next present
nsecs_t expectedPresentTime{0};
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index d50a768..85fc095 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -263,7 +263,6 @@
if (status_t result =
hwc.getDeviceCompositionChanges(*halDisplayId, requiresClientComposition,
getState().earliestPresentTime,
- getState().previousPresentFence,
getState().expectedPresentTime, outChanges);
result != NO_ERROR) {
ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
@@ -380,16 +379,11 @@
const TimePoint startTime = TimePoint::now();
- if (isPowerHintSessionEnabled()) {
- if (!getCompositionEngine().getHwComposer().getComposer()->isSupported(
- Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
- getState().previousPresentFence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
- mPowerAdvisor->setHwcPresentDelayedTime(mId, getState().earliestPresentTime);
- }
+ if (isPowerHintSessionEnabled() && getState().earliestPresentTime) {
+ mPowerAdvisor->setHwcPresentDelayedTime(mId, *getState().earliestPresentTime);
}
- hwc.presentAndGetReleaseFences(*halDisplayIdOpt, getState().earliestPresentTime,
- getState().previousPresentFence);
+ hwc.presentAndGetReleaseFences(*halDisplayIdOpt, getState().earliestPresentTime);
if (isPowerHintSessionEnabled()) {
mPowerAdvisor->setHwcPresentTiming(mId, startTime, TimePoint::now());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 175dd1d..e720af5 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -842,7 +842,6 @@
}
editState().earliestPresentTime = refreshArgs.earliestPresentTime;
- editState().previousPresentFence = refreshArgs.previousPresentFence;
editState().expectedPresentTime = refreshArgs.expectedPresentTime;
compositionengine::OutputLayer* peekThroughLayer = nullptr;
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 0756c1b..9be6bc2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -595,7 +595,7 @@
TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) {
EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mHwComposer,
- getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _))
+ getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _))
.WillOnce(Return(INVALID_OPERATION));
chooseCompositionStrategy(mDisplay.get());
@@ -619,8 +619,8 @@
.WillOnce(Return(false));
EXPECT_CALL(mHwComposer,
- getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges),
+ getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _))
+ .WillOnce(testing::DoAll(testing::SetArgPointee<4>(mDeviceRequestedChanges),
Return(NO_ERROR)));
EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
.Times(1);
@@ -672,8 +672,8 @@
.WillOnce(Return(false));
EXPECT_CALL(mHwComposer,
- getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR)));
+ getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(mDeviceRequestedChanges), Return(NO_ERROR)));
EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
.Times(1);
EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
@@ -901,7 +901,7 @@
sp<Fence> layer1Fence = sp<Fence>::make();
sp<Fence> layer2Fence = sp<Fence>::make();
- EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(HalDisplayId(DEFAULT_DISPLAY_ID), _, _))
+ EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(HalDisplayId(DEFAULT_DISPLAY_ID), _))
.Times(1);
EXPECT_CALL(mHwComposer, getPresentFence(HalDisplayId(DEFAULT_DISPLAY_ID)))
.WillOnce(Return(presentFence));
@@ -1078,7 +1078,7 @@
mDisplay->editState().isEnabled = true;
- EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(_, _, _));
+ EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(_, _));
EXPECT_CALL(*mDisplaySurface, onFrameCommitted());
mDisplay->postFramebuffer();
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 1a56ab7..67b94ee 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -54,16 +54,14 @@
MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId));
MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId));
- MOCK_METHOD6(getDeviceCompositionChanges,
- status_t(HalDisplayId, bool, std::chrono::steady_clock::time_point,
- const std::shared_ptr<FenceTime>&, nsecs_t,
- std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD5(getDeviceCompositionChanges,
+ status_t(HalDisplayId, bool, std::optional<std::chrono::steady_clock::time_point>,
+ nsecs_t, std::optional<android::HWComposer::DeviceRequestedChanges>*));
MOCK_METHOD5(setClientTarget,
status_t(HalDisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
ui::Dataspace));
- MOCK_METHOD3(presentAndGetReleaseFences,
- status_t(HalDisplayId, std::chrono::steady_clock::time_point,
- const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD2(presentAndGetReleaseFences,
+ status_t(HalDisplayId, std::optional<std::chrono::steady_clock::time_point>));
MOCK_METHOD2(setPowerMode, status_t(PhysicalDisplayId, hal::PowerMode));
MOCK_METHOD2(setActiveConfig, status_t(HalDisplayId, size_t));
MOCK_METHOD2(setColorTransform, status_t(HalDisplayId, const mat4&));
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index bd2680f..f28bfd4 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -1547,6 +1547,8 @@
}
bool AidlComposer::hasMultiThreadedPresentSupport(Display display) {
+#if 0
+ // TODO (b/259132483): Reenable
const auto displayId = translate<int64_t>(display);
std::vector<AidlDisplayCapability> capabilities;
const auto status = mAidlComposerClient->getDisplayCapabilities(displayId, &capabilities);
@@ -1556,6 +1558,10 @@
}
return std::find(capabilities.begin(), capabilities.end(),
AidlDisplayCapability::MULTI_THREADED_PRESENT) != capabilities.end();
+#else
+ (void) display;
+ return false;
+#endif
}
void AidlComposer::addReader(Display display) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 28148ac..f350eba 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -395,8 +395,8 @@
status_t HWComposer::getDeviceCompositionChanges(
HalDisplayId displayId, bool frameUsesClientComposition,
- std::chrono::steady_clock::time_point earliestPresentTime,
- const std::shared_ptr<FenceTime>& previousPresentFence, nsecs_t expectedPresentTime,
+ std::optional<std::chrono::steady_clock::time_point> earliestPresentTime,
+ nsecs_t expectedPresentTime,
std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
ATRACE_CALL();
@@ -426,14 +426,13 @@
// If composer supports getting the expected present time, we can skip
// as composer will make sure to prevent early presentation
- if (mComposer->isSupported(Hwc2::Composer::OptionalFeature::ExpectedPresentTime)) {
+ if (!earliestPresentTime) {
return true;
}
// composer doesn't support getting the expected present time. We can only
// skip validate if we know that we are not going to present early.
- return std::chrono::steady_clock::now() >= earliestPresentTime ||
- previousPresentFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING;
+ return std::chrono::steady_clock::now() >= *earliestPresentTime;
}();
displayData.validateWasSkipped = false;
@@ -508,8 +507,8 @@
}
status_t HWComposer::presentAndGetReleaseFences(
- HalDisplayId displayId, std::chrono::steady_clock::time_point earliestPresentTime,
- const std::shared_ptr<FenceTime>& previousPresentFence) {
+ HalDisplayId displayId,
+ std::optional<std::chrono::steady_clock::time_point> earliestPresentTime) {
ATRACE_CALL();
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -525,13 +524,9 @@
return NO_ERROR;
}
- const bool waitForEarliestPresent =
- !mComposer->isSupported(Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
- previousPresentFence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
-
- if (waitForEarliestPresent) {
+ if (earliestPresentTime) {
ATRACE_NAME("wait for earliest present time");
- std::this_thread::sleep_until(earliestPresentTime);
+ std::this_thread::sleep_until(*earliestPresentTime);
}
auto error = hwcDisplay->present(&displayData.lastPresentFence);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 7a3f41c..3702c62 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -143,17 +143,16 @@
// expected.
virtual status_t getDeviceCompositionChanges(
HalDisplayId, bool frameUsesClientComposition,
- std::chrono::steady_clock::time_point earliestPresentTime,
- const std::shared_ptr<FenceTime>& previousPresentFence, nsecs_t expectedPresentTime,
- std::optional<DeviceRequestedChanges>* outChanges) = 0;
+ std::optional<std::chrono::steady_clock::time_point> earliestPresentTime,
+ nsecs_t expectedPresentTime, std::optional<DeviceRequestedChanges>* outChanges) = 0;
virtual status_t setClientTarget(HalDisplayId, uint32_t slot, const sp<Fence>& acquireFence,
const sp<GraphicBuffer>& target, ui::Dataspace) = 0;
// Present layers to the display and read releaseFences.
virtual status_t presentAndGetReleaseFences(
- HalDisplayId, std::chrono::steady_clock::time_point earliestPresentTime,
- const std::shared_ptr<FenceTime>& previousPresentFence) = 0;
+ HalDisplayId,
+ std::optional<std::chrono::steady_clock::time_point> earliestPresentTime) = 0;
// set power mode
virtual status_t setPowerMode(PhysicalDisplayId, hal::PowerMode) = 0;
@@ -339,8 +338,8 @@
status_t getDeviceCompositionChanges(
HalDisplayId, bool frameUsesClientComposition,
- std::chrono::steady_clock::time_point earliestPresentTime,
- const std::shared_ptr<FenceTime>& previousPresentFence, nsecs_t expectedPresentTime,
+ std::optional<std::chrono::steady_clock::time_point> earliestPresentTime,
+ nsecs_t expectedPresentTime,
std::optional<DeviceRequestedChanges>* outChanges) override;
status_t setClientTarget(HalDisplayId, uint32_t slot, const sp<Fence>& acquireFence,
@@ -348,8 +347,8 @@
// Present layers to the display and read releaseFences.
status_t presentAndGetReleaseFences(
- HalDisplayId, std::chrono::steady_clock::time_point earliestPresentTime,
- const std::shared_ptr<FenceTime>& previousPresentFence) override;
+ HalDisplayId,
+ std::optional<std::chrono::steady_clock::time_point> earliestPresentTime) override;
// set power mode
status_t setPowerMode(PhysicalDisplayId, hal::PowerMode mode) override;
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
index ce21233..6af352c 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
@@ -74,4 +74,23 @@
return LayerCreationArgs(other.flinger, other.client, other.name, other.flags, other.metadata);
}
+std::string LayerCreationArgs::getDebugString() const {
+ std::stringstream stream;
+ stream << "LayerCreationArgs{" << name << "[" << sequence << "] flags=" << flags
+ << " pid=" << ownerPid << " uid=" << ownerUid;
+ if (addToRoot) {
+ stream << " addToRoot=" << addToRoot;
+ }
+ if (parentId != UNASSIGNED_LAYER_ID) {
+ stream << " parentId=" << parentId;
+ }
+ if (layerIdToMirror != UNASSIGNED_LAYER_ID) {
+ stream << " layerIdToMirror=" << layerIdToMirror;
+ }
+ if (layerStackToMirror != ui::INVALID_LAYER_STACK) {
+ stream << " layerStackToMirror=" << layerStackToMirror.id;
+ }
+ return stream.str();
+}
+
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
index 011250c..3a0fc6d 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
@@ -44,6 +44,7 @@
bool internalLayer = false);
LayerCreationArgs(std::optional<uint32_t> id, bool internalLayer = false);
LayerCreationArgs() = default; // for tracing
+ std::string getDebugString() const;
android::SurfaceFlinger* flinger;
sp<android::Client> client;
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index 3706225..33d9dbe 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -164,7 +164,8 @@
}
}
-void LayerLifecycleManager::applyTransactions(const std::vector<TransactionState>& transactions) {
+void LayerLifecycleManager::applyTransactions(const std::vector<TransactionState>& transactions,
+ bool ignoreUnknownLayers) {
for (const auto& transaction : transactions) {
for (const auto& resolvedComposerState : transaction.states) {
const auto& clientState = resolvedComposerState.state;
@@ -176,7 +177,8 @@
RequestedLayerState* layer = getLayerFromId(layerId);
if (layer == nullptr) {
- LOG_ALWAYS_FATAL("%s Layer with layerid=%d not found", __func__, layerId);
+ LOG_ALWAYS_FATAL_IF(!ignoreUnknownLayers, "%s Layer with layerid=%d not found",
+ __func__, layerId);
continue;
}
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
index 3d9a74c..f258678 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
@@ -39,7 +39,11 @@
public:
// External state changes should be updated in the following order:
void addLayers(std::vector<std::unique_ptr<RequestedLayerState>>);
- void applyTransactions(const std::vector<TransactionState>&);
+ // Ignore unknown layers when interoping with legacy front end. In legacy we destroy
+ // the layers it is unreachable. When using the LayerLifecycleManager for layer trace
+ // generation we may encounter layers which are known because we don't have an explicit
+ // lifecycle. Ignore these errors while we have to interop with legacy.
+ void applyTransactions(const std::vector<TransactionState>&, bool ignoreUnknownLayers = false);
// Ignore unknown handles when iteroping with legacy front end. In the old world, we
// would create child layers which are not necessary with the new front end. This means
// we will get notified for handle changes that don't exist in the new front end.
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 2d6d8ad..1e931a7 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -187,6 +187,8 @@
<< " geomLayerTransform={tx=" << geomLayerTransform.tx()
<< ",ty=" << geomLayerTransform.ty() << "}"
<< "}";
+ debug << " input{ touchCropId=" << touchCropId
+ << " replaceTouchableRegionWithCrop=" << inputInfo.replaceTouchableRegionWithCrop << "}";
return debug.str();
}
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 5491d9a..b167d3e 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -94,6 +94,7 @@
int32_t frameRateSelectionPriority;
LayerHierarchy::TraversalPath mirrorRootPath;
bool unreachable = true;
+ uint32_t touchCropId;
uid_t uid;
pid_t pid;
ChildState childState;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index babcbe7..25cbe7a 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -447,23 +447,36 @@
}
}
+ // Update touchable region crops outside the main update pass. This is because a layer could be
+ // cropped by any other layer and it requires both snapshots to be updated.
+ updateTouchableRegionCrop(args);
+
const bool hasUnreachableSnapshots = sortSnapshotsByZ(args);
clearChanges(mRootSnapshot);
- // Destroy unreachable snapshots
- if (!hasUnreachableSnapshots) {
+ // Destroy unreachable snapshots for clone layers. And destroy snapshots for non-clone
+ // layers if the layer have been destroyed.
+ // TODO(b/238781169) consider making clone layer ids stable as well
+ if (!hasUnreachableSnapshots && args.layerLifecycleManager.getDestroyedLayers().empty()) {
return;
}
+ std::unordered_set<uint32_t> destroyedLayerIds;
+ for (auto& destroyedLayer : args.layerLifecycleManager.getDestroyedLayers()) {
+ destroyedLayerIds.insert(destroyedLayer->id);
+ }
+
auto it = mSnapshots.begin();
while (it < mSnapshots.end()) {
auto& traversalPath = it->get()->path;
- if (!it->get()->unreachable) {
+ if (!it->get()->unreachable &&
+ destroyedLayerIds.find(traversalPath.id) == destroyedLayerIds.end()) {
it++;
continue;
}
mIdToSnapshot.erase(traversalPath);
+ mNeedsTouchableRegionCrop.erase(traversalPath);
mSnapshots.back()->globalZ = it->get()->globalZ;
std::iter_swap(it, mSnapshots.end() - 1);
mSnapshots.erase(mSnapshots.end() - 1);
@@ -554,7 +567,7 @@
mResortSnapshots = false;
for (auto& snapshot : mSnapshots) {
- snapshot->unreachable = true;
+ snapshot->unreachable = snapshot->path.isClone();
}
size_t globalZ = 0;
@@ -739,6 +752,8 @@
// If root layer, use the layer stack otherwise get the parent's layer stack.
snapshot.color.a = parentSnapshot.color.a * requested.color.a;
snapshot.alpha = snapshot.color.a;
+ snapshot.inputInfo.alpha = snapshot.color.a;
+
snapshot.isSecure =
parentSnapshot.isSecure || (requested.flags & layer_state_t::eLayerSecure);
snapshot.isTrustedOverlay = parentSnapshot.isTrustedOverlay || requested.isTrustedOverlay;
@@ -986,9 +1001,11 @@
snapshot.inputInfo.ownerUid = static_cast<int32_t>(requested.ownerUid);
snapshot.inputInfo.ownerPid = requested.ownerPid;
}
+ snapshot.touchCropId = requested.touchCropId;
snapshot.inputInfo.id = static_cast<int32_t>(snapshot.uniqueSequence);
snapshot.inputInfo.displayId = static_cast<int32_t>(snapshot.outputFilter.layerStack.id);
+ updateVisibility(snapshot, snapshot.isVisible);
if (!needsInputInfo(snapshot, requested)) {
return;
}
@@ -1033,27 +1050,13 @@
}
auto cropLayerSnapshot = getSnapshot(requested.touchCropId);
- if (snapshot.inputInfo.replaceTouchableRegionWithCrop) {
- Rect inputBoundsInDisplaySpace;
- if (!cropLayerSnapshot) {
- FloatRect inputBounds = getInputBounds(snapshot, /*fillParentBounds=*/true).first;
- inputBoundsInDisplaySpace =
- getInputBoundsInDisplaySpace(snapshot, inputBounds, displayInfo.transform);
- } else {
- FloatRect inputBounds =
- getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
- inputBoundsInDisplaySpace =
- getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
- displayInfo.transform);
- }
- snapshot.inputInfo.touchableRegion = Region(inputBoundsInDisplaySpace);
- } else if (cropLayerSnapshot) {
- FloatRect inputBounds = getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
+ if (cropLayerSnapshot) {
+ mNeedsTouchableRegionCrop.insert(path);
+ } else if (snapshot.inputInfo.replaceTouchableRegionWithCrop) {
+ FloatRect inputBounds = getInputBounds(snapshot, /*fillParentBounds=*/true).first;
Rect inputBoundsInDisplaySpace =
- getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
- displayInfo.transform);
- snapshot.inputInfo.touchableRegion = snapshot.inputInfo.touchableRegion.intersect(
- displayInfo.transform.transform(inputBoundsInDisplaySpace));
+ getInputBoundsInDisplaySpace(snapshot, inputBounds, displayInfo.transform);
+ snapshot.inputInfo.touchableRegion = Region(inputBoundsInDisplaySpace);
}
// Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
@@ -1066,12 +1069,7 @@
// touches from going outside the cloned area.
if (path.isClone()) {
snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::CLONE;
- auto clonedRootSnapshot = getSnapshot(snapshot.mirrorRootPath);
- if (clonedRootSnapshot) {
- const Rect rect =
- displayInfo.transform.transform(Rect{clonedRootSnapshot->transformedBounds});
- snapshot.inputInfo.touchableRegion = snapshot.inputInfo.touchableRegion.intersect(rect);
- }
+ mNeedsTouchableRegionCrop.insert(path);
}
}
@@ -1117,4 +1115,77 @@
}
}
+void LayerSnapshotBuilder::updateTouchableRegionCrop(const Args& args) {
+ if (mNeedsTouchableRegionCrop.empty()) {
+ return;
+ }
+
+ static constexpr ftl::Flags<RequestedLayerState::Changes> AFFECTS_INPUT =
+ RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Created |
+ RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
+ RequestedLayerState::Changes::Input;
+
+ if (args.forceUpdate != ForceUpdateFlags::ALL &&
+ !args.layerLifecycleManager.getGlobalChanges().any(AFFECTS_INPUT)) {
+ return;
+ }
+
+ for (auto& path : mNeedsTouchableRegionCrop) {
+ frontend::LayerSnapshot* snapshot = getSnapshot(path);
+ if (!snapshot) {
+ continue;
+ }
+ const std::optional<frontend::DisplayInfo> displayInfoOpt =
+ args.displays.get(snapshot->outputFilter.layerStack);
+ static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
+ auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
+
+ bool needsUpdate =
+ args.forceUpdate == ForceUpdateFlags::ALL || snapshot->changes.any(AFFECTS_INPUT);
+ auto cropLayerSnapshot = getSnapshot(snapshot->touchCropId);
+ needsUpdate =
+ needsUpdate || (cropLayerSnapshot && cropLayerSnapshot->changes.any(AFFECTS_INPUT));
+ auto clonedRootSnapshot = path.isClone() ? getSnapshot(snapshot->mirrorRootPath) : nullptr;
+ needsUpdate = needsUpdate ||
+ (clonedRootSnapshot && clonedRootSnapshot->changes.any(AFFECTS_INPUT));
+
+ if (!needsUpdate) {
+ continue;
+ }
+
+ if (snapshot->inputInfo.replaceTouchableRegionWithCrop) {
+ Rect inputBoundsInDisplaySpace;
+ if (!cropLayerSnapshot) {
+ FloatRect inputBounds = getInputBounds(*snapshot, /*fillParentBounds=*/true).first;
+ inputBoundsInDisplaySpace =
+ getInputBoundsInDisplaySpace(*snapshot, inputBounds, displayInfo.transform);
+ } else {
+ FloatRect inputBounds =
+ getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
+ inputBoundsInDisplaySpace =
+ getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
+ displayInfo.transform);
+ }
+ snapshot->inputInfo.touchableRegion = Region(inputBoundsInDisplaySpace);
+ } else if (cropLayerSnapshot) {
+ FloatRect inputBounds =
+ getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
+ Rect inputBoundsInDisplaySpace =
+ getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
+ displayInfo.transform);
+ snapshot->inputInfo.touchableRegion = snapshot->inputInfo.touchableRegion.intersect(
+ displayInfo.transform.transform(inputBoundsInDisplaySpace));
+ }
+
+ // If the layer is a clone, we need to crop the input region to cloned root to prevent
+ // touches from going outside the cloned area.
+ if (clonedRootSnapshot) {
+ const Rect rect =
+ displayInfo.transform.transform(Rect{clonedRootSnapshot->transformedBounds});
+ snapshot->inputInfo.touchableRegion =
+ snapshot->inputInfo.touchableRegion.intersect(rect);
+ }
+ }
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index 7b1ff27..148c98e 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -119,10 +119,14 @@
const LayerSnapshot& parentSnapshot);
void updateChildState(LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot,
const Args& args);
+ void updateTouchableRegionCrop(const Args& args);
std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*,
LayerHierarchy::TraversalPathHash>
mIdToSnapshot;
+ // Track snapshots that needs touchable region crop from other snapshots
+ std::unordered_set<LayerHierarchy::TraversalPath, LayerHierarchy::TraversalPathHash>
+ mNeedsTouchableRegionCrop;
std::vector<std::unique_ptr<LayerSnapshot>> mSnapshots;
LayerSnapshot mRootSnapshot;
bool mResortSnapshots = false;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 755e585..8dec57b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -75,6 +75,7 @@
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHandle.h"
#include "LayerProtoHelper.h"
+#include "MutexUtils.h"
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
@@ -305,10 +306,12 @@
auto layersInTree = getRootLayer()->getLayersInTree(LayerVector::StateSet::Current);
std::sort(layersInTree.begin(), layersInTree.end());
- traverse(LayerVector::StateSet::Current, [&](Layer* layer) {
- layer->removeFromCurrentState();
- layer->removeRelativeZ(layersInTree);
- });
+ REQUIRE_MUTEX(mFlinger->mStateLock);
+ traverse(LayerVector::StateSet::Current,
+ [&](Layer* layer) REQUIRES(layer->mFlinger->mStateLock) {
+ layer->removeFromCurrentState();
+ layer->removeRelativeZ(layersInTree);
+ });
}
void Layer::addToCurrentState() {
@@ -1009,10 +1012,12 @@
mFlinger->mLayersAdded = true;
// set up SF to handle added color layer
if (isRemovedFromCurrentState()) {
+ MUTEX_ALIAS(mFlinger->mStateLock, mDrawingState.bgColorLayer->mFlinger->mStateLock);
mDrawingState.bgColorLayer->onRemovedFromCurrentState();
}
mFlinger->setTransactionFlags(eTransactionNeeded);
} else if (mDrawingState.bgColorLayer && alpha == 0) {
+ MUTEX_ALIAS(mFlinger->mStateLock, mDrawingState.bgColorLayer->mFlinger->mStateLock);
mDrawingState.bgColorLayer->reparent(nullptr);
mDrawingState.bgColorLayer = nullptr;
return true;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1af648a..0bfab7c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -290,7 +290,7 @@
virtual bool setMetadata(const LayerMetadata& data);
virtual void setChildrenDrawingParent(const sp<Layer>&);
- virtual bool reparent(const sp<IBinder>& newParentHandle);
+ virtual bool reparent(const sp<IBinder>& newParentHandle) REQUIRES(mFlinger->mStateLock);
virtual bool setColorTransform(const mat4& matrix);
virtual mat4 getColorTransform() const;
virtual bool hasColorTransform() const;
@@ -316,7 +316,8 @@
bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/);
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& /*handles*/,
bool willPresent);
- virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
+ virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace)
+ REQUIRES(mFlinger->mStateLock);
virtual bool setColorSpaceAgnostic(const bool agnostic);
virtual bool setDimmingEnabled(const bool dimmingEnabled);
virtual bool setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility);
@@ -641,13 +642,13 @@
/*
* Remove from current state and mark for removal.
*/
- void removeFromCurrentState();
+ void removeFromCurrentState() REQUIRES(mFlinger->mStateLock);
/*
* called with the state lock from a binder thread when the layer is
* removed from the current list to the pending removal list
*/
- void onRemovedFromCurrentState();
+ void onRemovedFromCurrentState() REQUIRES(mFlinger->mStateLock);
/*
* Called when the layer is added back to the current state list.
@@ -880,6 +881,9 @@
mTransformHint = transformHint;
}
+ // Exposed so SurfaceFlinger can assert that it's held
+ const sp<SurfaceFlinger> mFlinger;
+
protected:
// For unit tests
friend class TestableSurfaceFlinger;
@@ -941,9 +945,6 @@
*/
std::pair<FloatRect, bool> getInputBounds(bool fillParentBounds) const;
- // constant
- sp<SurfaceFlinger> mFlinger;
-
bool mPremultipliedAlpha{true};
const std::string mName;
const std::string mTransactionName{"TX - " + mName};
diff --git a/services/surfaceflinger/MutexUtils.h b/services/surfaceflinger/MutexUtils.h
index f8be6f3..58f7cb4 100644
--- a/services/surfaceflinger/MutexUtils.h
+++ b/services/surfaceflinger/MutexUtils.h
@@ -50,4 +50,14 @@
const status_t status;
};
+// Require, under penalty of compilation failure, that the compiler thinks that a mutex is held.
+#define REQUIRE_MUTEX(expr) ([]() REQUIRES(expr) {})()
+
+// Tell the compiler that we know that a mutex is held.
+#define ASSERT_MUTEX(expr) ([]() ASSERT_CAPABILITY(expr) {})()
+
+// Specify that one mutex is an alias for another.
+// (e.g. SurfaceFlinger::mStateLock and Layer::mFlinger->mStateLock)
+#define MUTEX_ALIAS(held, alias) (REQUIRE_MUTEX(held), ASSERT_MUTEX(alias))
+
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a271083..a538335 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2621,8 +2621,21 @@
const auto prevVsyncTime = mExpectedPresentTime - mScheduler->getVsyncSchedule()->period();
const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
- refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
- refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
+ const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period();
+ const bool threeVsyncsAhead = mExpectedPresentTime - frameTime > 2 * vsyncPeriod;
+
+ // We should wait for the earliest present time if HWC doesn't support ExpectedPresentTime,
+ // and the next vsync is not already taken by the previous frame.
+ const bool waitForEarliestPresent =
+ !getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
+ (threeVsyncsAhead ||
+ mPreviousPresentFences[0].fenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING);
+
+ if (waitForEarliestPresent) {
+ refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
+ }
+
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
refreshArgs.expectedPresentTime = mExpectedPresentTime.ns();
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
@@ -3722,11 +3735,8 @@
ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
if (updateWindowInfo) {
mWindowInfosListenerInvoker
- ->windowInfosChanged(std::move(windowInfos), std::move(displayInfos),
- std::move(
- inputWindowCommands.windowInfosReportedListeners),
- /* forceImmediateCall= */
- !inputWindowCommands.focusRequests.empty());
+ ->windowInfosChanged(windowInfos, displayInfos,
+ inputWindowCommands.windowInfosReportedListeners);
} else {
// If there are listeners but no changes to input windows, call the listeners
// immediately.
@@ -4759,6 +4769,7 @@
}
return 0;
}
+ MUTEX_ALIAS(mStateLock, layer->mFlinger->mStateLock);
ui::LayerStack oldLayerStack = layer->getLayerStack(LayerVector::StateSet::Current);
@@ -7729,6 +7740,7 @@
ALOGD("Layer was destroyed soon after creation %p", state.layer.unsafe_get());
return;
}
+ MUTEX_ALIAS(mStateLock, layer->mFlinger->mStateLock);
sp<Layer> parent;
bool addToRoot = state.addToRoot;
@@ -7903,9 +7915,15 @@
ISurfaceComposerClient::eNoColorFill,
gui::LayerMetadata());
sp<Layer> childMirror;
- createEffectLayer(mirrorArgs, &unused, &childMirror);
- childMirror->setClonedChild(layer->createClone());
- childMirror->reparent(mirrorDisplay.rootHandle);
+ {
+ Mutex::Autolock lock(mStateLock);
+ createEffectLayer(mirrorArgs, &unused, &childMirror);
+ MUTEX_ALIAS(mStateLock, childMirror->mFlinger->mStateLock);
+ childMirror->setClonedChild(layer->createClone());
+ childMirror->reparent(mirrorDisplay.rootHandle);
+ }
+ // lock on mStateLock needs to be released before binder handle gets destroyed
+ unused.clear();
}
}
return true;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 74d00dd..834c8b6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -797,7 +797,7 @@
status_t mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args,
gui::CreateSurfaceResult& outResult);
- void markLayerPendingRemovalLocked(const sp<Layer>& layer);
+ void markLayerPendingRemovalLocked(const sp<Layer>& layer) REQUIRES(mStateLock);
// add a layer to SurfaceFlinger
status_t addClientLayer(LayerCreationArgs& args, const sp<IBinder>& handle,
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index 26ed878..87a633f 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -271,6 +271,7 @@
for (const proto::LayerState& layerState : transaction.layer_changes()) {
auto it = mStartingStates.find(layerState.layer_id());
if (it == mStartingStates.end()) {
+ // TODO(b/238781169) make this log fatal when we switch over to using new fe
ALOGW("Could not find layer id %d", layerState.layer_id());
continue;
}
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 4b4ce18..55004c5 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-#include <ios>
-#include <memory>
-#include <vector>
-#include "FrontEnd/LayerCreationArgs.h"
-#include "FrontEnd/RequestedLayerState.h"
-#include "Tracing/LayerTracing.h"
-#include "TransactionState.h"
-#include "cutils/properties.h"
#undef LOG_TAG
#define LOG_TAG "LayerTraceGenerator"
//#define LOG_NDEBUG 0
@@ -33,8 +25,15 @@
#include <utils/String16.h>
#include <filesystem>
#include <fstream>
+#include <ios>
#include <string>
+#include <vector>
+#include "FrontEnd/LayerCreationArgs.h"
+#include "FrontEnd/RequestedLayerState.h"
#include "LayerProtoHelper.h"
+#include "Tracing/LayerTracing.h"
+#include "TransactionState.h"
+#include "cutils/properties.h"
#include "LayerTraceGenerator.h"
@@ -84,6 +83,7 @@
for (int j = 0; j < entry.added_layers_size(); j++) {
LayerCreationArgs args;
parser.fromProto(entry.added_layers(j), args);
+ ALOGV(" %s", args.getDebugString().c_str());
addedLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args));
}
@@ -105,9 +105,14 @@
transactions.emplace_back(std::move(transaction));
}
+ for (int j = 0; j < entry.destroyed_layers_size(); j++) {
+ ALOGV(" destroyedHandles=%d", entry.destroyed_layers(j));
+ }
+
std::vector<uint32_t> destroyedHandles;
destroyedHandles.reserve((size_t)entry.destroyed_layer_handles_size());
for (int j = 0; j < entry.destroyed_layer_handles_size(); j++) {
+ ALOGV(" destroyedHandles=%d", entry.destroyed_layer_handles(j));
destroyedHandles.push_back(entry.destroyed_layer_handles(j));
}
@@ -118,7 +123,7 @@
// apply updates
lifecycleManager.addLayers(std::move(addedLayers));
- lifecycleManager.applyTransactions(transactions);
+ lifecycleManager.applyTransactions(transactions, /*ignoreUnknownHandles=*/true);
lifecycleManager.onHandlesDestroyed(destroyedHandles, /*ignoreUnknownHandles=*/true);
if (lifecycleManager.getGlobalChanges().test(
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 73a7cae..292083b 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -25,14 +25,20 @@
using gui::IWindowInfosListener;
using gui::WindowInfo;
-struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener,
- IBinder::DeathRecipient {
- WindowInfosReportedListenerInvoker(size_t callbackCount,
- WindowInfosReportedListenerSet windowInfosReportedListeners)
+struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowInfosReportedListener,
+ DeathRecipient {
+ explicit WindowInfosReportedListener(
+ size_t callbackCount,
+ const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+ SpHash<gui::IWindowInfosReportedListener>>&
+ windowInfosReportedListeners)
: mCallbacksPending(callbackCount),
- mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {}
+ mWindowInfosReportedListeners(windowInfosReportedListeners) {}
binder::Status onWindowInfosReported() override {
+ // TODO(b/222421815) There could potentially be callbacks that we don't need to wait for
+ // before calling the WindowInfosReportedListeners coming from InputWindowCommands. Filter
+ // the list of callbacks down to those from system server.
if (--mCallbacksPending == 0) {
for (const auto& listener : mWindowInfosReportedListeners) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
@@ -48,7 +54,9 @@
private:
std::atomic<size_t> mCallbacksPending;
- WindowInfosReportedListenerSet mWindowInfosReportedListeners;
+ std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+ SpHash<gui::IWindowInfosReportedListener>>
+ mWindowInfosReportedListeners;
};
void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
@@ -74,76 +82,38 @@
}
void WindowInfosListenerInvoker::windowInfosChanged(
- std::vector<WindowInfo> windowInfos, std::vector<DisplayInfo> displayInfos,
- WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall) {
- reportedListeners.insert(sp<WindowInfosListenerInvoker>::fromExisting(this));
- auto callListeners = [this, windowInfos = std::move(windowInfos),
- displayInfos = std::move(displayInfos),
- reportedListeners = std::move(reportedListeners)]() mutable {
- ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
- {
- std::scoped_lock lock(mListenersMutex);
- for (const auto& [_, listener] : mWindowInfosListeners) {
- windowInfosListeners.push_back(listener);
- }
- }
-
- auto reportedInvoker =
- sp<WindowInfosReportedListenerInvoker>::make(windowInfosListeners.size(),
- std::move(reportedListeners));
-
- for (const auto& listener : windowInfosListeners) {
- sp<IBinder> asBinder = IInterface::asBinder(listener);
-
- // linkToDeath is used here to ensure that the windowInfosReportedListeners
- // are called even if one of the windowInfosListeners dies before
- // calling onWindowInfosReported.
- asBinder->linkToDeath(reportedInvoker);
-
- auto status =
- listener->onWindowInfosChanged(windowInfos, displayInfos, reportedInvoker);
- if (!status.isOk()) {
- reportedInvoker->onWindowInfosReported();
- }
- }
- };
-
+ const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos,
+ const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+ SpHash<gui::IWindowInfosReportedListener>>&
+ windowInfosReportedListeners) {
+ ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
{
- std::scoped_lock lock(mMessagesMutex);
- // If there are unacked messages and this isn't a forced call, then return immediately.
- // If a forced window infos change doesn't happen first, the update will be sent after
- // the WindowInfosReportedListeners are called. If a forced window infos change happens or
- // if there are subsequent delayed messages before this update is sent, then this message
- // will be dropped and the listeners will only be called with the latest info. This is done
- // to reduce the amount of binder memory used.
- if (mActiveMessageCount > 0 && !forceImmediateCall) {
- mWindowInfosChangedDelayed = std::move(callListeners);
- return;
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mWindowInfosListeners) {
+ windowInfosListeners.push_back(listener);
}
-
- mWindowInfosChangedDelayed = nullptr;
- mActiveMessageCount++;
- }
- callListeners();
-}
-
-binder::Status WindowInfosListenerInvoker::onWindowInfosReported() {
- std::function<void()> callListeners;
-
- {
- std::scoped_lock lock{mMessagesMutex};
- mActiveMessageCount--;
- if (!mWindowInfosChangedDelayed || mActiveMessageCount > 0) {
- return binder::Status::ok();
- }
-
- mActiveMessageCount++;
- callListeners = std::move(mWindowInfosChangedDelayed);
- mWindowInfosChangedDelayed = nullptr;
}
- callListeners();
- return binder::Status::ok();
+ auto windowInfosReportedListener = windowInfosReportedListeners.empty()
+ ? nullptr
+ : sp<WindowInfosReportedListener>::make(windowInfosListeners.size(),
+ windowInfosReportedListeners);
+ for (const auto& listener : windowInfosListeners) {
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+
+ // linkToDeath is used here to ensure that the windowInfosReportedListeners
+ // are called even if one of the windowInfosListeners dies before
+ // calling onWindowInfosReported.
+ if (windowInfosReportedListener) {
+ asBinder->linkToDeath(windowInfosReportedListener);
+ }
+
+ auto status = listener->onWindowInfosChanged(windowInfos, displayInfos,
+ windowInfosReportedListener);
+ if (windowInfosReportedListener && !status.isOk()) {
+ windowInfosReportedListener->onWindowInfosReported();
+ }
+ }
}
} // namespace android
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index bfe036e..d60a9c4 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -23,40 +23,34 @@
#include <android/gui/IWindowInfosReportedListener.h>
#include <binder/IBinder.h>
#include <ftl/small_map.h>
-#include <gui/SpHash.h>
#include <utils/Mutex.h>
namespace android {
-using WindowInfosReportedListenerSet =
- std::unordered_set<sp<gui::IWindowInfosReportedListener>,
- gui::SpHash<gui::IWindowInfosReportedListener>>;
+class SurfaceFlinger;
-class WindowInfosListenerInvoker : public gui::BnWindowInfosReportedListener,
- public IBinder::DeathRecipient {
+class WindowInfosListenerInvoker : public IBinder::DeathRecipient {
public:
void addWindowInfosListener(sp<gui::IWindowInfosListener>);
void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
- void windowInfosChanged(std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>,
- WindowInfosReportedListenerSet windowInfosReportedListeners,
- bool forceImmediateCall);
-
- binder::Status onWindowInfosReported() override;
+ void windowInfosChanged(const std::vector<gui::WindowInfo>&,
+ const std::vector<gui::DisplayInfo>&,
+ const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+ SpHash<gui::IWindowInfosReportedListener>>&
+ windowInfosReportedListeners);
protected:
void binderDied(const wp<IBinder>& who) override;
private:
+ struct WindowInfosReportedListener;
+
std::mutex mListenersMutex;
static constexpr size_t kStaticCapacity = 3;
ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
mWindowInfosListeners GUARDED_BY(mListenersMutex);
-
- std::mutex mMessagesMutex;
- uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0;
- std::function<void()> mWindowInfosChangedDelayed GUARDED_BY(mMessagesMutex);
};
} // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index 8a6af10..a9247fe 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -222,7 +222,7 @@
std::optional<impl::HWComposer::DeviceRequestedChanges> outChanges;
mHwc.getDeviceCompositionChanges(halDisplayID,
mFdp.ConsumeBool() /*frameUsesClientComposition*/,
- std::chrono::steady_clock::now(), FenceTime::NO_FENCE,
+ std::chrono::steady_clock::now(),
mFdp.ConsumeIntegral<nsecs_t>(), &outChanges);
}
@@ -555,8 +555,7 @@
mHwc.setClientTarget(halDisplayID, mFdp.ConsumeIntegral<uint32_t>(), Fence::NO_FENCE,
sp<GraphicBuffer>::make(), mFdp.PickValueInArray(kDataspaces));
- mHwc.presentAndGetReleaseFences(halDisplayID, std::chrono::steady_clock::now(),
- FenceTime::NO_FENCE);
+ mHwc.presentAndGetReleaseFences(halDisplayID, std::chrono::steady_clock::now());
mHwc.setPowerMode(mPhysicalDisplayId, mFdp.PickValueInArray(kPowerModes));
diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
index 3e3d8f0..2b29530 100644
--- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
+++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
@@ -148,6 +148,35 @@
touchableRegionBounds};
}
+static std::vector<LayerInfo> getLayerInfosFromProto(
+ android::surfaceflinger::LayersTraceProto& entry) {
+ std::unordered_map<int32_t /* snapshotId*/, int32_t /*layerId*/> snapshotIdToLayerId;
+ std::vector<LayerInfo> layers;
+ layers.reserve(static_cast<size_t>(entry.layers().layers_size()));
+ bool mapSnapshotIdToLayerId = false;
+ for (int i = 0; i < entry.layers().layers_size(); i++) {
+ auto layer = entry.layers().layers(i);
+ LayerInfo layerInfo = getLayerInfoFromProto(layer);
+
+ snapshotIdToLayerId[layerInfo.id] = static_cast<int32_t>(layer.original_id());
+ if (layer.original_id() != 0) {
+ mapSnapshotIdToLayerId = true;
+ }
+ layers.push_back(layerInfo);
+ }
+ std::sort(layers.begin(), layers.end(), compareById);
+
+ if (!mapSnapshotIdToLayerId) {
+ return layers;
+ }
+ for (auto& layer : layers) {
+ layer.id = snapshotIdToLayerId[layer.id];
+ auto it = snapshotIdToLayerId.find(layer.parent);
+ layer.parent = it == snapshotIdToLayerId.end() ? -1 : it->second;
+ }
+ return layers;
+}
+
TEST_P(TransactionTraceTestSuite, validateEndState) {
ASSERT_GT(mActualLayersTraceProto.entry_size(), 0);
ASSERT_GT(mExpectedLayersTraceProto.entry_size(), 0);
@@ -158,32 +187,9 @@
EXPECT_EQ(expectedLastEntry.layers().layers_size(), actualLastEntry.layers().layers_size());
- std::vector<LayerInfo> expectedLayers;
- expectedLayers.reserve(static_cast<size_t>(expectedLastEntry.layers().layers_size()));
- for (int i = 0; i < expectedLastEntry.layers().layers_size(); i++) {
- auto layer = expectedLastEntry.layers().layers(i);
- LayerInfo layerInfo = getLayerInfoFromProto(layer);
- expectedLayers.push_back(layerInfo);
- }
- std::sort(expectedLayers.begin(), expectedLayers.end(), compareById);
-
- std::unordered_map<int32_t /* snapshotId*/, int32_t /*layerId*/> snapshotIdToLayerId;
- std::vector<LayerInfo> actualLayers;
- actualLayers.reserve(static_cast<size_t>(actualLastEntry.layers().layers_size()));
- for (int i = 0; i < actualLastEntry.layers().layers_size(); i++) {
- auto layer = actualLastEntry.layers().layers(i);
- LayerInfo layerInfo = getLayerInfoFromProto(layer);
- snapshotIdToLayerId[layerInfo.id] = static_cast<int32_t>(layer.original_id());
- actualLayers.push_back(layerInfo);
- }
-
- for (auto& layer : actualLayers) {
- layer.id = snapshotIdToLayerId[layer.id];
- auto it = snapshotIdToLayerId.find(layer.parent);
- layer.parent = it == snapshotIdToLayerId.end() ? -1 : it->second;
- }
-
- std::sort(actualLayers.begin(), actualLayers.end(), compareById);
+ std::vector<LayerInfo> expectedLayers = getLayerInfosFromProto(expectedLastEntry);
+ std::vector<LayerInfo> actualLayers = getLayerInfosFromProto(actualLastEntry);
+ ;
size_t i = 0;
for (; i < actualLayers.size() && i < expectedLayers.size(); i++) {
diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_b275630566.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_b275630566.winscope
new file mode 100644
index 0000000..fe504d7
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_b275630566.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_b275630566.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_b275630566.winscope
new file mode 100644
index 0000000..6f7ba15
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_b275630566.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 5b3c7ef..79cfd6a 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -278,6 +278,25 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setTouchableRegionCrop(uint32_t id, Region region, uint32_t touchCropId,
+ bool replaceTouchableRegionWithCrop) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.windowInfoHandle =
+ sp<gui::WindowInfoHandle>::make();
+ auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ inputInfo->touchableRegion = region;
+ inputInfo->replaceTouchableRegionWithCrop = replaceTouchableRegionWithCrop;
+ transactions.back().states.front().touchCropId = touchCropId;
+
+ inputInfo->token = sp<BBinder>::make();
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
LayerLifecycleManager mLifecycleManager;
};
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index b8c4781..5a066a6 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -308,6 +308,31 @@
EXPECT_EQ(getSnapshot(1)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote);
}
+TEST_F(LayerSnapshotTest, canCropTouchableRegion) {
+ // ROOT
+ // ├── 1
+ // │ ├── 11
+ // │ │ └── 111 (touchregion set to touch but cropped by layer 13)
+ // │ ├── 12
+ // │ │ ├── 121
+ // │ │ └── 122
+ // │ │ └── 1221
+ // │ └── 13 (crop set to touchCrop)
+ // └── 2
+
+ Rect touchCrop{300, 300, 400, 500};
+ setCrop(13, touchCrop);
+ Region touch{Rect{0, 0, 1000, 1000}};
+ setTouchableRegionCrop(111, touch, /*touchCropId=*/13, /*replaceTouchableRegionWithCrop=*/true);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 111})->inputInfo.touchableRegion.bounds(), touchCrop);
+
+ Rect modifiedTouchCrop{100, 300, 400, 700};
+ setCrop(13, modifiedTouchCrop);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 111})->inputInfo.touchableRegion.bounds(), modifiedTouchCrop);
+}
+
// Display Mirroring Tests
// tree with 3 levels of children
// ROOT (DISPLAY 0)