MotionEvent: add safe dumping method
This method should allow us to log more details of an event in case of
validation failures, without potential for infinite recursion in getter
methods.
Bug: 379368465
Test: add a test to MotionEventTest that calls
getHistoricalRawPointerCoords with an invalid pointer index, and
check the logs when run with `atest --host`
Flag: EXEMPT logs only
Change-Id: I9c7084cedbc7e6f6834cd1b401da04d07d22ce35
diff --git a/include/input/Input.h b/include/input/Input.h
index a8684bd..0e330e4 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -994,6 +994,15 @@
std::vector<PointerProperties> mPointerProperties;
std::vector<nsecs_t> mSampleEventTimes;
std::vector<PointerCoords> mSamplePointerCoords;
+
+private:
+ /**
+ * Create a human-readable string representation of the event's data for debugging purposes.
+ *
+ * Unlike operator<<, this method does not assume that the event data is valid or consistent, or
+ * call any accessor methods that might themselves call safeDump in the case of invalid data.
+ */
+ std::string safeDump() const;
};
std::ostream& operator<<(std::ostream& out, const MotionEvent& event);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index b87a706..65a088e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -685,11 +685,12 @@
const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
if (CC_UNLIKELY(pointerIndex < 0 || pointerIndex >= getPointerCount())) {
- LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for " << *this;
+ LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for "
+ << safeDump();
}
const size_t position = getHistorySize() * getPointerCount() + pointerIndex;
if (CC_UNLIKELY(position < 0 || position >= mSamplePointerCoords.size())) {
- LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << *this;
+ LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << safeDump();
}
return &mSamplePointerCoords[position];
}
@@ -705,17 +706,16 @@
const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
size_t pointerIndex, size_t historicalIndex) const {
if (CC_UNLIKELY(pointerIndex < 0 || pointerIndex >= getPointerCount())) {
- LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex
- << "; should be between >0 and ≤" << getPointerCount();
+ LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for "
+ << safeDump();
}
if (CC_UNLIKELY(historicalIndex < 0 || historicalIndex > getHistorySize())) {
- LOG(FATAL) << __func__ << ": Invalid historical index " << historicalIndex
- << "; should be >0 and ≤" << getHistorySize();
+ LOG(FATAL) << __func__ << ": Invalid historical index " << historicalIndex << " for "
+ << safeDump();
}
const size_t position = historicalIndex * getPointerCount() + pointerIndex;
if (CC_UNLIKELY(position < 0 || position >= mSamplePointerCoords.size())) {
- LOG(FATAL) << __func__ << ": Invalid array index " << position << "; should be >0 and ≤"
- << mSamplePointerCoords.size();
+ LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << safeDump();
}
return &mSamplePointerCoords[position];
}
@@ -1146,6 +1146,53 @@
// clang-format on
}
+std::string MotionEvent::safeDump() const {
+ std::stringstream out;
+ // Field names have the m prefix here to make it easy to distinguish safeDump output from
+ // operator<< output in logs.
+ out << "MotionEvent { mAction=" << MotionEvent::actionToString(mAction);
+ if (mActionButton != 0) {
+ out << ", mActionButton=" << mActionButton;
+ }
+ if (mButtonState != 0) {
+ out << ", mButtonState=" << mButtonState;
+ }
+ if (mClassification != MotionClassification::NONE) {
+ out << ", mClassification=" << motionClassificationToString(mClassification);
+ }
+ if (mMetaState != 0) {
+ out << ", mMetaState=" << mMetaState;
+ }
+ if (mFlags != 0) {
+ out << ", mFlags=0x" << std::hex << mFlags << std::dec;
+ }
+ if (mEdgeFlags != 0) {
+ out << ", mEdgeFlags=" << mEdgeFlags;
+ }
+ out << ", mDownTime=" << mDownTime;
+ out << ", mDeviceId=" << mDeviceId;
+ out << ", mSource=" << inputEventSourceToString(mSource);
+ out << ", mDisplayId=" << mDisplayId;
+ out << ", mEventId=0x" << std::hex << mId << std::dec;
+ // Since we're not assuming the data is at all valid, we also limit the number of items that
+ // might be printed from vectors, in case the vector's size field is corrupted.
+ out << ", mPointerProperties=(" << mPointerProperties.size() << ")[";
+ for (size_t i = 0; i < mPointerProperties.size() && i < MAX_POINTERS; i++) {
+ out << (i > 0 ? ", " : "") << mPointerProperties.at(i);
+ }
+ out << "], mSampleEventTimes=(" << mSampleEventTimes.size() << ")[";
+ for (size_t i = 0; i < mSampleEventTimes.size() && i < 256; i++) {
+ out << (i > 0 ? ", " : "") << mSampleEventTimes.at(i);
+ }
+ out << "], mSamplePointerCoords=(" << mSamplePointerCoords.size() << ")[";
+ for (size_t i = 0; i < mSamplePointerCoords.size() && i < MAX_POINTERS; i++) {
+ const PointerCoords& coords = mSamplePointerCoords.at(i);
+ out << (i > 0 ? ", " : "") << "(" << coords.getX() << ", " << coords.getY() << ")";
+ }
+ out << "] }";
+ return out.str();
+}
+
std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction());
if (event.getActionButton() != 0) {