diff options
author | 2024-11-19 18:34:59 +0000 | |
---|---|---|
committer | 2024-11-20 11:24:34 +0000 | |
commit | 2358c1360dee84841d9d405cb0de5fa199fd0cf1 (patch) | |
tree | 0bc01d9083885b911e5ad3b9d2979c8b2ca3a105 | |
parent | ffbd83c6226273ae00781f42e52f485d895ee864 (diff) |
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
-rw-r--r-- | include/input/Input.h | 9 | ||||
-rw-r--r-- | libs/input/Input.cpp | 63 |
2 files changed, 64 insertions, 8 deletions
diff --git a/include/input/Input.h b/include/input/Input.h index a8684bd19b..0e330e453b 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -994,6 +994,15 @@ protected: 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 b87a7068b5..65a088eb6d 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -685,11 +685,12 @@ void MotionEvent::setCursorPosition(float x, float y) { 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 @@ float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const { 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 @@ bool MotionEvent::operator==(const android::MotionEvent& o) const { // 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) { |