Merge "Migrate renderengine atrace calls to perfetto" into main
diff --git a/data/etc/input/motion_predictor_config.xml b/data/etc/input/motion_predictor_config.xml
index c3f2fed..14540ec 100644
--- a/data/etc/input/motion_predictor_config.xml
+++ b/data/etc/input/motion_predictor_config.xml
@@ -35,7 +35,10 @@
The jerk thresholds are based on normalized dt = 1 calculations.
-->
- <low-jerk>1.0</low-jerk>
- <high-jerk>1.1</high-jerk>
+ <low-jerk>1.5</low-jerk>
+ <high-jerk>2.0</high-jerk>
+
+ <!-- The forget factor in the first-order IIR filter for jerk smoothing -->
+ <jerk-forget-factor>0.25</jerk-forget-factor>
</motion-predictor>
diff --git a/include/input/MotionPredictor.h b/include/input/MotionPredictor.h
index f715039..2f1ef86 100644
--- a/include/input/MotionPredictor.h
+++ b/include/input/MotionPredictor.h
@@ -56,12 +56,20 @@
// acceleration) and has the units of d^3p/dt^3.
std::optional<float> jerkMagnitude() const;
+ // forgetFactor is the coefficient of the first-order IIR filter for jerk. A factor of 1 results
+ // in no smoothing.
+ void setForgetFactor(float forgetFactor);
+ float getForgetFactor() const;
+
private:
const bool mNormalizedDt;
+ // Coefficient of first-order IIR filter to smooth jerk calculation.
+ float mForgetFactor = 1;
RingBuffer<int64_t> mTimestamps{4};
std::array<float, 4> mXDerivatives{}; // [x, x', x'', x''']
std::array<float, 4> mYDerivatives{}; // [y, y', y'', y''']
+ float mJerkMagnitude;
};
/**
@@ -116,6 +124,11 @@
bool isPredictionAvailable(int32_t deviceId, int32_t source);
+ /**
+ * Currently used to expose config constants in testing.
+ */
+ const TfLiteMotionPredictorModel::Config& getModelConfig();
+
private:
const nsecs_t mPredictionTimestampOffsetNanos;
const std::function<bool()> mCheckMotionPredictionEnabled;
diff --git a/include/input/TfLiteMotionPredictor.h b/include/input/TfLiteMotionPredictor.h
index 728a8e1..08a4330 100644
--- a/include/input/TfLiteMotionPredictor.h
+++ b/include/input/TfLiteMotionPredictor.h
@@ -110,6 +110,9 @@
// High jerk means more predictions will be pruned, vice versa for low.
float lowJerk = 0;
float highJerk = 0;
+
+ // Coefficient for the first-order IIR filter for jerk calculation.
+ float jerkForgetFactor = 1;
};
// Creates a model from an encoded Flatbuffer model.
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 62b8433..7c19614 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -111,7 +111,9 @@
} else {
binder = getRandomBinder(&provider);
}
- CHECK(OK == p->writeStrongBinder(binder));
+
+ // may fail if mixing kernel binder and RPC binder
+ (void) p->writeStrongBinder(binder);
},
});
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index f4cf11e..a9bd11e 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <set>
+#include <utility>
#include <android-base/file.h>
#include <android-base/parseint.h>
@@ -115,7 +116,7 @@
/* list of extra hal interfaces to dump containing process during native dumps */
// This is filled when dumpstate is called.
-static std::set<const std::string> extra_hal_interfaces_to_dump;
+static std::set<std::string> extra_hal_interfaces_to_dump;
static void read_extra_hals_to_dump_from_property() {
// extra hals to dump are already filled
@@ -129,7 +130,7 @@
if (trimmed_token.length() == 0) {
continue;
}
- extra_hal_interfaces_to_dump.insert(trimmed_token);
+ extra_hal_interfaces_to_dump.insert(std::move(trimmed_token));
}
}
diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp
index 5b61d39..9204b95 100644
--- a/libs/input/MotionPredictor.cpp
+++ b/libs/input/MotionPredictor.cpp
@@ -75,6 +75,9 @@
JerkTracker::JerkTracker(bool normalizedDt) : mNormalizedDt(normalizedDt) {}
void JerkTracker::pushSample(int64_t timestamp, float xPos, float yPos) {
+ // If we previously had full samples, we have a previous jerk calculation
+ // to do weighted smoothing.
+ const bool applySmoothing = mTimestamps.size() == mTimestamps.capacity();
mTimestamps.pushBack(timestamp);
const int numSamples = mTimestamps.size();
@@ -115,6 +118,16 @@
}
}
+ if (numSamples == static_cast<int>(mTimestamps.capacity())) {
+ float newJerkMagnitude = std::hypot(newXDerivatives[3], newYDerivatives[3]);
+ ALOGD_IF(isDebug(), "raw jerk: %f", newJerkMagnitude);
+ if (applySmoothing) {
+ mJerkMagnitude = mJerkMagnitude + (mForgetFactor * (newJerkMagnitude - mJerkMagnitude));
+ } else {
+ mJerkMagnitude = newJerkMagnitude;
+ }
+ }
+
std::swap(newXDerivatives, mXDerivatives);
std::swap(newYDerivatives, mYDerivatives);
}
@@ -125,11 +138,19 @@
std::optional<float> JerkTracker::jerkMagnitude() const {
if (mTimestamps.size() == mTimestamps.capacity()) {
- return std::hypot(mXDerivatives[3], mYDerivatives[3]);
+ return mJerkMagnitude;
}
return std::nullopt;
}
+void JerkTracker::setForgetFactor(float forgetFactor) {
+ mForgetFactor = forgetFactor;
+}
+
+float JerkTracker::getForgetFactor() const {
+ return mForgetFactor;
+}
+
// --- MotionPredictor ---
MotionPredictor::MotionPredictor(nsecs_t predictionTimestampOffsetNanos,
@@ -159,6 +180,7 @@
if (!mModel) {
mModel = TfLiteMotionPredictorModel::create();
LOG_ALWAYS_FATAL_IF(!mModel);
+ mJerkTracker.setForgetFactor(mModel->config().jerkForgetFactor);
}
if (!mBuffers) {
@@ -357,4 +379,12 @@
return true;
}
+const TfLiteMotionPredictorModel::Config& MotionPredictor::getModelConfig() {
+ if (!mModel) {
+ mModel = TfLiteMotionPredictorModel::create();
+ LOG_ALWAYS_FATAL_IF(!mModel);
+ }
+ return mModel->config();
+}
+
} // namespace android
diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp
index b843a4b..b401c98 100644
--- a/libs/input/TfLiteMotionPredictor.cpp
+++ b/libs/input/TfLiteMotionPredictor.cpp
@@ -283,6 +283,7 @@
.distanceNoiseFloor = parseXMLFloat(*configRoot, "distance-noise-floor"),
.lowJerk = parseXMLFloat(*configRoot, "low-jerk"),
.highJerk = parseXMLFloat(*configRoot, "high-jerk"),
+ .jerkForgetFactor = parseXMLFloat(*configRoot, "jerk-forget-factor"),
};
return std::unique_ptr<TfLiteMotionPredictorModel>(
diff --git a/libs/input/tests/MotionPredictor_test.cpp b/libs/input/tests/MotionPredictor_test.cpp
index d077760..5bd5794 100644
--- a/libs/input/tests/MotionPredictor_test.cpp
+++ b/libs/input/tests/MotionPredictor_test.cpp
@@ -88,6 +88,7 @@
TEST(JerkTrackerTest, JerkCalculationNormalizedDtTrue) {
JerkTracker jerkTracker(true);
+ jerkTracker.setForgetFactor(.5);
jerkTracker.pushSample(/*timestamp=*/0, 20, 50);
jerkTracker.pushSample(/*timestamp=*/1, 25, 53);
jerkTracker.pushSample(/*timestamp=*/2, 30, 60);
@@ -118,11 +119,14 @@
* y'': 3 -> -15
* y''': -18
*/
- EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), std::hypot(-50, -18));
+ const float newJerk = (1 - jerkTracker.getForgetFactor()) * std::hypot(10, -1) +
+ jerkTracker.getForgetFactor() * std::hypot(-50, -18);
+ EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), newJerk);
}
TEST(JerkTrackerTest, JerkCalculationNormalizedDtFalse) {
JerkTracker jerkTracker(false);
+ jerkTracker.setForgetFactor(.5);
jerkTracker.pushSample(/*timestamp=*/0, 20, 50);
jerkTracker.pushSample(/*timestamp=*/10, 25, 53);
jerkTracker.pushSample(/*timestamp=*/20, 30, 60);
@@ -153,7 +157,9 @@
* y'': .03 -> -.125 (delta above, divide by 10)
* y''': -.0155 (delta above, divide by 10)
*/
- EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), std::hypot(-.0375, -.0155));
+ const float newJerk = (1 - jerkTracker.getForgetFactor()) * std::hypot(.01, -.001) +
+ jerkTracker.getForgetFactor() * std::hypot(-.0375, -.0155);
+ EXPECT_FLOAT_EQ(jerkTracker.jerkMagnitude().value(), newJerk);
}
TEST(JerkTrackerTest, JerkCalculationAfterReset) {
@@ -291,15 +297,19 @@
MotionPredictor predictor(/*predictionTimestampOffsetNanos=*/0,
[]() { return true /*enable prediction*/; });
- // Jerk is medium (1.05 normalized, which is halfway between LOW_JANK and HIGH_JANK)
- predictor.record(getMotionEvent(DOWN, 0, 5.2, 20ms));
- predictor.record(getMotionEvent(MOVE, 0, 11.5, 30ms));
- predictor.record(getMotionEvent(MOVE, 0, 22, 40ms));
- predictor.record(getMotionEvent(MOVE, 0, 37.75, 50ms));
- predictor.record(getMotionEvent(MOVE, 0, 59.8, 60ms));
+ const float mediumJerk =
+ (predictor.getModelConfig().lowJerk + predictor.getModelConfig().highJerk) / 2;
+ const float a = 3; // initial acceleration
+ const float b = 4; // initial velocity
+ const float c = 5; // initial position
+ predictor.record(getMotionEvent(DOWN, 0, c, 20ms));
+ predictor.record(getMotionEvent(MOVE, 0, c + b, 30ms));
+ predictor.record(getMotionEvent(MOVE, 0, c + 2 * b + a, 40ms));
+ predictor.record(getMotionEvent(MOVE, 0, c + 3 * b + 3 * a + mediumJerk, 50ms));
+ predictor.record(getMotionEvent(MOVE, 0, c + 4 * b + 6 * a + 4 * mediumJerk, 60ms));
std::unique_ptr<MotionEvent> predicted = predictor.predict(82 * NSEC_PER_MSEC);
EXPECT_NE(nullptr, predicted);
- // Halfway between LOW_JANK and HIGH_JANK means that half of the predictions
+ // Halfway between LOW_JERK and HIGH_JERK means that half of the predictions
// will be pruned. If model prediction window is close enough to predict()
// call time window, then half of the model predictions (5/2 -> 2) will be
// ouputted.
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 6fcb3a4..d05ff34 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -326,7 +326,7 @@
* COMPOSER_OVERLAY, the system will try to prioritize the buffer receiving
* an overlay plane & avoid caching it in intermediate composition buffers.
*/
- AHARDWAREBUFFER_USAGE_FRONT_BUFFER = 1UL << 32,
+ AHARDWAREBUFFER_USAGE_FRONT_BUFFER = 1ULL << 32,
AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28,
AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29,
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index d246870..59b0656 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -729,8 +729,7 @@
const auto externalTexture =
std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine,
impl::ExternalTexture::Usage::READABLE);
- std::vector<const std::shared_ptr<ExternalTexture>> textures =
- {srcTexture, externalTexture};
+ std::vector<std::shared_ptr<ExternalTexture>> textures = {srcTexture, externalTexture};
// Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
// It doesn't have to be f16, but it can't be the usual 8888.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6c4870f..5ed4e69 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -901,6 +901,24 @@
const nsecs_t mProcessingTimestamp;
};
+/**
+ * This is needed to help use "InputEventInjectionResult" with base::Result.
+ */
+template <typename T>
+struct EnumErrorWrapper {
+ T mVal;
+ EnumErrorWrapper(T&& e) : mVal(std::forward<T>(e)) {}
+ operator const T&() const { return mVal; }
+ T value() const { return mVal; }
+ std::string print() const { return ftl::enum_string(mVal); }
+};
+
+Error<EnumErrorWrapper<InputEventInjectionResult>> injectionError(InputEventInjectionResult&& e) {
+ LOG_ALWAYS_FATAL_IF(e == InputEventInjectionResult::SUCCEEDED);
+ return Error<EnumErrorWrapper<InputEventInjectionResult>>(
+ std::forward<InputEventInjectionResult>(e));
+}
+
} // namespace
// --- InputDispatcher ---
@@ -1929,20 +1947,21 @@
}
// Identify targets.
- InputEventInjectionResult injectionResult;
- sp<WindowInfoHandle> focusedWindow =
- findFocusedWindowTargetLocked(currentTime, *entry, nextWakeupTime,
- /*byref*/ injectionResult);
- if (injectionResult == InputEventInjectionResult::PENDING) {
- return false;
- }
+ Result<sp<WindowInfoHandle>, InputEventInjectionResult> result =
+ findFocusedWindowTargetLocked(currentTime, *entry, nextWakeupTime);
- setInjectionResult(*entry, injectionResult);
- if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
+ if (!result.ok()) {
+ if (result.error().code() == InputEventInjectionResult::PENDING) {
+ return false;
+ }
+ setInjectionResult(*entry, result.error().code());
return true;
}
+ sp<WindowInfoHandle>& focusedWindow = *result;
LOG_ALWAYS_FATAL_IF(focusedWindow == nullptr);
+ setInjectionResult(*entry, InputEventInjectionResult::SUCCEEDED);
+
std::vector<InputTarget> inputTargets;
addWindowTargetLocked(focusedWindow, InputTarget::DispatchMode::AS_IS,
InputTarget::Flags::FOREGROUND, getDownTime(*entry), inputTargets);
@@ -2047,19 +2066,28 @@
pilferPointersLocked(mDragState->dragWindow->getToken());
}
- inputTargets =
- findTouchedWindowTargetsLocked(currentTime, *entry, /*byref*/ injectionResult);
- LOG_ALWAYS_FATAL_IF(injectionResult != InputEventInjectionResult::SUCCEEDED &&
- !inputTargets.empty());
+ Result<std::vector<InputTarget>, InputEventInjectionResult> result =
+ findTouchedWindowTargetsLocked(currentTime, *entry);
+
+ if (result.ok()) {
+ inputTargets = std::move(*result);
+ injectionResult = InputEventInjectionResult::SUCCEEDED;
+ } else {
+ injectionResult = result.error().code();
+ }
} else {
// Non touch event. (eg. trackball)
- sp<WindowInfoHandle> focusedWindow =
- findFocusedWindowTargetLocked(currentTime, *entry, nextWakeupTime, injectionResult);
- if (injectionResult == InputEventInjectionResult::SUCCEEDED) {
+ Result<sp<WindowInfoHandle>, InputEventInjectionResult> result =
+ findFocusedWindowTargetLocked(currentTime, *entry, nextWakeupTime);
+ if (result.ok()) {
+ sp<WindowInfoHandle>& focusedWindow = *result;
LOG_ALWAYS_FATAL_IF(focusedWindow == nullptr);
addWindowTargetLocked(focusedWindow, InputTarget::DispatchMode::AS_IS,
InputTarget::Flags::FOREGROUND, getDownTime(*entry),
inputTargets);
+ injectionResult = InputEventInjectionResult::SUCCEEDED;
+ } else {
+ injectionResult = result.error().code();
}
}
if (injectionResult == InputEventInjectionResult::PENDING) {
@@ -2266,11 +2294,9 @@
return false;
}
-sp<WindowInfoHandle> InputDispatcher::findFocusedWindowTargetLocked(
- nsecs_t currentTime, const EventEntry& entry, nsecs_t& nextWakeupTime,
- InputEventInjectionResult& outInjectionResult) {
- outInjectionResult = InputEventInjectionResult::FAILED; // Default result
-
+Result<sp<WindowInfoHandle>, InputEventInjectionResult>
+InputDispatcher::findFocusedWindowTargetLocked(nsecs_t currentTime, const EventEntry& entry,
+ nsecs_t& nextWakeupTime) {
ui::LogicalDisplayId displayId = getTargetDisplayId(entry);
sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
std::shared_ptr<InputApplicationHandle> focusedApplicationHandle =
@@ -2282,12 +2308,12 @@
ALOGI("Dropping %s event because there is no focused window or focused application in "
"display %s.",
ftl::enum_string(entry.type).c_str(), displayId.toString().c_str());
- return nullptr;
+ return injectionError(InputEventInjectionResult::FAILED);
}
// Drop key events if requested by input feature
if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) {
- return nullptr;
+ return injectionError(InputEventInjectionResult::FAILED);
}
// Compatibility behavior: raise ANR if there is a focused application, but no focused window.
@@ -2307,17 +2333,15 @@
"window when it finishes starting up. Will wait for %" PRId64 "ms",
mAwaitedFocusedApplication->getName().c_str(), millis(timeout));
nextWakeupTime = std::min(nextWakeupTime, *mNoFocusedWindowTimeoutTime);
- outInjectionResult = InputEventInjectionResult::PENDING;
- return nullptr;
+ return injectionError(InputEventInjectionResult::PENDING);
} else if (currentTime > *mNoFocusedWindowTimeoutTime) {
// Already raised ANR. Drop the event
ALOGE("Dropping %s event because there is no focused window",
ftl::enum_string(entry.type).c_str());
- return nullptr;
+ return injectionError(InputEventInjectionResult::FAILED);
} else {
// Still waiting for the focused window
- outInjectionResult = InputEventInjectionResult::PENDING;
- return nullptr;
+ return injectionError(InputEventInjectionResult::PENDING);
}
}
@@ -2327,15 +2351,13 @@
// Verify targeted injection.
if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) {
ALOGW("Dropping injected event: %s", (*err).c_str());
- outInjectionResult = InputEventInjectionResult::TARGET_MISMATCH;
- return nullptr;
+ return injectionError(InputEventInjectionResult::TARGET_MISMATCH);
}
if (focusedWindowHandle->getInfo()->inputConfig.test(
WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
- outInjectionResult = InputEventInjectionResult::PENDING;
- return nullptr;
+ return injectionError(InputEventInjectionResult::PENDING);
}
// If the event is a key event, then we must wait for all previous events to
@@ -2352,12 +2374,10 @@
if (entry.type == EventEntry::Type::KEY) {
if (shouldWaitToSendKeyLocked(currentTime, focusedWindowHandle->getName().c_str())) {
nextWakeupTime = std::min(nextWakeupTime, *mKeyIsWaitingForEventsTimeout);
- outInjectionResult = InputEventInjectionResult::PENDING;
- return nullptr;
+ return injectionError(InputEventInjectionResult::PENDING);
}
}
-
- outInjectionResult = InputEventInjectionResult::SUCCEEDED;
+ // Success!
return focusedWindowHandle;
}
@@ -2381,9 +2401,8 @@
return responsiveMonitors;
}
-std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked(
- nsecs_t currentTime, const MotionEntry& entry,
- InputEventInjectionResult& outInjectionResult) {
+base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult>
+InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry) {
ATRACE_CALL();
std::vector<InputTarget> targets;
@@ -2393,9 +2412,6 @@
const int32_t action = entry.action;
const int32_t maskedAction = MotionEvent::getActionMasked(action);
- // Update the touch state as needed based on the properties of the touch event.
- outInjectionResult = InputEventInjectionResult::PENDING;
-
// Copy current touch state into tempTouchState.
// This state will be used to update mTouchStatesByDisplay at the end of this function.
// If no state for the specified display exists, then our initial state will be empty.
@@ -2435,8 +2451,7 @@
// Started hovering, but the device is already down: reject the hover event
LOG(ERROR) << "Got hover event " << entry.getDescription()
<< " but the device is already down " << oldState->dump();
- outInjectionResult = InputEventInjectionResult::FAILED;
- return {};
+ return injectionError(InputEventInjectionResult::FAILED);
}
// For hover actions, we will treat 'tempTouchState' as a new state, so let's erase
// all of the existing hovering pointers and recompute.
@@ -2468,9 +2483,7 @@
// Verify targeted injection.
if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
ALOGW("Dropping injected touch event: %s", (*err).c_str());
- outInjectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
- newTouchedWindowHandle = nullptr;
- return {};
+ return injectionError(InputEventInjectionResult::TARGET_MISMATCH);
}
// Figure out whether splitting will be allowed for this window.
@@ -2502,8 +2515,7 @@
if (newTouchedWindows.empty()) {
LOG(INFO) << "Dropping event because there is no touchable window at (" << x << ", "
<< y << ") on display " << displayId << ": " << entry;
- outInjectionResult = InputEventInjectionResult::FAILED;
- return {};
+ return injectionError(InputEventInjectionResult::FAILED);
}
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
@@ -2603,8 +2615,7 @@
<< " is not down or we previously dropped the pointer down event in "
<< "display " << displayId << ": " << entry.getDescription();
}
- outInjectionResult = InputEventInjectionResult::FAILED;
- return {};
+ return injectionError(InputEventInjectionResult::FAILED);
}
// If the pointer is not currently hovering, then ignore the event.
@@ -2615,8 +2626,7 @@
LOG(INFO) << "Dropping event because the hovering pointer is not in any windows in "
"display "
<< displayId << ": " << entry.getDescription();
- outInjectionResult = InputEventInjectionResult::FAILED;
- return {};
+ return injectionError(InputEventInjectionResult::FAILED);
}
tempTouchState.removeHoveringPointer(entry.deviceId, pointerId);
}
@@ -2637,8 +2647,7 @@
// Verify targeted injection.
if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
ALOGW("Dropping injected event: %s", (*err).c_str());
- outInjectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
- return {};
+ return injectionError(InputEventInjectionResult::TARGET_MISMATCH);
}
// Do not slide events to the window which can not receive motion event
@@ -2707,6 +2716,9 @@
if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
continue;
}
+ if (!touchedWindow.hasTouchingPointers(entry.deviceId)) {
+ continue;
+ }
touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers);
}
}
@@ -2738,8 +2750,7 @@
ALOGW("Dropping targeted injection: At least one touched window is not owned by uid "
"%s:%s",
entry.injectionState->targetUid->toString().c_str(), errs.c_str());
- outInjectionResult = InputEventInjectionResult::TARGET_MISMATCH;
- return {};
+ return injectionError(InputEventInjectionResult::TARGET_MISMATCH);
}
}
@@ -2796,8 +2807,7 @@
if (targets.empty()) {
LOG(INFO) << "Dropping event because no targets were found: " << entry.getDescription();
- outInjectionResult = InputEventInjectionResult::FAILED;
- return {};
+ return injectionError(InputEventInjectionResult::FAILED);
}
// If we only have windows getting ACTION_OUTSIDE, then drop the event, because there is no
@@ -2807,12 +2817,9 @@
})) {
LOG(INFO) << "Dropping event because all windows would just receive ACTION_OUTSIDE: "
<< entry.getDescription();
- outInjectionResult = InputEventInjectionResult::FAILED;
- return {};
+ return injectionError(InputEventInjectionResult::FAILED);
}
- outInjectionResult = InputEventInjectionResult::SUCCEEDED;
-
// Now that we have generated all of the input targets for this event, reset the dispatch
// mode for all touched window to AS_IS.
for (TouchedWindow& touchedWindow : tempTouchState.windows) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 2125226..3c2f3e9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -537,12 +537,11 @@
void resetNoFocusedWindowTimeoutLocked() REQUIRES(mLock);
ui::LogicalDisplayId getTargetDisplayId(const EventEntry& entry);
- sp<android::gui::WindowInfoHandle> findFocusedWindowTargetLocked(
- nsecs_t currentTime, const EventEntry& entry, nsecs_t& nextWakeupTime,
- android::os::InputEventInjectionResult& outInjectionResult) REQUIRES(mLock);
- std::vector<InputTarget> findTouchedWindowTargetsLocked(
- nsecs_t currentTime, const MotionEntry& entry,
- android::os::InputEventInjectionResult& outInjectionResult) REQUIRES(mLock);
+ base::Result<sp<android::gui::WindowInfoHandle>, android::os::InputEventInjectionResult>
+ findFocusedWindowTargetLocked(nsecs_t currentTime, const EventEntry& entry,
+ nsecs_t& nextWakeupTime) REQUIRES(mLock);
+ base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult>
+ findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry) REQUIRES(mLock);
std::vector<Monitor> selectResponsiveMonitorsLocked(
const std::vector<Monitor>& gestureMonitors) const REQUIRES(mLock);
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 65e0429..b2fd391 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -78,6 +78,7 @@
"PropertyProvider_test.cpp",
"RotaryEncoderInputMapper_test.cpp",
"SlopController_test.cpp",
+ "SwitchInputMapper_test.cpp",
"SyncQueue_test.cpp",
"TimerProvider_test.cpp",
"TestInputListener.cpp",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 4e662d4..9ad3de0 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5659,6 +5659,72 @@
rightWindow->assertNoEvents();
}
+/**
+ * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a
+ * down event to the right window. Device B sends a down event to the left window, and then a
+ * POINTER_DOWN event to the right window. However, since the left window prevents splitting, the
+ * POINTER_DOWN event should only go to the left window, and not to the right window.
+ * This test attempts to reproduce a crash.
+ */
+TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> leftWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left window (prevent splitting)",
+ ui::LogicalDisplayId::DEFAULT);
+ leftWindow->setFrame(Rect(0, 0, 100, 100));
+ leftWindow->setPreventSplitting(true);
+
+ sp<FakeWindowHandle> rightWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
+ ui::LogicalDisplayId::DEFAULT);
+ rightWindow->setFrame(Rect(100, 0, 200, 100));
+
+ mDispatcher->onWindowInfosChanged(
+ {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
+
+ const DeviceId deviceA = 9;
+ const DeviceId deviceB = 3;
+ // Touch the right window with device A
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
+ .deviceId(deviceA)
+ .build());
+ rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
+ // Touch the left window with device B
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .deviceId(deviceB)
+ .build());
+ leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
+ // Send a second pointer from device B to the right window. It shouldn't go to the right window
+ // because the left window prevents splitting.
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceB)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
+ .build());
+ leftWindow->consumeMotionPointerDown(1, WithDeviceId(deviceB));
+
+ // Finish the gesture for both devices
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceB)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
+ .build());
+ leftWindow->consumeMotionPointerUp(1, WithDeviceId(deviceB));
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .deviceId(deviceB)
+ .build());
+ leftWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB), WithPointerId(0, 0)));
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
+ .deviceId(deviceA)
+ .build());
+ rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA)));
+}
+
TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp
index 5722444..e773f58 100644
--- a/services/inputflinger/tests/InputMapperTest.cpp
+++ b/services/inputflinger/tests/InputMapperTest.cpp
@@ -89,6 +89,13 @@
}
}
+void InputMapperUnitTest::setSwitchState(int32_t state, std::set<int32_t> switchCodes) {
+ for (const auto& switchCode : switchCodes) {
+ EXPECT_CALL(mMockEventHub, getSwitchState(EVENTHUB_ID, switchCode))
+ .WillRepeatedly(testing::Return(static_cast<int>(state)));
+ }
+}
+
std::list<NotifyArgs> InputMapperUnitTest::process(int32_t type, int32_t code, int32_t value) {
nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
return process(when, type, code, value);
diff --git a/services/inputflinger/tests/InputMapperTest.h b/services/inputflinger/tests/InputMapperTest.h
index 5bd8cda..88057dc 100644
--- a/services/inputflinger/tests/InputMapperTest.h
+++ b/services/inputflinger/tests/InputMapperTest.h
@@ -58,6 +58,8 @@
void setKeyCodeState(KeyState state, std::set<int> keyCodes);
+ void setSwitchState(int32_t state, std::set<int32_t> switchCodes);
+
std::list<NotifyArgs> process(int32_t type, int32_t code, int32_t value);
std::list<NotifyArgs> process(nsecs_t when, int32_t type, int32_t code, int32_t value);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 1ba79a9..0b780be 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -31,7 +31,6 @@
#include <PeripheralController.h>
#include <SensorInputMapper.h>
#include <SingleTouchInputMapper.h>
-#include <SwitchInputMapper.h>
#include <TestEventMatchers.h>
#include <TestInputListener.h>
#include <TouchInputMapper.h>
@@ -3063,48 +3062,6 @@
mapper.assertProcessWasCalled();
}
-// --- SwitchInputMapperTest ---
-
-class SwitchInputMapperTest : public InputMapperTest {
-protected:
-};
-
-TEST_F(SwitchInputMapperTest, GetSources) {
- SwitchInputMapper& mapper = constructAndAddMapper<SwitchInputMapper>();
-
- ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper.getSources());
-}
-
-TEST_F(SwitchInputMapperTest, GetSwitchState) {
- SwitchInputMapper& mapper = constructAndAddMapper<SwitchInputMapper>();
-
- mFakeEventHub->setSwitchState(EVENTHUB_ID, SW_LID, 1);
- ASSERT_EQ(1, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
-
- mFakeEventHub->setSwitchState(EVENTHUB_ID, SW_LID, 0);
- ASSERT_EQ(0, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
-}
-
-TEST_F(SwitchInputMapperTest, Process) {
- SwitchInputMapper& mapper = constructAndAddMapper<SwitchInputMapper>();
- std::list<NotifyArgs> out;
- out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_LID, 1);
- ASSERT_TRUE(out.empty());
- out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_JACK_PHYSICAL_INSERT, 1);
- ASSERT_TRUE(out.empty());
- out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_HEADPHONE_INSERT, 0);
- ASSERT_TRUE(out.empty());
- out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
- ASSERT_EQ(1u, out.size());
- const NotifySwitchArgs& args = std::get<NotifySwitchArgs>(*out.begin());
- ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
- ASSERT_EQ((1U << SW_LID) | (1U << SW_JACK_PHYSICAL_INSERT), args.switchValues);
- ASSERT_EQ((1U << SW_LID) | (1U << SW_JACK_PHYSICAL_INSERT) | (1 << SW_HEADPHONE_INSERT),
- args.switchMask);
- ASSERT_EQ(uint32_t(0), args.policyFlags);
-}
-
// --- VibratorInputMapperTest ---
class VibratorInputMapperTest : public InputMapperTest {
protected:
diff --git a/services/inputflinger/tests/SwitchInputMapper_test.cpp b/services/inputflinger/tests/SwitchInputMapper_test.cpp
new file mode 100644
index 0000000..4020e78
--- /dev/null
+++ b/services/inputflinger/tests/SwitchInputMapper_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SwitchInputMapper.h"
+
+#include <list>
+#include <variant>
+
+#include <NotifyArgs.h>
+#include <gtest/gtest.h>
+#include <input/Input.h>
+#include <linux/input-event-codes.h>
+
+#include "InputMapperTest.h"
+#include "TestConstants.h"
+
+namespace android {
+
+class SwitchInputMapperTest : public InputMapperUnitTest {
+protected:
+ void SetUp() override {
+ InputMapperUnitTest::SetUp();
+ createDevice();
+ mMapper = createInputMapper<SwitchInputMapper>(*mDeviceContext,
+ mFakePolicy->getReaderConfiguration());
+ }
+};
+
+TEST_F(SwitchInputMapperTest, GetSources) {
+ ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mMapper->getSources());
+}
+
+TEST_F(SwitchInputMapperTest, GetSwitchState) {
+ setSwitchState(1, {SW_LID});
+ ASSERT_EQ(1, mMapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
+
+ setSwitchState(0, {SW_LID});
+ ASSERT_EQ(0, mMapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
+}
+
+TEST_F(SwitchInputMapperTest, Process) {
+ std::list<NotifyArgs> out;
+ out = process(ARBITRARY_TIME, EV_SW, SW_LID, 1);
+ ASSERT_TRUE(out.empty());
+ out = process(ARBITRARY_TIME, EV_SW, SW_JACK_PHYSICAL_INSERT, 1);
+ ASSERT_TRUE(out.empty());
+ out = process(ARBITRARY_TIME, EV_SW, SW_HEADPHONE_INSERT, 0);
+ ASSERT_TRUE(out.empty());
+ out = process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ ASSERT_EQ(1u, out.size());
+ const NotifySwitchArgs& args = std::get<NotifySwitchArgs>(*out.begin());
+ ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
+ ASSERT_EQ((1U << SW_LID) | (1U << SW_JACK_PHYSICAL_INSERT), args.switchValues);
+ ASSERT_EQ((1U << SW_LID) | (1U << SW_JACK_PHYSICAL_INSERT) | (1 << SW_HEADPHONE_INSERT),
+ args.switchMask);
+ ASSERT_EQ(uint32_t(0), args.policyFlags);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
index 6be6735..9c0e072 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
@@ -92,15 +92,15 @@
}
private:
- std::vector<const LayerState> copyLayers(const std::vector<const LayerState*>& layers) {
- std::vector<const LayerState> copiedLayers;
+ std::vector<LayerState> copyLayers(const std::vector<const LayerState*>& layers) {
+ std::vector<LayerState> copiedLayers;
copiedLayers.reserve(layers.size());
std::transform(layers.cbegin(), layers.cend(), std::back_inserter(copiedLayers),
[](const LayerState* layerState) { return *layerState; });
return copiedLayers;
}
- std::vector<const LayerState> mLayers;
+ std::vector<LayerState> mLayers;
// TODO(b/180976743): Tune kMaxDifferingFields
constexpr static int kMaxDifferingFields = 6;
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 30b8eee..0d2987c 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -331,6 +331,7 @@
TransactionTraceWriter::getInstance().invoke("DuplicateLayer", /* overwrite= */ false);
return;
}
+ mVisitedLayers.insert(snapshot->uniqueSequence);
LayerProtoHelper::writeSnapshotToProto(layerProto, layer, *snapshot, mTraceFlags);
for (const auto& [child, variant] : root.mChildren) {
diff --git a/services/surfaceflinger/LocklessQueue.h b/services/surfaceflinger/LocklessQueue.h
index 6b63360..4d0b261 100644
--- a/services/surfaceflinger/LocklessQueue.h
+++ b/services/surfaceflinger/LocklessQueue.h
@@ -15,11 +15,11 @@
*/
#pragma once
+
#include <atomic>
#include <optional>
-template <typename T>
-// Single consumer multi producer stack. We can understand the two operations independently to see
+// Single consumer multi producer queue. We can understand the two operations independently to see
// why they are without race condition.
//
// push is responsible for maintaining a linked list stored in mPush, and called from multiple
@@ -36,33 +36,27 @@
// then store the list and pop one element.
//
// If we already had something in the pop list we just pop directly.
+template <typename T>
class LocklessQueue {
public:
- class Entry {
- public:
- T mValue;
- std::atomic<Entry*> mNext;
- Entry(T value) : mValue(value) {}
- };
- std::atomic<Entry*> mPush = nullptr;
- std::atomic<Entry*> mPop = nullptr;
bool isEmpty() { return (mPush.load() == nullptr) && (mPop.load() == nullptr); }
void push(T value) {
- Entry* entry = new Entry(value);
+ Entry* entry = new Entry(std::move(value));
Entry* previousHead = mPush.load(/*std::memory_order_relaxed*/);
do {
entry->mNext = previousHead;
} while (!mPush.compare_exchange_weak(previousHead, entry)); /*std::memory_order_release*/
}
+
std::optional<T> pop() {
Entry* popped = mPop.load(/*std::memory_order_acquire*/);
if (popped) {
// Single consumer so this is fine
mPop.store(popped->mNext /* , std::memory_order_release */);
- auto value = popped->mValue;
+ auto value = std::move(popped->mValue);
delete popped;
- return std::move(value);
+ return value;
} else {
Entry* grabbedList = mPush.exchange(nullptr /* , std::memory_order_acquire */);
if (!grabbedList) return std::nullopt;
@@ -74,9 +68,19 @@
grabbedList = next;
}
mPop.store(popped /* , std::memory_order_release */);
- auto value = grabbedList->mValue;
+ auto value = std::move(grabbedList->mValue);
delete grabbedList;
- return std::move(value);
+ return value;
}
}
+
+private:
+ class Entry {
+ public:
+ T mValue;
+ std::atomic<Entry*> mNext;
+ Entry(T value) : mValue(value) {}
+ };
+ std::atomic<Entry*> mPush = nullptr;
+ std::atomic<Entry*> mPop = nullptr;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index fbd788b..0dffa4b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -117,10 +117,10 @@
}
}
-void Scheduler::setPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) {
+void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) {
demotePacesetterDisplay();
- promotePacesetterDisplay(pacesetterIdOpt);
+ promotePacesetterDisplay(pacesetterId);
}
void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
@@ -917,22 +917,22 @@
return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides);
}
-void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) {
+void Scheduler::promotePacesetterDisplay(PhysicalDisplayId pacesetterId) {
std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
{
std::scoped_lock lock(mDisplayLock);
- pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterIdOpt);
+ pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterId);
}
applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}
std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked(
- std::optional<PhysicalDisplayId> pacesetterIdOpt) {
- // TODO(b/241286431): Choose the pacesetter display.
- mPacesetterDisplayId = pacesetterIdOpt.value_or(mDisplays.begin()->first);
- ALOGI("Display %s is the pacesetter", to_string(*mPacesetterDisplayId).c_str());
+ PhysicalDisplayId pacesetterId) {
+ // TODO: b/241286431 - Choose the pacesetter among mDisplays.
+ mPacesetterDisplayId = pacesetterId;
+ ALOGI("Display %s is the pacesetter", to_string(pacesetterId).c_str());
std::shared_ptr<VsyncSchedule> newVsyncSchedulePtr;
if (const auto pacesetterOpt = pacesetterDisplayLocked()) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 1a4aa79..4dba6fc 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -92,8 +92,8 @@
void startTimers();
- // TODO(b/241285191): Remove this API by promoting pacesetter in onScreen{Acquired,Released}.
- void setPacesetterDisplay(std::optional<PhysicalDisplayId>) REQUIRES(kMainThreadContext)
+ // TODO: b/241285191 - Remove this API by promoting pacesetter in onScreen{Acquired,Released}.
+ void setPacesetterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext)
EXCLUDES(mDisplayLock);
using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>;
@@ -377,10 +377,8 @@
void resyncAllToHardwareVsync(bool allowToEnable) EXCLUDES(mDisplayLock);
void setVsyncConfig(const VsyncConfig&, Period vsyncPeriod);
- // Chooses a pacesetter among the registered displays, unless `pacesetterIdOpt` is specified.
- // The new `mPacesetterDisplayId` is never `std::nullopt`.
- void promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt)
- REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
+ void promotePacesetterDisplay(PhysicalDisplayId pacesetterId) REQUIRES(kMainThreadContext)
+ EXCLUDES(mDisplayLock);
// Changes to the displays (e.g. registering and unregistering) must be made
// while mDisplayLock is locked, and the new pacesetter then must be promoted while
@@ -388,8 +386,7 @@
// MessageQueue and EventThread need to use the new pacesetter's
// VsyncSchedule, and this must happen while mDisplayLock is *not* locked,
// or else we may deadlock with EventThread.
- std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked(
- std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt)
+ std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked(PhysicalDisplayId pacesetterId)
REQUIRES(kMainThreadContext, mDisplayLock);
void applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule>) EXCLUDES(mDisplayLock);
diff --git a/services/surfaceflinger/tests/common/Android.bp b/services/surfaceflinger/tests/common/Android.bp
new file mode 100644
index 0000000..2dfa8af
--- /dev/null
+++ b/services/surfaceflinger/tests/common/Android.bp
@@ -0,0 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_headers {
+ name: "surfaceflinger_tests_common_headers",
+ export_include_dirs: ["."],
+}
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
new file mode 100644
index 0000000..2e5913b
--- /dev/null
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gui/fake/BufferData.h>
+#include <renderengine/mock/FakeExternalTexture.h>
+#include <ui/ShadowSettings.h>
+
+#include <Client.h> // temporarily needed for LayerCreationArgs
+#include <FrontEnd/LayerCreationArgs.h>
+#include <FrontEnd/LayerHierarchy.h>
+#include <FrontEnd/LayerLifecycleManager.h>
+#include <FrontEnd/LayerSnapshotBuilder.h>
+
+namespace android::surfaceflinger::frontend {
+
+class LayerLifecycleManagerHelper {
+public:
+ LayerLifecycleManagerHelper(LayerLifecycleManager& layerLifecycleManager)
+ : mLifecycleManager(layerLifecycleManager) {}
+ ~LayerLifecycleManagerHelper() = default;
+
+ static LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, uint32_t parentId,
+ uint32_t layerIdToMirror) {
+ LayerCreationArgs args(std::make_optional(id));
+ args.name = "testlayer";
+ args.addToRoot = canBeRoot;
+ args.parentId = parentId;
+ args.layerIdToMirror = layerIdToMirror;
+ return args;
+ }
+
+ static LayerCreationArgs createDisplayMirrorArgs(uint32_t id,
+ ui::LayerStack layerStackToMirror) {
+ LayerCreationArgs args(std::make_optional(id));
+ args.name = "testlayer";
+ args.addToRoot = true;
+ args.layerStackToMirror = layerStackToMirror;
+ return args;
+ }
+
+ static std::unique_ptr<RequestedLayerState> rootLayer(uint32_t id) {
+ return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/true,
+ /*parent=*/UNASSIGNED_LAYER_ID,
+ /*mirror=*/UNASSIGNED_LAYER_ID));
+ }
+
+ static std::unique_ptr<RequestedLayerState> childLayer(uint32_t id, uint32_t parentId) {
+ return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/false,
+ parentId,
+ /*mirror=*/UNASSIGNED_LAYER_ID));
+ }
+
+ static std::vector<TransactionState> setZTransaction(uint32_t id, int32_t z) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.z = z;
+ return transactions;
+ }
+
+ void createRootLayer(uint32_t id) {
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ layers.emplace_back(std::make_unique<RequestedLayerState>(
+ createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/UNASSIGNED_LAYER_ID,
+ /*mirror=*/UNASSIGNED_LAYER_ID)));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
+ void createDisplayMirrorLayer(uint32_t id, ui::LayerStack layerStack) {
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ layers.emplace_back(std::make_unique<RequestedLayerState>(
+ createDisplayMirrorArgs(/*id=*/id, layerStack)));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
+ void createLayer(uint32_t id, uint32_t parentId) {
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ layers.emplace_back(std::make_unique<RequestedLayerState>(
+ createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId,
+ /*mirror=*/UNASSIGNED_LAYER_ID)));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
+ std::vector<TransactionState> reparentLayerTransaction(uint32_t id, uint32_t newParentId) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().parentId = newParentId;
+ transactions.back().states.front().state.what = layer_state_t::eReparent;
+ transactions.back().states.front().relativeParentId = UNASSIGNED_LAYER_ID;
+ transactions.back().states.front().layerId = id;
+ return transactions;
+ }
+
+ void reparentLayer(uint32_t id, uint32_t newParentId) {
+ mLifecycleManager.applyTransactions(reparentLayerTransaction(id, newParentId));
+ }
+
+ std::vector<TransactionState> relativeLayerTransaction(uint32_t id, uint32_t relativeParentId) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().relativeParentId = relativeParentId;
+ transactions.back().states.front().state.what = layer_state_t::eRelativeLayerChanged;
+ transactions.back().states.front().layerId = id;
+ return transactions;
+ }
+
+ void reparentRelativeLayer(uint32_t id, uint32_t relativeParentId) {
+ mLifecycleManager.applyTransactions(relativeLayerTransaction(id, relativeParentId));
+ }
+
+ void removeRelativeZ(uint32_t id) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
+ transactions.back().states.front().layerId = id;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setPosition(uint32_t id, float x, float y) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::ePositionChanged;
+ transactions.back().states.front().state.x = x;
+ transactions.back().states.front().state.y = y;
+ transactions.back().states.front().layerId = id;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void mirrorLayer(uint32_t id, uint32_t parentId, uint32_t layerIdToMirror) {
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ layers.emplace_back(std::make_unique<RequestedLayerState>(
+ createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId,
+ /*mirror=*/layerIdToMirror)));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
+ void updateBackgroundColor(uint32_t id, half alpha) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
+ transactions.back().states.front().state.bgColor.a = alpha;
+ transactions.back().states.front().layerId = id;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void destroyLayerHandle(uint32_t id) { mLifecycleManager.onHandlesDestroyed({{id, "test"}}); }
+
+ void setZ(uint32_t id, int32_t z) {
+ mLifecycleManager.applyTransactions(setZTransaction(id, z));
+ }
+
+ void setCrop(uint32_t id, const Rect& crop) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eCropChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.crop = crop;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setFlags(uint32_t id, uint32_t mask, uint32_t flags) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eFlagsChanged;
+ transactions.back().states.front().state.flags = flags;
+ transactions.back().states.front().state.mask = mask;
+ transactions.back().states.front().layerId = id;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setAlpha(uint32_t id, float alpha) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eAlphaChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.color.a = static_cast<half>(alpha);
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void hideLayer(uint32_t id) {
+ setFlags(id, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+ }
+
+ void showLayer(uint32_t id) { setFlags(id, layer_state_t::eLayerHidden, 0); }
+
+ void setColor(uint32_t id, half3 rgb = half3(1._hf, 1._hf, 1._hf)) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eColorChanged;
+ transactions.back().states.front().state.color.rgb = rgb;
+ transactions.back().states.front().layerId = id;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setLayerStack(uint32_t id, int32_t layerStack) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eLayerStackChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.layerStack = ui::LayerStack::fromValue(layerStack);
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setTouchableRegion(uint32_t id, Region region) {
+ 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->token = sp<BBinder>::make();
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setInputInfo(uint32_t id, std::function<void(gui::WindowInfo&)> configureInput) {
+ 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();
+ if (!inputInfo->token) {
+ inputInfo->token = sp<BBinder>::make();
+ }
+ configureInput(*inputInfo);
+
+ 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);
+ }
+
+ void setBackgroundBlurRadius(uint32_t id, uint32_t backgroundBlurRadius) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eBackgroundBlurRadiusChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.backgroundBlurRadius = backgroundBlurRadius;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setFrameRateSelectionPriority(uint32_t id, int32_t priority) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eFrameRateSelectionPriority;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.frameRateSelectionPriority = priority;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setFrameRate(uint32_t id, float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.frameRate = frameRate;
+ transactions.back().states.front().state.frameRateCompatibility = compatibility;
+ transactions.back().states.front().state.changeFrameRateStrategy = changeFrameRateStrategy;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setFrameRateCategory(uint32_t id, int8_t frameRateCategory) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eFrameRateCategoryChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.frameRateCategory = frameRateCategory;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setFrameRateSelectionStrategy(uint32_t id, int8_t strategy) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what =
+ layer_state_t::eFrameRateSelectionStrategyChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.frameRateSelectionStrategy = strategy;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setDefaultFrameRateCompatibility(uint32_t id, int8_t defaultFrameRateCompatibility) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what =
+ layer_state_t::eDefaultFrameRateCompatibilityChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.defaultFrameRateCompatibility =
+ defaultFrameRateCompatibility;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setRoundedCorners(uint32_t id, float radius) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eCornerRadiusChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.cornerRadius = radius;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setBuffer(uint32_t id, std::shared_ptr<renderengine::ExternalTexture> texture) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eBufferChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().externalTexture = texture;
+ transactions.back().states.front().state.bufferData =
+ std::make_shared<fake::BufferData>(texture->getId(), texture->getWidth(),
+ texture->getHeight(), texture->getPixelFormat(),
+ texture->getUsage());
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setBuffer(uint32_t id) {
+ static uint64_t sBufferId = 1;
+ setBuffer(id,
+ std::make_shared<renderengine::mock::
+ FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ sBufferId++,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_PROTECTED /*usage*/));
+ }
+
+ void setBufferCrop(uint32_t id, const Rect& bufferCrop) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eBufferCropChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.bufferCrop = bufferCrop;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setDamageRegion(uint32_t id, const Region& damageRegion) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eSurfaceDamageRegionChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.surfaceDamageRegion = damageRegion;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setDataspace(uint32_t id, ui::Dataspace dataspace) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eDataspaceChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.dataspace = dataspace;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setMatrix(uint32_t id, float dsdx, float dtdx, float dtdy, float dsdy) {
+ layer_state_t::matrix22_t matrix{dsdx, dtdx, dtdy, dsdy};
+
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eMatrixChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.matrix = matrix;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setShadowRadius(uint32_t id, float shadowRadius) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eShadowRadiusChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.shadowRadius = shadowRadius;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setTrustedOverlay(uint32_t id, gui::TrustedOverlay trustedOverlay) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eTrustedOverlayChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.trustedOverlay = trustedOverlay;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setDropInputMode(uint32_t id, gui::DropInputMode dropInputMode) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eDropInputModeChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.dropInputMode = dropInputMode;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+private:
+ LayerLifecycleManager& mLifecycleManager;
+};
+
+} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 518f2a1..9ebef8c 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -58,6 +58,7 @@
],
test_suites: ["device-tests"],
static_libs: ["libc++fs"],
+ header_libs: ["surfaceflinger_tests_common_headers"],
srcs: [
":libsurfaceflinger_mock_sources",
":libsurfaceflinger_sources",
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 8b3303c..37cda3e 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -25,13 +25,15 @@
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
+#include "LayerLifecycleManagerHelper.h"
+
#include "FrontEnd/LayerSnapshotBuilder.h"
namespace android::surfaceflinger::frontend {
-class LayerHierarchyTestBase : public testing::Test {
+class LayerHierarchyTestBase : public testing::Test, public LayerLifecycleManagerHelper {
protected:
- LayerHierarchyTestBase() {
+ LayerHierarchyTestBase() : LayerLifecycleManagerHelper(mLifecycleManager) {
// tree with 3 levels of children
// ROOT
// ├── 1
@@ -55,24 +57,6 @@
createLayer(1221, 122);
}
- LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, uint32_t parentId,
- uint32_t layerIdToMirror) {
- LayerCreationArgs args(std::make_optional(id));
- args.name = "testlayer";
- args.addToRoot = canBeRoot;
- args.parentId = parentId;
- args.layerIdToMirror = layerIdToMirror;
- return args;
- }
-
- LayerCreationArgs createDisplayMirrorArgs(uint32_t id, ui::LayerStack layerStackToMirror) {
- LayerCreationArgs args(std::make_optional(id));
- args.name = "testlayer";
- args.addToRoot = true;
- args.layerStackToMirror = layerStackToMirror;
- return args;
- }
-
std::vector<uint32_t> getTraversalPath(const LayerHierarchy& hierarchy) const {
std::vector<uint32_t> layerIds;
hierarchy.traverse([&layerIds = layerIds](const LayerHierarchy& hierarchy,
@@ -94,98 +78,6 @@
return layerIds;
}
- virtual void createRootLayer(uint32_t id) {
- std::vector<std::unique_ptr<RequestedLayerState>> layers;
- layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/UNASSIGNED_LAYER_ID,
- /*mirror=*/UNASSIGNED_LAYER_ID)));
- mLifecycleManager.addLayers(std::move(layers));
- }
-
- void createDisplayMirrorLayer(uint32_t id, ui::LayerStack layerStack) {
- std::vector<std::unique_ptr<RequestedLayerState>> layers;
- layers.emplace_back(std::make_unique<RequestedLayerState>(
- createDisplayMirrorArgs(/*id=*/id, layerStack)));
- mLifecycleManager.addLayers(std::move(layers));
- }
-
- virtual void createLayer(uint32_t id, uint32_t parentId) {
- std::vector<std::unique_ptr<RequestedLayerState>> layers;
- layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId,
- /*mirror=*/UNASSIGNED_LAYER_ID)));
- mLifecycleManager.addLayers(std::move(layers));
- }
-
- std::vector<TransactionState> reparentLayerTransaction(uint32_t id, uint32_t newParentId) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().parentId = newParentId;
- transactions.back().states.front().state.what = layer_state_t::eReparent;
- transactions.back().states.front().relativeParentId = UNASSIGNED_LAYER_ID;
- transactions.back().states.front().layerId = id;
- return transactions;
- }
-
- void reparentLayer(uint32_t id, uint32_t newParentId) {
- mLifecycleManager.applyTransactions(reparentLayerTransaction(id, newParentId));
- }
-
- std::vector<TransactionState> relativeLayerTransaction(uint32_t id, uint32_t relativeParentId) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().relativeParentId = relativeParentId;
- transactions.back().states.front().state.what = layer_state_t::eRelativeLayerChanged;
- transactions.back().states.front().layerId = id;
- return transactions;
- }
-
- void reparentRelativeLayer(uint32_t id, uint32_t relativeParentId) {
- mLifecycleManager.applyTransactions(relativeLayerTransaction(id, relativeParentId));
- }
-
- void removeRelativeZ(uint32_t id) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- transactions.back().states.front().layerId = id;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setPosition(uint32_t id, float x, float y) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().state.what = layer_state_t::ePositionChanged;
- transactions.back().states.front().state.x = x;
- transactions.back().states.front().state.y = y;
- transactions.back().states.front().layerId = id;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- virtual void mirrorLayer(uint32_t id, uint32_t parentId, uint32_t layerIdToMirror) {
- std::vector<std::unique_ptr<RequestedLayerState>> layers;
- layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId,
- /*mirror=*/layerIdToMirror)));
- mLifecycleManager.addLayers(std::move(layers));
- }
-
- void updateBackgroundColor(uint32_t id, half alpha) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- transactions.back().states.front().state.bgColor.a = alpha;
- transactions.back().states.front().layerId = id;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void destroyLayerHandle(uint32_t id) { mLifecycleManager.onHandlesDestroyed({{id, "test"}}); }
-
void updateAndVerify(LayerHierarchyBuilder& hierarchyBuilder) {
hierarchyBuilder.update(mLifecycleManager);
mLifecycleManager.commitChanges();
@@ -201,321 +93,6 @@
mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
}
- std::vector<TransactionState> setZTransaction(uint32_t id, int32_t z) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.z = z;
- return transactions;
- }
-
- void setZ(uint32_t id, int32_t z) {
- mLifecycleManager.applyTransactions(setZTransaction(id, z));
- }
-
- void setCrop(uint32_t id, const Rect& crop) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eCropChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.crop = crop;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setFlags(uint32_t id, uint32_t mask, uint32_t flags) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eFlagsChanged;
- transactions.back().states.front().state.flags = flags;
- transactions.back().states.front().state.mask = mask;
- transactions.back().states.front().layerId = id;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setAlpha(uint32_t id, float alpha) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eAlphaChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.color.a = static_cast<half>(alpha);
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void hideLayer(uint32_t id) {
- setFlags(id, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
- }
-
- void showLayer(uint32_t id) { setFlags(id, layer_state_t::eLayerHidden, 0); }
-
- void setColor(uint32_t id, half3 rgb = half3(1._hf, 1._hf, 1._hf)) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().state.what = layer_state_t::eColorChanged;
- transactions.back().states.front().state.color.rgb = rgb;
- transactions.back().states.front().layerId = id;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setLayerStack(uint32_t id, int32_t layerStack) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eLayerStackChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.layerStack = ui::LayerStack::fromValue(layerStack);
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setTouchableRegion(uint32_t id, Region region) {
- 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->token = sp<BBinder>::make();
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setInputInfo(uint32_t id, std::function<void(gui::WindowInfo&)> configureInput) {
- 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();
- if (!inputInfo->token) {
- inputInfo->token = sp<BBinder>::make();
- }
- configureInput(*inputInfo);
-
- 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);
- }
-
- void setBackgroundBlurRadius(uint32_t id, uint32_t backgroundBlurRadius) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eBackgroundBlurRadiusChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.backgroundBlurRadius = backgroundBlurRadius;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setFrameRateSelectionPriority(uint32_t id, int32_t priority) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eFrameRateSelectionPriority;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.frameRateSelectionPriority = priority;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setFrameRate(uint32_t id, float frameRate, int8_t compatibility,
- int8_t changeFrameRateStrategy) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.frameRate = frameRate;
- transactions.back().states.front().state.frameRateCompatibility = compatibility;
- transactions.back().states.front().state.changeFrameRateStrategy = changeFrameRateStrategy;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setFrameRateCategory(uint32_t id, int8_t frameRateCategory) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eFrameRateCategoryChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.frameRateCategory = frameRateCategory;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setFrameRateSelectionStrategy(uint32_t id, int8_t strategy) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what =
- layer_state_t::eFrameRateSelectionStrategyChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.frameRateSelectionStrategy = strategy;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setDefaultFrameRateCompatibility(uint32_t id, int8_t defaultFrameRateCompatibility) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what =
- layer_state_t::eDefaultFrameRateCompatibilityChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.defaultFrameRateCompatibility =
- defaultFrameRateCompatibility;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setRoundedCorners(uint32_t id, float radius) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eCornerRadiusChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.cornerRadius = radius;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setBuffer(uint32_t id, std::shared_ptr<renderengine::ExternalTexture> texture) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eBufferChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().externalTexture = texture;
- transactions.back().states.front().state.bufferData =
- std::make_shared<fake::BufferData>(texture->getId(), texture->getWidth(),
- texture->getHeight(), texture->getPixelFormat(),
- texture->getUsage());
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setBuffer(uint32_t id) {
- static uint64_t sBufferId = 1;
- setBuffer(id,
- std::make_shared<renderengine::mock::
- FakeExternalTexture>(1U /*width*/, 1U /*height*/,
- sBufferId++,
- HAL_PIXEL_FORMAT_RGBA_8888,
- GRALLOC_USAGE_PROTECTED /*usage*/));
- }
-
- void setBufferCrop(uint32_t id, const Rect& bufferCrop) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eBufferCropChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.bufferCrop = bufferCrop;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setDamageRegion(uint32_t id, const Region& damageRegion) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eSurfaceDamageRegionChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.surfaceDamageRegion = damageRegion;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setDataspace(uint32_t id, ui::Dataspace dataspace) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eDataspaceChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.dataspace = dataspace;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setMatrix(uint32_t id, float dsdx, float dtdx, float dtdy, float dsdy) {
- layer_state_t::matrix22_t matrix{dsdx, dtdx, dtdy, dsdy};
-
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eMatrixChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.matrix = matrix;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setShadowRadius(uint32_t id, float shadowRadius) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eShadowRadiusChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.shadowRadius = shadowRadius;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setTrustedOverlay(uint32_t id, gui::TrustedOverlay trustedOverlay) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eTrustedOverlayChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.trustedOverlay = trustedOverlay;
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void setDropInputMode(uint32_t id, gui::DropInputMode dropInputMode) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eDropInputModeChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.dropInputMode = dropInputMode;
- mLifecycleManager.applyTransactions(transactions);
- }
-
LayerLifecycleManager mLifecycleManager;
};
@@ -523,21 +100,6 @@
protected:
LayerSnapshotTestBase() : LayerHierarchyTestBase() {}
- void createRootLayer(uint32_t id) override {
- LayerHierarchyTestBase::createRootLayer(id);
- setColor(id);
- }
-
- void createLayer(uint32_t id, uint32_t parentId) override {
- LayerHierarchyTestBase::createLayer(id, parentId);
- setColor(parentId);
- }
-
- void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) override {
- LayerHierarchyTestBase::mirrorLayer(id, parent, layerToMirror);
- setColor(id);
- }
-
void update(LayerSnapshotBuilder& snapshotBuilder) {
mHierarchyBuilder.update(mLifecycleManager);
LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
index bc15dec..b4efe0f 100644
--- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
@@ -61,18 +61,6 @@
class LayerLifecycleManagerTest : public LayerHierarchyTestBase {
protected:
- std::unique_ptr<RequestedLayerState> rootLayer(uint32_t id) {
- return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/true,
- /*parent=*/UNASSIGNED_LAYER_ID,
- /*mirror=*/UNASSIGNED_LAYER_ID));
- }
-
- std::unique_ptr<RequestedLayerState> childLayer(uint32_t id, uint32_t parentId) {
- return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/false,
- parentId,
- /*mirror=*/UNASSIGNED_LAYER_ID));
- }
-
RequestedLayerState* getRequestedLayerState(LayerLifecycleManager& lifecycleManager,
uint32_t layerId) {
return lifecycleManager.getLayerFromId(layerId);