Merge "Add AIDL HAL stack traces to bug-reports" into tm-dev
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
index 7c3b29b..0a75278 100644
--- a/include/input/PrintTools.h
+++ b/include/input/PrintTools.h
@@ -58,4 +58,13 @@
const char* toString(bool value);
+/**
+ * Add "prefix" to the beginning of each line in the provided string
+ * "str".
+ * The string 'str' is typically multi-line.
+ * The most common use case for this function is to add some padding
+ * when dumping state.
+ */
+std::string addLinePrefix(std::string str, const std::string& prefix);
+
} // namespace android
\ No newline at end of file
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 63d87da..d8d2cf2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -226,6 +226,10 @@
],
afdo: true,
+
+ header_abi_checker: {
+ diff_flags: ["-allow-adding-removing-weak-symbols"],
+ },
}
cc_defaults {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 501f8cf..47d801a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1497,6 +1497,13 @@
releaseBufferIfOverwriting(*s);
+ if (buffer == nullptr) {
+ s->what &= ~layer_state_t::eBufferChanged;
+ s->bufferData = nullptr;
+ mContainsBuffer = false;
+ return *this;
+ }
+
std::shared_ptr<BufferData> bufferData = std::make_shared<BufferData>();
bufferData->buffer = buffer;
uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber);
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 804ce4f..4e966d1 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -76,7 +76,7 @@
info.inputConfig == inputConfig && info.displayId == displayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
- info.layoutParamsFlags == layoutParamsFlags;
+ info.layoutParamsFlags == layoutParamsFlags && info.isClone == isClone;
}
status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -124,7 +124,8 @@
parcel->write(touchableRegion) ?:
parcel->writeBool(replaceTouchableRegionWithCrop) ?:
parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
- parcel->writeStrongBinder(windowToken);
+ parcel->writeStrongBinder(windowToken) ?:
+ parcel->writeBool(isClone);
// clang-format on
return status;
}
@@ -175,7 +176,8 @@
parcel->read(touchableRegion) ?:
parcel->readBool(&replaceTouchableRegionWithCrop) ?:
parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
- parcel->readNullableStrongBinder(&windowToken);
+ parcel->readNullableStrongBinder(&windowToken) ?:
+ parcel->readBool(&isClone);
// clang-format on
if (status != OK) {
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 0e1d258..169f7f0 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -236,6 +236,8 @@
void setInputConfig(ftl::Flags<InputConfig> config, bool value);
+ bool isClone = false;
+
void addTouchableRegion(const Rect& region);
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index c51b244..99658cc 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -71,6 +71,7 @@
i.applicationInfo.name = "ApplicationFooBar";
i.applicationInfo.token = new BBinder();
i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD;
+ i.isClone = true;
Parcel p;
i.writeToParcel(&p);
@@ -101,6 +102,7 @@
ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
ASSERT_EQ(i.applicationInfo, i2.applicationInfo);
+ ASSERT_EQ(i.isClone, i2.isClone);
}
TEST(InputApplicationInfo, Parcelling) {
diff --git a/libs/input/PrintTools.cpp b/libs/input/PrintTools.cpp
index 5d6ae4e..01f6bf5 100644
--- a/libs/input/PrintTools.cpp
+++ b/libs/input/PrintTools.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "PrintTools"
#include <input/PrintTools.h>
+#include <sstream>
namespace android {
@@ -24,4 +25,20 @@
return value ? "true" : "false";
}
+std::string addLinePrefix(std::string str, const std::string& prefix) {
+ std::stringstream ss;
+ bool newLineStarted = true;
+ for (const auto& ch : str) {
+ if (newLineStarted) {
+ ss << prefix;
+ newLineStarted = false;
+ }
+ if (ch == '\n') {
+ newLineStarted = true;
+ }
+ ss << ch;
+ }
+ return ss.str();
+}
+
} // namespace android
diff --git a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
index 95cfae7..d73fff4 100644
--- a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
+++ b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
@@ -153,11 +153,11 @@
uint32_t uid;
// The start time of the period in nanoseconds. The clock must be
- // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function.
+ // CLOCK_MONOTONIC_RAW, as returned by the ktime_get_raw_ns(void) function.
uint64_t start_time_ns;
// The end time of the period in nanoseconds. The clock must be
- // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function.
+ // CLOCK_MONOTONIC_RAW, as returned by the ktime_get_raw_ns(void) function.
uint64_t end_time_ns;
// The amount of time the GPU was running GPU work for |uid| during the
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 3ea0986..8ce2f35 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -367,7 +367,7 @@
// --- InputClassifier ---
-InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {}
+InputClassifier::InputClassifier(InputListenerInterface& listener) : mQueuedListener(listener) {}
void InputClassifier::onBinderDied(void* cookie) {
InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
@@ -417,55 +417,67 @@
void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
// pass through
- mListener.notifyConfigurationChanged(args);
+ mQueuedListener.notifyConfigurationChanged(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
// pass through
- mListener.notifyKey(args);
+ mQueuedListener.notifyKey(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyMotion(const NotifyMotionArgs* args) {
- std::scoped_lock lock(mLock);
- // MotionClassifier is only used for touch events, for now
- const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args);
- if (!sendToMotionClassifier) {
- mListener.notifyMotion(args);
- return;
- }
-
- NotifyMotionArgs newArgs(*args);
- newArgs.classification = mMotionClassifier->classify(newArgs);
- mListener.notifyMotion(&newArgs);
+ { // acquire lock
+ std::scoped_lock lock(mLock);
+ // MotionClassifier is only used for touch events, for now
+ const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args);
+ if (!sendToMotionClassifier) {
+ mQueuedListener.notifyMotion(args);
+ } else {
+ NotifyMotionArgs newArgs(*args);
+ newArgs.classification = mMotionClassifier->classify(newArgs);
+ mQueuedListener.notifyMotion(&newArgs);
+ }
+ } // release lock
+ mQueuedListener.flush();
}
void InputClassifier::notifySensor(const NotifySensorArgs* args) {
// pass through
- mListener.notifySensor(args);
+ mQueuedListener.notifySensor(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) {
// pass through
- mListener.notifyVibratorState(args);
+ mQueuedListener.notifyVibratorState(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
// pass through
- mListener.notifySwitch(args);
+ mQueuedListener.notifySwitch(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- std::scoped_lock lock(mLock);
- if (mMotionClassifier) {
- mMotionClassifier->reset(*args);
- }
+ { // acquire lock
+ std::scoped_lock lock(mLock);
+ if (mMotionClassifier) {
+ mMotionClassifier->reset(*args);
+ }
+ } // release lock
+
// continue to next stage
- mListener.notifyDeviceReset(args);
+ mQueuedListener.notifyDeviceReset(args);
+ mQueuedListener.flush();
}
void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
// pass through
- mListener.notifyPointerCaptureChanged(args);
+ mQueuedListener.notifyPointerCaptureChanged(args);
+ mQueuedListener.flush();
}
void InputClassifier::setMotionClassifierLocked(
@@ -490,6 +502,10 @@
dump += "\n";
}
+void InputClassifier::monitor() {
+ std::scoped_lock lock(mLock);
+}
+
InputClassifier::~InputClassifier() {
}
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index e2a0bc2..56cf760 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -96,6 +96,9 @@
*/
virtual void dump(std::string& dump) = 0;
+ /* Called by the heatbeat to ensures that the classifier has not deadlocked. */
+ virtual void monitor() = 0;
+
InputClassifierInterface() { }
virtual ~InputClassifierInterface() { }
};
@@ -247,6 +250,7 @@
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
void dump(std::string& dump) override;
+ void monitor() override;
~InputClassifier();
@@ -257,7 +261,7 @@
// Protect access to mMotionClassifier, since it may become null via a hidl callback
std::mutex mLock;
// The next stage to pass input events to
- InputListenerInterface& mListener;
+ QueuedInputListener mQueuedListener;
std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock);
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 7b03631..9767cd9 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -62,8 +62,8 @@
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
- mUnwantedInteractionBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
- mReader = createInputReader(readerPolicy, *mUnwantedInteractionBlocker);
+ mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
+ mReader = createInputReader(readerPolicy, *mBlocker);
}
InputManager::~InputManager() {
@@ -111,7 +111,7 @@
}
UnwantedInteractionBlockerInterface& InputManager::getUnwantedInteractionBlocker() {
- return *mUnwantedInteractionBlocker;
+ return *mBlocker;
}
InputClassifierInterface& InputManager::getClassifier() {
@@ -122,6 +122,13 @@
return *mDispatcher;
}
+void InputManager::monitor() {
+ mReader->monitor();
+ mBlocker->monitor();
+ mClassifier->monitor();
+ mDispatcher->monitor();
+}
+
// Used by tests only.
binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) {
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 35d2b0f..8aad35b 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -90,6 +90,9 @@
/* Gets the input dispatcher. */
virtual InputDispatcherInterface& getDispatcher() = 0;
+
+ /* Check that the input stages have not deadlocked. */
+ virtual void monitor() = 0;
};
class InputManager : public InputManagerInterface, public BnInputFlinger {
@@ -108,6 +111,7 @@
UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() override;
InputClassifierInterface& getClassifier() override;
InputDispatcherInterface& getDispatcher() override;
+ void monitor() override;
status_t dump(int fd, const Vector<String16>& args) override;
binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
@@ -117,7 +121,7 @@
private:
std::unique_ptr<InputReaderInterface> mReader;
- std::unique_ptr<UnwantedInteractionBlockerInterface> mUnwantedInteractionBlocker;
+ std::unique_ptr<UnwantedInteractionBlockerInterface> mBlocker;
std::unique_ptr<InputClassifierInterface> mClassifier;
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index b69e16a..f57ff33 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -18,6 +18,7 @@
#include "UnwantedInteractionBlocker.h"
#include <android-base/stringprintf.h>
+#include <input/PrintTools.h>
#include <inttypes.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
@@ -80,47 +81,6 @@
return MT_TOOL_FINGER;
}
-static std::string addPrefix(std::string str, const std::string& prefix) {
- std::stringstream ss;
- bool newLineStarted = true;
- for (const auto& ch : str) {
- if (newLineStarted) {
- ss << prefix;
- newLineStarted = false;
- }
- if (ch == '\n') {
- newLineStarted = true;
- }
- ss << ch;
- }
- return ss.str();
-}
-
-template <typename T>
-static std::string dumpSet(const std::set<T>& v) {
- static_assert(std::is_integral<T>::value, "Only integral types can be printed.");
- std::string out;
- for (const T& entry : v) {
- out += out.empty() ? "{" : ", ";
- out += android::base::StringPrintf("%i", entry);
- }
- return out.empty() ? "{}" : (out + "}");
-}
-
-template <typename K, typename V>
-static std::string dumpMap(const std::map<K, V>& map) {
- static_assert(std::is_integral<K>::value, "Keys should have integral type to be printed.");
- static_assert(std::is_integral<V>::value, "Values should have integral type to be printed.");
- std::string out;
- for (const auto& [k, v] : map) {
- if (!out.empty()) {
- out += "\n";
- }
- out += android::base::StringPrintf("%i : %i", static_cast<int>(k), static_cast<int>(v));
- }
- return out;
-}
-
static std::string dumpDeviceInfo(const AndroidPalmFilterDeviceInfo& info) {
std::string out;
out += StringPrintf("max_x = %.2f\n", info.max_x);
@@ -168,10 +128,6 @@
return AMOTION_EVENT_ACTION_MOVE;
}
-static const char* toString(bool value) {
- return value ? "true" : "false";
-}
-
std::string toString(const ::ui::InProgressTouchEvdev& touch) {
return StringPrintf("x=%.1f, y=%.1f, tracking_id=%i, slot=%zu,"
" pressure=%.1f, major=%i, minor=%i, "
@@ -356,69 +312,87 @@
UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener,
bool enablePalmRejection)
- : mListener(listener), mEnablePalmRejection(enablePalmRejection) {}
+ : mQueuedListener(listener), mEnablePalmRejection(enablePalmRejection) {}
void UnwantedInteractionBlocker::notifyConfigurationChanged(
const NotifyConfigurationChangedArgs* args) {
- mListener.notifyConfigurationChanged(args);
+ mQueuedListener.notifyConfigurationChanged(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs* args) {
- mListener.notifyKey(args);
+ mQueuedListener.notifyKey(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
- const std::vector<NotifyMotionArgs> processedArgs =
- mPreferStylusOverTouchBlocker.processMotion(*args);
- for (const NotifyMotionArgs& loopArgs : processedArgs) {
- notifyMotionInner(&loopArgs);
- }
+ { // acquire lock
+ std::scoped_lock lock(mLock);
+ const std::vector<NotifyMotionArgs> processedArgs =
+ mPreferStylusOverTouchBlocker.processMotion(*args);
+ for (const NotifyMotionArgs& loopArgs : processedArgs) {
+ notifyMotionLocked(&loopArgs);
+ }
+ } // release lock
+
+ // Call out to the next stage without holding the lock
+ mQueuedListener.flush();
}
-void UnwantedInteractionBlocker::notifyMotionInner(const NotifyMotionArgs* args) {
+void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs* args) {
auto it = mPalmRejectors.find(args->deviceId);
const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source);
if (!sendToPalmRejector) {
- mListener.notifyMotion(args);
+ mQueuedListener.notifyMotion(args);
return;
}
- const std::vector<NotifyMotionArgs> newMotions = it->second.processMotion(*args);
- for (const NotifyMotionArgs& newArgs : newMotions) {
- mListener.notifyMotion(&newArgs);
+ std::vector<NotifyMotionArgs> processedArgs = it->second.processMotion(*args);
+ for (const NotifyMotionArgs& loopArgs : processedArgs) {
+ mQueuedListener.notifyMotion(&loopArgs);
}
}
void UnwantedInteractionBlocker::notifySwitch(const NotifySwitchArgs* args) {
- mListener.notifySwitch(args);
+ mQueuedListener.notifySwitch(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifySensor(const NotifySensorArgs* args) {
- mListener.notifySensor(args);
+ mQueuedListener.notifySensor(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyVibratorState(const NotifyVibratorStateArgs* args) {
- mListener.notifyVibratorState(args);
+ mQueuedListener.notifyVibratorState(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- auto it = mPalmRejectors.find(args->deviceId);
- if (it != mPalmRejectors.end()) {
- AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo();
- // Re-create the object instead of resetting it
- mPalmRejectors.erase(it);
- mPalmRejectors.emplace(args->deviceId, info);
- }
- mListener.notifyDeviceReset(args);
- mPreferStylusOverTouchBlocker.notifyDeviceReset(*args);
+ { // acquire lock
+ std::scoped_lock lock(mLock);
+ auto it = mPalmRejectors.find(args->deviceId);
+ if (it != mPalmRejectors.end()) {
+ AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo();
+ // Re-create the object instead of resetting it
+ mPalmRejectors.erase(it);
+ mPalmRejectors.emplace(args->deviceId, info);
+ }
+ mQueuedListener.notifyDeviceReset(args);
+ mPreferStylusOverTouchBlocker.notifyDeviceReset(*args);
+ } // release lock
+ // Send events to the next stage without holding the lock
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyPointerCaptureChanged(
const NotifyPointerCaptureChangedArgs* args) {
- mListener.notifyPointerCaptureChanged(args);
+ mQueuedListener.notifyPointerCaptureChanged(args);
+ mQueuedListener.flush();
}
void UnwantedInteractionBlocker::notifyInputDevicesChanged(
const std::vector<InputDeviceInfo>& inputDevices) {
+ std::scoped_lock lock(mLock);
if (!mEnablePalmRejection) {
// Palm rejection is disabled. Don't create any palm rejector objects.
return;
@@ -450,20 +424,23 @@
}
void UnwantedInteractionBlocker::dump(std::string& dump) {
+ std::scoped_lock lock(mLock);
dump += "UnwantedInteractionBlocker:\n";
dump += " mPreferStylusOverTouchBlocker:\n";
- dump += addPrefix(mPreferStylusOverTouchBlocker.dump(), " ");
+ dump += addLinePrefix(mPreferStylusOverTouchBlocker.dump(), " ");
dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection));
dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n",
toString(isPalmRejectionEnabled()));
dump += mPalmRejectors.empty() ? " mPalmRejectors: None\n" : " mPalmRejectors:\n";
for (const auto& [deviceId, palmRejector] : mPalmRejectors) {
dump += StringPrintf(" deviceId = %" PRId32 ":\n", deviceId);
- dump += addPrefix(palmRejector.dump(), " ");
+ dump += addLinePrefix(palmRejector.dump(), " ");
}
}
-void UnwantedInteractionBlocker::monitor() {}
+void UnwantedInteractionBlocker::monitor() {
+ std::scoped_lock lock(mLock);
+}
UnwantedInteractionBlocker::~UnwantedInteractionBlocker() {}
@@ -529,9 +506,9 @@
std::string SlotState::dump() const {
std::string out = "mSlotsByPointerId:\n";
- out += addPrefix(dumpMap(mSlotsByPointerId), " ") + "\n";
+ out += addLinePrefix(dumpMap(mSlotsByPointerId), " ") + "\n";
out += "mPointerIdsBySlot:\n";
- out += addPrefix(dumpMap(mPointerIdsBySlot), " ") + "\n";
+ out += addLinePrefix(dumpMap(mPointerIdsBySlot), " ") + "\n";
return out;
}
@@ -689,9 +666,9 @@
std::string PalmRejector::dump() const {
std::string out;
out += "mDeviceInfo:\n";
- out += addPrefix(dumpDeviceInfo(mDeviceInfo), " ");
+ out += addLinePrefix(dumpDeviceInfo(mDeviceInfo), " ");
out += "mSlotState:\n";
- out += addPrefix(mSlotState.dump(), " ");
+ out += addLinePrefix(mSlotState.dump(), " ");
out += "mSuppressedPointerIds: ";
out += dumpSet(mSuppressedPointerIds) + "\n";
return out;
diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h
index 8a1cd72..a433764 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.h
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -19,6 +19,7 @@
#include <map>
#include <set>
+#include <android-base/thread_annotations.h>
#include "include/UnwantedInteractionBlockerInterface.h"
#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h"
#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
@@ -86,18 +87,20 @@
~UnwantedInteractionBlocker();
private:
+ std::mutex mLock;
// The next stage to pass input events to
- InputListenerInterface& mListener;
+
+ QueuedInputListener mQueuedListener;
const bool mEnablePalmRejection;
// When stylus is down, ignore touch
- PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker;
+ PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker GUARDED_BY(mLock);
// Detect and reject unwanted palms on screen
// Use a separate palm rejector for every touch device.
- std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors;
+ std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors GUARDED_BY(mLock);
// TODO(b/210159205): delete this when simultaneous stylus and touch is supported
- void notifyMotionInner(const NotifyMotionArgs* args);
+ void notifyMotionLocked(const NotifyMotionArgs* args) REQUIRES(mLock);
};
class SlotState {
diff --git a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
index 2327266..1a6f847 100644
--- a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
+++ b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
@@ -39,11 +39,11 @@
/**
* Dump the state of the interaction blocker.
- * This method may be called on any thread (usually by the input manager).
+ * This method may be called on any thread (usually by the input manager on a binder thread).
*/
virtual void dump(std::string& dump) = 0;
- /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
+ /* Called by the heatbeat to ensures that the blocker has not deadlocked. */
virtual void monitor() = 0;
UnwantedInteractionBlockerInterface() {}
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index e378096..0062f42 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
#include <gui/constants.h>
#include <linux/input.h>
+#include <thread>
#include "TestInputListener.h"
@@ -547,6 +548,27 @@
mBlocker->notifyMotion(&args);
}
+/**
+ * Call dump, and on another thread, try to send some motions. The blocker should
+ * not crash. On 2022 hardware, this test requires ~ 13K executions (about 20 seconds) to reproduce
+ * the original bug. This is meant to be run with "--gtest_repeat=100000 --gtest_break_on_failure"
+ * options
+ */
+TEST_F(UnwantedInteractionBlockerTest, DumpCanBeAccessedOnAnotherThread) {
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+ mBlocker->notifyMotion(&args1);
+ std::thread dumpThread([this]() {
+ std::string dump;
+ mBlocker->dump(dump);
+ });
+ NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{4, 5, 6}});
+ mBlocker->notifyMotion(&args2);
+ NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{4, 5, 6}});
+ mBlocker->notifyMotion(&args3);
+ dumpThread.join();
+}
+
using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
/**
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 5ffbb7f..742af58 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -416,7 +416,12 @@
if (outputDependentState.overrideInfo.buffer != nullptr) {
displayFrame = outputDependentState.overrideInfo.displayFrame;
- sourceCrop = displayFrame.toFloatRect();
+ sourceCrop =
+ FloatRect(0.f, 0.f,
+ static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
+ ->getWidth()),
+ static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
+ ->getHeight()));
}
ALOGV("Writing display frame [%d, %d, %d, %d]", displayFrame.left, displayFrame.top,
@@ -790,7 +795,7 @@
// framebuffer space of the override buffer to layer space.
const ProjectionSpace& layerSpace = getOutput().getState().layerStackSpace;
const ui::Transform transform = getState().overrideInfo.displaySpace.getTransform(layerSpace);
- const Rect boundaries = transform.transform(getState().overrideInfo.displaySpace.getContent());
+ const Rect boundaries = transform.transform(getState().overrideInfo.displayFrame);
LayerFE::LayerSettings settings;
settings.geometry = renderengine::Geometry{
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 0918510..250f648 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -316,7 +316,7 @@
state.overrideInfo = {
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
- .displayFrame = mNewCachedSet->getBounds(),
+ .displayFrame = mNewCachedSet->getTextureBounds(),
.dataspace = mNewCachedSet->getOutputDataspace(),
.displaySpace = mNewCachedSet->getOutputSpace(),
.damageRegion = Region::INVALID_REGION,
@@ -356,7 +356,7 @@
state.overrideInfo = {
.buffer = currentLayerIter->getBuffer(),
.acquireFence = currentLayerIter->getDrawFence(),
- .displayFrame = currentLayerIter->getBounds(),
+ .displayFrame = currentLayerIter->getTextureBounds(),
.dataspace = currentLayerIter->getOutputDataspace(),
.displaySpace = currentLayerIter->getOutputSpace(),
.damageRegion = Region(),
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 7038e8c..5290bd9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -940,7 +940,7 @@
84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044};
-const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{1002, 1003, 1004, 20044};
+const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{0.f, 0.f, 4.f, 5.f};
const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
Rect{1005, 1006, 1007, 1008}};
const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b1de966..6ed4a94 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2391,6 +2391,7 @@
// 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 (isClone()) {
+ info.isClone = true;
if (const sp<Layer> clonedRoot = getClonedRoot()) {
const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds});
info.touchableRegion = info.touchableRegion.intersect(rect);
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index 16f041a..9c6e56d 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -47,6 +47,7 @@
mInterval(interval),
mResetCallback(resetCallback),
mTimeoutCallback(timeoutCallback) {
+ mLastResetTime = std::chrono::steady_clock::time_point::min();
LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided");
}
@@ -116,9 +117,10 @@
auto triggerTime = mClock->now() + mInterval;
state = TimerState::WAITING;
- while (state == TimerState::WAITING) {
+ while (true) {
+ mWaiting = true;
constexpr auto zero = std::chrono::steady_clock::duration::zero();
- // Wait for mInterval time for semaphore signal.
+ // Wait for mInterval time to check if we need to reset or drop into the idle state.
struct timespec ts;
calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts);
int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
@@ -128,13 +130,21 @@
LOG_ALWAYS_FATAL("%s", ss.str().c_str());
}
+ mWaiting = false;
state = checkForResetAndStop(state);
- if (state == TimerState::RESET) {
- triggerTime = mClock->now() + mInterval;
- state = TimerState::WAITING;
- } else if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) {
+ if (state == TimerState::STOPPED) {
+ break;
+ }
+
+ if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) {
triggerTimeout = true;
state = TimerState::IDLE;
+ break;
+ }
+
+ if (state == TimerState::RESET) {
+ triggerTime = mLastResetTime.load() + mInterval;
+ state = TimerState::WAITING;
}
}
@@ -158,9 +168,14 @@
}
void OneShotTimer::reset() {
+ mLastResetTime = mClock->now();
mResetTriggered = true;
- int result = sem_post(&mSemaphore);
- LOG_ALWAYS_FATAL_IF(result, "sem_post failed");
+ // If mWaiting is true, then we are guaranteed to be in a block where we are waiting on
+ // mSemaphore for a timeout, rather than idling. So we can avoid a sem_post call since we can
+ // just check that we triggered a reset on timeout.
+ if (!mWaiting) {
+ LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
+ }
}
std::string OneShotTimer::dump() const {
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index 09265bb..2017c31 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -103,6 +103,8 @@
// check in the main loop if they were.
std::atomic<bool> mResetTriggered = false;
std::atomic<bool> mStopTriggered = false;
+ std::atomic<bool> mWaiting = false;
+ std::atomic<std::chrono::steady_clock::time_point> mLastResetTime;
};
} // namespace scheduler
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 027a15e..a6d7f58 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -465,4 +465,22 @@
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
+TEST_F(ReleaseBufferCallbackTest, SetBuffer_OverwriteBuffersWithNull) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Create transaction with a buffer.
+ Transaction transaction;
+ transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ releaseCallback->getCallback());
+
+ // Call setBuffer on the same transaction with a null buffer.
+ transaction.setBuffer(layer, nullptr, std::nullopt, 0, releaseCallback->getCallback());
+
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
} // namespace android