Merge "Update dependent properties when deviceType is updated" into main
diff --git a/include/input/Input.h b/include/input/Input.h
index 17672d1..77d7448 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -196,11 +196,11 @@
#define MAX_POINTER_ID 31
/*
- * Number of high resolution mouse scroll units for one detent (mouse wheel click), as defined in
+ * Number of high resolution scroll units for one detent (scroll wheel click), as defined in
* evdev. This is relevant when an input device is emitting REL_WHEEL_HI_RES or REL_HWHEEL_HI_RES
* events.
*/
-constexpr int32_t kEvdevMouseHighResScrollUnitsPerDetent = 120;
+constexpr int32_t kEvdevHighResScrollUnitsPerDetent = 120;
/*
* Declare a concrete type for the NDK's input event forward declaration.
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index 9e48b08..c7b1970 100644
--- a/include/input/InputConsumerNoResampling.h
+++ b/include/input/InputConsumerNoResampling.h
@@ -24,7 +24,7 @@
/**
* An interface to receive batched input events. Even if you don't want batching, you still have to
* use this interface, and some of the events will be batched if your implementation is slow to
- * handle the incoming input.
+ * handle the incoming input. The events received by these callbacks are never null.
*/
class InputConsumerCallbacks {
public:
diff --git a/include/input/VirtualInputDevice.h b/include/input/VirtualInputDevice.h
index 9fbae73..dabe45c 100644
--- a/include/input/VirtualInputDevice.h
+++ b/include/input/VirtualInputDevice.h
@@ -129,6 +129,9 @@
VirtualRotaryEncoder(android::base::unique_fd fd);
virtual ~VirtualRotaryEncoder() override;
bool writeScrollEvent(float scrollAmount, std::chrono::nanoseconds eventTime);
+
+private:
+ int32_t mAccumulatedHighResScrollAmount;
};
} // namespace android
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 6185b7b..c57c9cd 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -441,14 +441,6 @@
return INVALID_OPERATION;
}
-status_t BBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>&) {
- return INVALID_OPERATION;
-}
-
-status_t BBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>&) {
- return INVALID_OPERATION;
-}
-
status_t BBinder::dump(int /*fd*/, const Vector<String16>& /*args*/)
{
return NO_ERROR;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 59c5be7..6594aa6 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -557,14 +557,6 @@
}
}
-status_t BpBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>&) {
- return INVALID_OPERATION;
-}
-
-status_t BpBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>&) {
- return INVALID_OPERATION;
-}
-
void BpBinder::reportOneDeath(const Obituary& obit)
{
sp<DeathRecipient> recipient = obit.recipient.promote();
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 3f70e8c..e8fe555 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1585,10 +1585,15 @@
fdVariant = borrowed_fd(fd);
}
if (!mAllowFds) {
+ ALOGE("FDs are not allowed in this parcel. Both the service and the client must set "
+ "the FileDescriptorTransportMode and agree on the support.");
return FDS_NOT_ALLOWED;
}
switch (rpcFields->mSession->getFileDescriptorTransportMode()) {
case RpcSession::FileDescriptorTransportMode::NONE: {
+ ALOGE("FDs are not allowed in this RpcSession. Both the service and the client "
+ "must set "
+ "the FileDescriptorTransportMode and agree on the support.");
return FDS_NOT_ALLOWED;
}
case RpcSession::FileDescriptorTransportMode::UNIX:
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 802a3bc..135be89 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -50,13 +50,6 @@
void* cookie = nullptr, uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
- // Placeholders to test if adding virtual functions here breaks things.
- // Will be replaced by an actual API once things are verified to work.
- LIBBINDER_EXPORTED virtual status_t addFrozenStateChangeCallback(
- const wp<FrozenStateChangeCallback>& callback);
- LIBBINDER_EXPORTED virtual status_t removeFrozenStateChangeCallback(
- const wp<FrozenStateChangeCallback>& callback);
-
LIBBINDER_EXPORTED virtual void* attachObject(const void* objectID, void* object,
void* cleanupCookie,
object_cleanup_func func) final;
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 0f52f6d..d7f74c4 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -66,12 +66,6 @@
void* cookie = nullptr, uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
- [[nodiscard]] virtual status_t addFrozenStateChangeCallback(
- const wp<FrozenStateChangeCallback>& recipient);
-
- [[nodiscard]] virtual status_t removeFrozenStateChangeCallback(
- const wp<FrozenStateChangeCallback>& recipient);
-
LIBBINDER_EXPORTED virtual void* attachObject(const void* objectID, void* object,
void* cleanupCookie,
object_cleanup_func func) final;
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 62d7354..4eb1c08 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -102,6 +102,10 @@
*/
virtual const String16& getInterfaceDescriptor() const = 0;
+ /**
+ * Last known alive status, from last call. May be arbitrarily stale.
+ * May be incorrect if a service returns an incorrect status code.
+ */
virtual bool isBinderAlive() const = 0;
virtual status_t pingBinder() = 0;
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
@@ -198,14 +202,9 @@
virtual void binderDied(const wp<IBinder>& who) = 0;
};
- class FrozenStateChangeCallback : public virtual RefBase {
- public:
- virtual void onStateChanged(const wp<IBinder>& who, bool isFrozen) = 0;
- };
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
+ #if defined(__clang__)
+ #pragma clang diagnostic pop
+ #endif
/**
* Register the @a recipient for a notification if this binder
@@ -254,12 +253,6 @@
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr) = 0;
- // Placeholders. See Binder.h for details.
- [[nodiscard]] virtual status_t addFrozenStateChangeCallback(
- const wp<FrozenStateChangeCallback>& callback) = 0;
- [[nodiscard]] virtual status_t removeFrozenStateChangeCallback(
- const wp<FrozenStateChangeCallback>& callback) = 0;
-
virtual bool checkSubclass(const void* subclassID) const;
typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
diff --git a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
index cf7dc1a..bfba79f 100644
--- a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
+++ b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
@@ -264,7 +264,7 @@
}
}
- bool getBoolean(const std::string& key, bool* _Nonnull val) {
+ bool getBoolean(const std::string& key, bool* _Nonnull val) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return APersistableBundle_getBoolean(mPBundle, key.c_str(), val);
} else {
@@ -272,7 +272,7 @@
}
}
- bool getInt(const std::string& key, int32_t* _Nonnull val) {
+ bool getInt(const std::string& key, int32_t* _Nonnull val) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return APersistableBundle_getInt(mPBundle, key.c_str(), val);
} else {
@@ -280,7 +280,7 @@
}
}
- bool getLong(const std::string& key, int64_t* _Nonnull val) {
+ bool getLong(const std::string& key, int64_t* _Nonnull val) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return APersistableBundle_getLong(mPBundle, key.c_str(), val);
} else {
@@ -288,7 +288,7 @@
}
}
- bool getDouble(const std::string& key, double* _Nonnull val) {
+ bool getDouble(const std::string& key, double* _Nonnull val) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return APersistableBundle_getDouble(mPBundle, key.c_str(), val);
} else {
@@ -300,7 +300,7 @@
return (char*)malloc(bufferSizeBytes);
}
- bool getString(const std::string& key, std::string* _Nonnull val) {
+ bool getString(const std::string& key, std::string* _Nonnull val) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
char* outString = nullptr;
bool ret = APersistableBundle_getString(mPBundle, key.c_str(), &outString,
@@ -318,7 +318,7 @@
bool getVecInternal(int32_t (*_Nonnull getVec)(const APersistableBundle* _Nonnull,
const char* _Nonnull, T* _Nullable, int32_t),
const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- std::vector<T>* _Nonnull vec) {
+ std::vector<T>* _Nonnull vec) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
int32_t bytes = 0;
// call first with nullptr to get required size in bytes
@@ -340,28 +340,28 @@
return false;
}
- bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) {
+ bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(),
vec);
}
return false;
}
- bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) {
+ bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(),
vec);
}
return false;
}
- bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) {
+ bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(),
vec);
}
return false;
}
- bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) {
+ bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle,
key.c_str(), vec);
@@ -372,7 +372,7 @@
// Takes ownership of and frees the char** and its elements.
// Creates a new set or vector based on the array of char*.
template <typename T>
- T moveStringsInternal(char* _Nullable* _Nonnull strings, int32_t bufferSizeBytes) {
+ T moveStringsInternal(char* _Nullable* _Nonnull strings, int32_t bufferSizeBytes) const {
if (strings && bufferSizeBytes > 0) {
int32_t num = bufferSizeBytes / sizeof(char*);
T ret;
@@ -386,7 +386,7 @@
return T();
}
- bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) {
+ bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0,
&stringAllocator, nullptr);
@@ -403,7 +403,7 @@
return false;
}
- bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) {
+ bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
APersistableBundle* bundle = nullptr;
bool ret = APersistableBundle_getPersistableBundle(mPBundle, key.c_str(), &bundle);
@@ -422,7 +422,7 @@
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable),
- const APersistableBundle* _Nonnull pBundle) {
+ const APersistableBundle* _Nonnull pBundle) const {
// call first with nullptr to get required size in bytes
int32_t bytes = getTypedKeys(pBundle, nullptr, 0, &stringAllocator, nullptr);
if (bytes > 0) {
@@ -435,84 +435,84 @@
return {};
}
- std::set<std::string> getBooleanKeys() {
+ std::set<std::string> getBooleanKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getBooleanKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getIntKeys() {
+ std::set<std::string> getIntKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getIntKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getLongKeys() {
+ std::set<std::string> getLongKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getLongKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getDoubleKeys() {
+ std::set<std::string> getDoubleKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getDoubleKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getStringKeys() {
+ std::set<std::string> getStringKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getStringKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getBooleanVectorKeys() {
+ std::set<std::string> getBooleanVectorKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getBooleanVectorKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getIntVectorKeys() {
+ std::set<std::string> getIntVectorKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getIntVectorKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getLongVectorKeys() {
+ std::set<std::string> getLongVectorKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getLongVectorKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getDoubleVectorKeys() {
+ std::set<std::string> getDoubleVectorKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getDoubleVectorKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getStringVectorKeys() {
+ std::set<std::string> getStringVectorKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getStringVectorKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getPersistableBundleKeys() {
+ std::set<std::string> getPersistableBundleKeys() const {
if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) {
return getKeys(&APersistableBundle_getPersistableBundleKeys, mPBundle);
} else {
return {};
}
}
- std::set<std::string> getMonKeys() {
+ std::set<std::string> getMonKeys() const {
// :P
return {"c(o,o)b", "c(o,o)b"};
}
diff --git a/libs/input/VirtualInputDevice.cpp b/libs/input/VirtualInputDevice.cpp
index 2e3e1a0..0579967 100644
--- a/libs/input/VirtualInputDevice.cpp
+++ b/libs/input/VirtualInputDevice.cpp
@@ -279,13 +279,17 @@
bool VirtualMouse::writeScrollEvent(float xAxisMovement, float yAxisMovement,
std::chrono::nanoseconds eventTime) {
if (!vd_flags::high_resolution_scroll()) {
- return writeInputEvent(EV_REL, REL_HWHEEL, xAxisMovement, eventTime) &&
- writeInputEvent(EV_REL, REL_WHEEL, yAxisMovement, eventTime) &&
+ return writeInputEvent(EV_REL, REL_HWHEEL, static_cast<int32_t>(xAxisMovement),
+ eventTime) &&
+ writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(yAxisMovement),
+ eventTime) &&
writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
}
- const int32_t highResScrollX = xAxisMovement * kEvdevMouseHighResScrollUnitsPerDetent;
- const int32_t highResScrollY = yAxisMovement * kEvdevMouseHighResScrollUnitsPerDetent;
+ const auto highResScrollX =
+ static_cast<int32_t>(xAxisMovement * kEvdevHighResScrollUnitsPerDetent);
+ const auto highResScrollY =
+ static_cast<int32_t>(yAxisMovement * kEvdevHighResScrollUnitsPerDetent);
bool highResScrollResult =
writeInputEvent(EV_REL, REL_HWHEEL_HI_RES, highResScrollX, eventTime) &&
writeInputEvent(EV_REL, REL_WHEEL_HI_RES, highResScrollY, eventTime);
@@ -299,19 +303,19 @@
// (single mouse wheel click).
mAccumulatedHighResScrollX += highResScrollX;
mAccumulatedHighResScrollY += highResScrollY;
- const int32_t scrollX = mAccumulatedHighResScrollX / kEvdevMouseHighResScrollUnitsPerDetent;
- const int32_t scrollY = mAccumulatedHighResScrollY / kEvdevMouseHighResScrollUnitsPerDetent;
+ const int32_t scrollX = mAccumulatedHighResScrollX / kEvdevHighResScrollUnitsPerDetent;
+ const int32_t scrollY = mAccumulatedHighResScrollY / kEvdevHighResScrollUnitsPerDetent;
if (scrollX != 0) {
if (!writeInputEvent(EV_REL, REL_HWHEEL, scrollX, eventTime)) {
return false;
}
- mAccumulatedHighResScrollX %= kEvdevMouseHighResScrollUnitsPerDetent;
+ mAccumulatedHighResScrollX %= kEvdevHighResScrollUnitsPerDetent;
}
if (scrollY != 0) {
if (!writeInputEvent(EV_REL, REL_WHEEL, scrollY, eventTime)) {
return false;
}
- mAccumulatedHighResScrollY %= kEvdevMouseHighResScrollUnitsPerDetent;
+ mAccumulatedHighResScrollY %= kEvdevHighResScrollUnitsPerDetent;
}
return writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
@@ -550,14 +554,38 @@
}
// --- VirtualRotaryEncoder ---
-VirtualRotaryEncoder::VirtualRotaryEncoder(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+VirtualRotaryEncoder::VirtualRotaryEncoder(unique_fd fd)
+ : VirtualInputDevice(std::move(fd)), mAccumulatedHighResScrollAmount(0) {}
VirtualRotaryEncoder::~VirtualRotaryEncoder() {}
bool VirtualRotaryEncoder::writeScrollEvent(float scrollAmount,
std::chrono::nanoseconds eventTime) {
- return writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(scrollAmount), eventTime) &&
- writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
+ if (!vd_flags::high_resolution_scroll()) {
+ return writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(scrollAmount), eventTime) &&
+ writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
+ }
+
+ const auto highResScrollAmount =
+ static_cast<int32_t>(scrollAmount * kEvdevHighResScrollUnitsPerDetent);
+ if (!writeInputEvent(EV_REL, REL_WHEEL_HI_RES, highResScrollAmount, eventTime)) {
+ return false;
+ }
+
+ // According to evdev spec, a high-resolution scroll device needs to emit REL_WHEEL / REL_HWHEEL
+ // events in addition to high-res scroll events. Regular scroll events can approximate high-res
+ // scroll events, so we send a regular scroll event when the accumulated scroll motion reaches a
+ // detent (single wheel click).
+ mAccumulatedHighResScrollAmount += highResScrollAmount;
+ const int32_t scroll = mAccumulatedHighResScrollAmount / kEvdevHighResScrollUnitsPerDetent;
+ if (scroll != 0) {
+ if (!writeInputEvent(EV_REL, REL_WHEEL, scroll, eventTime)) {
+ return false;
+ }
+ mAccumulatedHighResScrollAmount %= kEvdevHighResScrollUnitsPerDetent;
+ }
+
+ return writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
}
} // namespace android
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index a2192cb..96f8b05 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -15,13 +15,6 @@
bug: "271455682"
}
-flag {
- name: "enable_gestures_library_timer_provider"
- namespace: "input"
- description: "Set to true to enable timer support for the touchpad Gestures library"
- bug: "297192727"
- }
-
flag {
name: "enable_input_event_tracing"
namespace: "input"
diff --git a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
index f49469c..e710613 100644
--- a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
@@ -52,7 +52,7 @@
const int32_t action;
const nsecs_t downTime;
const uint32_t seq;
- const int32_t eventId;
+ int32_t eventId;
const int32_t deviceId = 1;
const uint32_t source = AINPUT_SOURCE_TOUCHSCREEN;
const ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT;
@@ -291,6 +291,7 @@
void publishAndConsumeKeyEvent();
void publishAndConsumeMotionStream();
void publishAndConsumeMotionDown(nsecs_t downTime);
+ void publishAndConsumeSinglePointerMultipleSamples(const size_t nSamples);
void publishAndConsumeBatchedMotionMove(nsecs_t downTime);
void publishAndConsumeFocusEvent();
void publishAndConsumeCaptureEvent();
@@ -298,6 +299,7 @@
void publishAndConsumeTouchModeEvent();
void publishAndConsumeMotionEvent(int32_t action, nsecs_t downTime,
const std::vector<Pointer>& pointers);
+
void TearDown() override {
// Destroy the consumer, flushing any of the pending ack's.
sendMessage(LooperMessage::DESTROY_CONSUMER);
@@ -519,6 +521,123 @@
{Pointer{.id = 0, .x = 20, .y = 30}});
}
+/*
+ * Decompose a potential multi-sampled MotionEvent into multiple MotionEvents
+ * with a single sample.
+ */
+std::vector<MotionEvent> splitBatchedMotionEvent(const MotionEvent& batchedMotionEvent) {
+ std::vector<MotionEvent> singleMotionEvents;
+ const size_t batchSize = batchedMotionEvent.getHistorySize() + 1;
+ for (size_t i = 0; i < batchSize; ++i) {
+ MotionEvent singleMotionEvent;
+ singleMotionEvent
+ .initialize(batchedMotionEvent.getId(), batchedMotionEvent.getDeviceId(),
+ batchedMotionEvent.getSource(), batchedMotionEvent.getDisplayId(),
+ batchedMotionEvent.getHmac(), batchedMotionEvent.getAction(),
+ batchedMotionEvent.getActionButton(), batchedMotionEvent.getFlags(),
+ batchedMotionEvent.getEdgeFlags(), batchedMotionEvent.getMetaState(),
+ batchedMotionEvent.getButtonState(),
+ batchedMotionEvent.getClassification(),
+ batchedMotionEvent.getTransform(), batchedMotionEvent.getXPrecision(),
+ batchedMotionEvent.getYPrecision(),
+ batchedMotionEvent.getRawXCursorPosition(),
+ batchedMotionEvent.getRawYCursorPosition(),
+ batchedMotionEvent.getRawTransform(), batchedMotionEvent.getDownTime(),
+ batchedMotionEvent.getHistoricalEventTime(/*historicalIndex=*/i),
+ batchedMotionEvent.getPointerCount(),
+ batchedMotionEvent.getPointerProperties(),
+ (batchedMotionEvent.getSamplePointerCoords() + i));
+ singleMotionEvents.push_back(singleMotionEvent);
+ }
+ return singleMotionEvents;
+}
+
+/*
+ * Simulates a single pointer touching the screen and leaving it there for a period of time.
+ * Publishes a DOWN event and consumes it right away. Then, publishes a sequence of MOVE
+ * samples for the same pointer, and waits until it has been consumed. Splits batched MotionEvents
+ * into individual samples. Checks the consumed MotionEvents against the published ones.
+ * This test is non-deterministic because it depends on the timing of arrival of events to the
+ * socket.
+ *
+ * @param nSamples The number of MOVE samples to publish before attempting consumption.
+ */
+void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeSinglePointerMultipleSamples(
+ const size_t nSamples) {
+ const nsecs_t downTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ const Pointer pointer(0, 20, 30);
+
+ const PublishMotionArgs argsDown(AMOTION_EVENT_ACTION_DOWN, downTime, {pointer}, mSeq);
+ const nsecs_t publishTimeOfDown = systemTime(SYSTEM_TIME_MONOTONIC);
+ publishMotionEvent(*mPublisher, argsDown);
+
+ // Consume the DOWN event.
+ ASSERT_TRUE(mMotionEvents.popWithTimeout(TIMEOUT).has_value());
+
+ verifyFinishedSignal(*mPublisher, mSeq, publishTimeOfDown);
+
+ std::vector<nsecs_t> publishTimes;
+ std::vector<PublishMotionArgs> argsMoves;
+ std::queue<uint32_t> publishedSequenceNumbers;
+
+ // Block Looper to increase the chance of batching events
+ {
+ std::scoped_lock l(mLock);
+ mLooperMayProceed = false;
+ }
+ sendMessage(LooperMessage::BLOCK_LOOPER);
+ {
+ std::unique_lock l(mLock);
+ mNotifyLooperWaiting.wait(l, [this] { return mLooperIsBlocked; });
+ }
+
+ uint32_t firstSampleId;
+ for (size_t i = 0; i < nSamples; ++i) {
+ publishedSequenceNumbers.push(++mSeq);
+ PublishMotionArgs argsMove(AMOTION_EVENT_ACTION_MOVE, downTime, {pointer}, mSeq);
+ // A batched MotionEvent only has a single event id, currently determined when the
+ // MotionEvent is initialized. Therefore, to pass the eventId comparisons inside
+ // verifyArgsEqualToEvent, we need to override the event id of the published args to match
+ // the event id of the first sample inside the MotionEvent.
+ if (i == 0) {
+ firstSampleId = argsMove.eventId;
+ }
+ argsMove.eventId = firstSampleId;
+ publishTimes.push_back(systemTime(SYSTEM_TIME_MONOTONIC));
+ argsMoves.push_back(argsMove);
+ publishMotionEvent(*mPublisher, argsMove);
+ }
+
+ std::vector<MotionEvent> singleSampledMotionEvents;
+
+ // Unblock Looper
+ {
+ std::scoped_lock l(mLock);
+ mLooperMayProceed = true;
+ }
+ mNotifyLooperMayProceed.notify_all();
+
+ // We have no control over the socket behavior, so the consumer can receive
+ // the motion as a batched event, or as a sequence of multiple single-sample MotionEvents (or a
+ // mix of those)
+ while (singleSampledMotionEvents.size() != nSamples) {
+ const std::optional<std::unique_ptr<MotionEvent>> batchedMotionEvent =
+ mMotionEvents.popWithTimeout(TIMEOUT);
+ // The events received by these calls are never null
+ std::vector<MotionEvent> splitMotionEvents = splitBatchedMotionEvent(**batchedMotionEvent);
+ singleSampledMotionEvents.insert(singleSampledMotionEvents.end(), splitMotionEvents.begin(),
+ splitMotionEvents.end());
+ }
+
+ // Consumer can choose to finish events in any order. For simplicity,
+ // we verify the events in sequence (since that is how the test is implemented).
+ for (size_t i = 0; i < nSamples; ++i) {
+ verifyArgsEqualToEvent(argsMoves[i], singleSampledMotionEvents[i]);
+ verifyFinishedSignal(*mPublisher, publishedSequenceNumbers.front(), publishTimes[i]);
+ publishedSequenceNumbers.pop();
+ }
+}
+
void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeBatchedMotionMove(
nsecs_t downTime) {
uint32_t seq = mSeq++;
@@ -814,4 +933,8 @@
ASSERT_NO_FATAL_FAILURE(publishAndConsumeTouchModeEvent());
}
+TEST_F(InputPublisherAndConsumerNoResamplingTest, PublishAndConsumeSinglePointer) {
+ publishAndConsumeSinglePointerMultipleSamples(3);
+}
+
} // namespace android
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 5261287..dd78049 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -300,7 +300,9 @@
if (result == 0) {
outPlanes->planeCount = 3;
outPlanes->planes[0].data = yuvData.y;
- if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+ // P010 is word-aligned 10-bit semiplaner, and YCbCr_422_I is a single interleaved plane
+ if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010 ||
+ format == AHARDWAREBUFFER_FORMAT_YCbCr_422_I) {
outPlanes->planes[0].pixelStride = 2;
} else {
outPlanes->planes[0].pixelStride = 1;
diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp
index 3a4c869..b5c56c5 100644
--- a/libs/tracing_perfetto/Android.bp
+++ b/libs/tracing_perfetto/Android.bp
@@ -40,6 +40,7 @@
],
shared_libs: [
+ "libbase",
"libcutils",
"libperfetto_c",
"android.os.flags-aconfig-cc-host",
diff --git a/libs/tracing_perfetto/include/trace_result.h b/libs/tracing_perfetto/include/trace_result.h
deleted file mode 100644
index f7581fc..0000000
--- a/libs/tracing_perfetto/include/trace_result.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef TRACE_RESULT_H
-#define TRACE_RESULT_H
-
-namespace tracing_perfetto {
-
-enum class Result {
- SUCCESS,
- NOT_SUPPORTED,
- INVALID_INPUT,
-};
-
-}
-
-#endif // TRACE_RESULT_H
diff --git a/libs/tracing_perfetto/include/tracing_perfetto.h b/libs/tracing_perfetto/include/tracing_perfetto.h
index 2c1c2a4..0b2b0af 100644
--- a/libs/tracing_perfetto/include/tracing_perfetto.h
+++ b/libs/tracing_perfetto/include/tracing_perfetto.h
@@ -19,35 +19,32 @@
#include <stdint.h>
-#include "trace_result.h"
-
namespace tracing_perfetto {
void registerWithPerfetto(bool test = false);
-Result traceBegin(uint64_t category, const char* name);
+void traceBegin(uint64_t category, const char* name);
-Result traceEnd(uint64_t category);
+void traceEnd(uint64_t category);
-Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie);
+void traceAsyncBegin(uint64_t category, const char* name, int32_t cookie);
-Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie);
+void traceAsyncEnd(uint64_t category, const char* name, int32_t cookie);
-Result traceAsyncBeginForTrack(uint64_t category, const char* name,
+void traceAsyncBeginForTrack(uint64_t category, const char* name,
const char* trackName, int32_t cookie);
-Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
+void traceAsyncEndForTrack(uint64_t category, const char* trackName,
int32_t cookie);
-Result traceInstant(uint64_t category, const char* name);
+void traceInstant(uint64_t category, const char* name);
-Result traceInstantForTrack(uint64_t category, const char* trackName,
+void traceInstantForTrack(uint64_t category, const char* trackName,
const char* name);
-Result traceCounter(uint64_t category, const char* name, int64_t value);
+void traceCounter(uint64_t category, const char* name, int64_t value);
bool isTagEnabled(uint64_t category);
-
} // namespace tracing_perfetto
#endif // TRACING_PERFETTO_H
diff --git a/libs/tracing_perfetto/tests/Android.bp b/libs/tracing_perfetto/tests/Android.bp
index a35b0e0..d203467 100644
--- a/libs/tracing_perfetto/tests/Android.bp
+++ b/libs/tracing_perfetto/tests/Android.bp
@@ -26,6 +26,7 @@
static_libs: [
"libflagtest",
"libgmock",
+ "perfetto_trace_protos",
],
cflags: [
"-Wall",
@@ -35,6 +36,8 @@
"android.os.flags-aconfig-cc-host",
"libbase",
"libperfetto_c",
+ "liblog",
+ "libprotobuf-cpp-lite",
"libtracing_perfetto",
],
srcs: [
diff --git a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
index 7716b9a..e9fee2e 100644
--- a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
+++ b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
@@ -16,10 +16,10 @@
#include "tracing_perfetto.h"
-#include <thread>
-
#include <android_os.h>
#include <flag_macros.h>
+#include <thread>
+#include <unistd.h>
#include "gtest/gtest.h"
#include "perfetto/public/abi/data_source_abi.h"
@@ -45,67 +45,182 @@
#include "trace_categories.h"
#include "utils.h"
+#include "protos/perfetto/trace/trace.pb.h"
+#include "protos/perfetto/trace/trace_packet.pb.h"
+#include "protos/perfetto/trace/interned_data/interned_data.pb.h"
+
+#include <fstream>
+#include <iterator>
namespace tracing_perfetto {
-using ::perfetto::shlib::test_utils::AllFieldsWithId;
-using ::perfetto::shlib::test_utils::FieldView;
-using ::perfetto::shlib::test_utils::IdFieldView;
-using ::perfetto::shlib::test_utils::MsgField;
-using ::perfetto::shlib::test_utils::PbField;
-using ::perfetto::shlib::test_utils::StringField;
+using ::perfetto::protos::Trace;
+using ::perfetto::protos::TracePacket;
+using ::perfetto::protos::EventCategory;
+using ::perfetto::protos::EventName;
+using ::perfetto::protos::FtraceEvent;
+using ::perfetto::protos::FtraceEventBundle;
+using ::perfetto::protos::InternedData;
+
using ::perfetto::shlib::test_utils::TracingSession;
-using ::perfetto::shlib::test_utils::VarIntField;
-using ::testing::_;
-using ::testing::ElementsAre;
-using ::testing::UnorderedElementsAre;
const auto PERFETTO_SDK_TRACING = ACONFIG_FLAG(android::os, perfetto_sdk_tracing);
+// TODO(b/303199244): Add tests for all the library functions.
class TracingPerfettoTest : public testing::Test {
protected:
void SetUp() override {
- tracing_perfetto::registerWithPerfetto(true /* test */);
+ tracing_perfetto::registerWithPerfetto(false /* test */);
}
};
-// TODO(b/303199244): Add tests for all the library functions.
-
-TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstant,
- REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
- TracingSession tracing_session =
- TracingSession::Builder().set_data_source_name("track_event").Build();
- tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, "");
-
+Trace stopSession(TracingSession& tracing_session) {
+ tracing_session.FlushBlocking(5000);
tracing_session.StopBlocking();
std::vector<uint8_t> data = tracing_session.ReadBlocking();
+ std::string data_string(data.begin(), data.end());
+
+ perfetto::protos::Trace trace;
+ trace.ParseFromString(data_string);
+
+ return trace;
+}
+
+void verifyTrackEvent(const Trace& trace, const std::string expected_category,
+ const std::string& expected_name) {
bool found = false;
- for (struct PerfettoPbDecoderField trace_field : FieldView(data)) {
- ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
- MsgField(_)));
- IdFieldView track_event(
- trace_field, perfetto_protos_TracePacket_track_event_field_number);
- if (track_event.size() == 0) {
- continue;
+ for (const TracePacket& packet: trace.packet()) {
+ if (packet.has_track_event() && packet.has_interned_data()) {
+
+ const InternedData& interned_data = packet.interned_data();
+ if (interned_data.event_categories_size() > 0) {
+ const EventCategory& event_category = packet.interned_data().event_categories(0);
+ if (event_category.name() == expected_category) {
+ found = true;
+ }
+ }
+
+ if (interned_data.event_names_size() > 0) {
+ const EventName& event_name = packet.interned_data().event_names(0);
+ if (event_name.name() == expected_name) {
+ found &= true;
+ }
+ }
+
+ if (found) {
+ break;
+ }
}
- found = true;
- IdFieldView cat_iid_fields(
- track_event.front(),
- perfetto_protos_TrackEvent_category_iids_field_number);
- ASSERT_THAT(cat_iid_fields, ElementsAre(VarIntField(_)));
- uint64_t cat_iid = cat_iid_fields.front().value.integer64;
- EXPECT_THAT(
- trace_field,
- AllFieldsWithId(
- perfetto_protos_TracePacket_interned_data_field_number,
- ElementsAre(AllFieldsWithId(
- perfetto_protos_InternedData_event_categories_field_number,
- ElementsAre(MsgField(UnorderedElementsAre(
- PbField(perfetto_protos_EventCategory_iid_field_number,
- VarIntField(cat_iid)),
- PbField(perfetto_protos_EventCategory_name_field_number,
- StringField("input")))))))));
}
EXPECT_TRUE(found);
}
-} // namespace tracing_perfetto
\ No newline at end of file
+void verifyAtraceEvent(const Trace& trace, const std::string& expected_name) {
+ std::string expected_print_buf = "I|" + std::to_string(gettid()) + "|" + expected_name + "\n";
+
+ bool found = false;
+ for (const TracePacket& packet: trace.packet()) {
+ if (packet.has_ftrace_events()) {
+ const FtraceEventBundle& ftrace_events_bundle = packet.ftrace_events();
+
+ if (ftrace_events_bundle.event_size() > 0) {
+ const FtraceEvent& ftrace_event = ftrace_events_bundle.event(0);
+ if (ftrace_event.has_print() && (ftrace_event.print().buf() == expected_print_buf)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ EXPECT_TRUE(found);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfetto,
+ REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+ std::string event_category = "input";
+ std::string event_name = "traceInstantWithPerfetto";
+
+ TracingSession tracing_session =
+ TracingSession::Builder().add_enabled_category(event_category).Build();
+
+ tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+ Trace trace = stopSession(tracing_session);
+
+ verifyTrackEvent(trace, event_category, event_name);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithAtrace,
+ REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+ std::string event_category = "input";
+ std::string event_name = "traceInstantWithAtrace";
+
+ TracingSession tracing_session =
+ TracingSession::Builder().add_atrace_category(event_category).Build();
+
+ tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+ Trace trace = stopSession(tracing_session);
+
+ verifyAtraceEvent(trace, event_name);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtrace,
+ REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+ std::string event_category = "input";
+ std::string event_name = "traceInstantWithPerfettoAndAtrace";
+
+ TracingSession tracing_session =
+ TracingSession::Builder()
+ .add_atrace_category(event_category)
+ .add_enabled_category(event_category).Build();
+
+ tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+ Trace trace = stopSession(tracing_session);
+
+ verifyAtraceEvent(trace, event_name);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtraceAndPreferTrackEvent,
+ REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+ std::string event_category = "input";
+ std::string event_name = "traceInstantWithPerfettoAndAtraceAndPreferTrackEvent";
+
+ TracingSession tracing_session =
+ TracingSession::Builder()
+ .add_atrace_category(event_category)
+ .add_atrace_category_prefer_sdk(event_category)
+ .add_enabled_category(event_category).Build();
+
+ tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+ Trace trace = stopSession(tracing_session);
+
+ verifyTrackEvent(trace, event_category, event_name);
+}
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtraceConcurrently,
+ REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+ std::string event_category = "input";
+ std::string event_name = "traceInstantWithPerfettoAndAtraceConcurrently";
+
+ TracingSession perfetto_tracing_session =
+ TracingSession::Builder()
+ .add_atrace_category(event_category)
+ .add_atrace_category_prefer_sdk(event_category)
+ .add_enabled_category(event_category).Build();
+
+ TracingSession atrace_tracing_session =
+ TracingSession::Builder()
+ .add_atrace_category(event_category)
+ .add_enabled_category(event_category).Build();
+
+ tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());
+
+ Trace atrace_trace = stopSession(atrace_tracing_session);
+ Trace perfetto_trace = stopSession(perfetto_tracing_session);
+
+ verifyAtraceEvent(atrace_trace, event_name);
+ verifyAtraceEvent(perfetto_trace, event_name);
+}
+} // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tests/utils.cpp b/libs/tracing_perfetto/tests/utils.cpp
index 9c42028..8c4d4a8 100644
--- a/libs/tracing_perfetto/tests/utils.cpp
+++ b/libs/tracing_perfetto/tests/utils.cpp
@@ -26,6 +26,11 @@
#include "perfetto/public/protos/config/track_event/track_event_config.pzc.h"
#include "perfetto/public/tracing_session.h"
+#include "protos/perfetto/config/ftrace/ftrace_config.pb.h"
+#include "protos/perfetto/config/track_event/track_event_config.pb.h"
+#include "protos/perfetto/config/data_source_config.pb.h"
+#include "protos/perfetto/config/trace_config.pb.h"
+
namespace perfetto {
namespace shlib {
namespace test_utils {
@@ -44,63 +49,54 @@
} // namespace
TracingSession TracingSession::Builder::Build() {
- struct PerfettoPbMsgWriter writer;
- struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
+ perfetto::protos::TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(1024);
- struct perfetto_protos_TraceConfig cfg;
- PerfettoPbMsgInit(&cfg.msg, &writer);
+ auto* track_event_ds_config = trace_config.add_data_sources()->mutable_config();
+ auto* ftrace_ds_config = trace_config.add_data_sources()->mutable_config();
+
+ track_event_ds_config->set_name("track_event");
+ track_event_ds_config->set_target_buffer(0);
+
+ ftrace_ds_config->set_name("linux.ftrace");
+ ftrace_ds_config->set_target_buffer(0);
{
- struct perfetto_protos_TraceConfig_BufferConfig buffers;
- perfetto_protos_TraceConfig_begin_buffers(&cfg, &buffers);
-
- perfetto_protos_TraceConfig_BufferConfig_set_size_kb(&buffers, 1024);
-
- perfetto_protos_TraceConfig_end_buffers(&cfg, &buffers);
- }
-
- {
- struct perfetto_protos_TraceConfig_DataSource data_sources;
- perfetto_protos_TraceConfig_begin_data_sources(&cfg, &data_sources);
-
- {
- struct perfetto_protos_DataSourceConfig ds_cfg;
- perfetto_protos_TraceConfig_DataSource_begin_config(&data_sources,
- &ds_cfg);
-
- perfetto_protos_DataSourceConfig_set_cstr_name(&ds_cfg,
- data_source_name_.c_str());
- if (!enabled_categories_.empty() && !disabled_categories_.empty()) {
- perfetto_protos_TrackEventConfig te_cfg;
- perfetto_protos_DataSourceConfig_begin_track_event_config(&ds_cfg,
- &te_cfg);
- for (const std::string& cat : enabled_categories_) {
- perfetto_protos_TrackEventConfig_set_enabled_categories(
- &te_cfg, cat.data(), cat.size());
- }
- for (const std::string& cat : disabled_categories_) {
- perfetto_protos_TrackEventConfig_set_disabled_categories(
- &te_cfg, cat.data(), cat.size());
- }
- perfetto_protos_DataSourceConfig_end_track_event_config(&ds_cfg,
- &te_cfg);
+ auto* ftrace_config = ftrace_ds_config->mutable_ftrace_config();
+ if (!atrace_categories_.empty()) {
+ ftrace_config->add_ftrace_events("ftrace/print");
+ for (const std::string& cat : atrace_categories_) {
+ ftrace_config->add_atrace_categories(cat);
}
- perfetto_protos_TraceConfig_DataSource_end_config(&data_sources, &ds_cfg);
+ for (const std::string& cat : atrace_categories_prefer_sdk_) {
+ ftrace_config->add_atrace_categories_prefer_sdk(cat);
+ }
}
-
- perfetto_protos_TraceConfig_end_data_sources(&cfg, &data_sources);
}
- size_t cfg_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
- std::unique_ptr<uint8_t[]> ser(new uint8_t[cfg_size]);
- PerfettoHeapBufferCopyInto(hb, &writer.writer, ser.get(), cfg_size);
- PerfettoHeapBufferDestroy(hb, &writer.writer);
+
+ {
+ auto* track_event_config = track_event_ds_config->mutable_track_event_config();
+ if (!enabled_categories_.empty() || !disabled_categories_.empty()) {
+ for (const std::string& cat : enabled_categories_) {
+ track_event_config->add_enabled_categories(cat);
+ }
+
+ for (const std::string& cat : disabled_categories_) {
+ track_event_config->add_disabled_categories(cat);
+ }
+ }
+ }
struct PerfettoTracingSessionImpl* ts =
- PerfettoTracingSessionCreate(PERFETTO_BACKEND_IN_PROCESS);
+ PerfettoTracingSessionCreate(PERFETTO_BACKEND_SYSTEM);
- PerfettoTracingSessionSetup(ts, ser.get(), cfg_size);
+ std::string trace_config_string;
+ trace_config.SerializeToString(&trace_config_string);
+ PerfettoTracingSessionSetup(ts, trace_config_string.data(), trace_config_string.length());
+
+ // Fails to start here
PerfettoTracingSessionStartBlocking(ts);
return TracingSession::Adopt(ts);
diff --git a/libs/tracing_perfetto/tests/utils.h b/libs/tracing_perfetto/tests/utils.h
index 4353554..8edb414 100644
--- a/libs/tracing_perfetto/tests/utils.h
+++ b/libs/tracing_perfetto/tests/utils.h
@@ -74,10 +74,6 @@
class Builder {
public:
Builder() = default;
- Builder& set_data_source_name(std::string data_source_name) {
- data_source_name_ = std::move(data_source_name);
- return *this;
- }
Builder& add_enabled_category(std::string category) {
enabled_categories_.push_back(std::move(category));
return *this;
@@ -86,12 +82,21 @@
disabled_categories_.push_back(std::move(category));
return *this;
}
+ Builder& add_atrace_category(std::string category) {
+ atrace_categories_.push_back(std::move(category));
+ return *this;
+ }
+ Builder& add_atrace_category_prefer_sdk(std::string category) {
+ atrace_categories_prefer_sdk_.push_back(std::move(category));
+ return *this;
+ }
TracingSession Build();
private:
- std::string data_source_name_;
std::vector<std::string> enabled_categories_;
std::vector<std::string> disabled_categories_;
+ std::vector<std::string> atrace_categories_;
+ std::vector<std::string> atrace_categories_prefer_sdk_;
};
static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
diff --git a/libs/tracing_perfetto/tracing_perfetto.cpp b/libs/tracing_perfetto/tracing_perfetto.cpp
index 6f716ee..fc5336d 100644
--- a/libs/tracing_perfetto/tracing_perfetto.cpp
+++ b/libs/tracing_perfetto/tracing_perfetto.cpp
@@ -28,116 +28,112 @@
internal::registerWithPerfetto(test);
}
-Result traceBegin(uint64_t category, const char* name) {
+void traceBegin(uint64_t category, const char* name) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceBegin(*perfettoTeCategory, name);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_begin(category, name);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceBegin(*perfettoTeCategory, name);
}
}
-Result traceEnd(uint64_t category) {
+void traceEnd(uint64_t category) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceEnd(*perfettoTeCategory);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_end(category);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceEnd(*perfettoTeCategory);
}
}
-Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie) {
+void traceAsyncBegin(uint64_t category, const char* name, int32_t cookie) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceAsyncBegin(*perfettoTeCategory, name, cookie);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_async_begin(category, name, cookie);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceAsyncBegin(*perfettoTeCategory, name, cookie);
}
}
-Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie) {
+void traceAsyncEnd(uint64_t category, const char* name, int32_t cookie) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceAsyncEnd(*perfettoTeCategory, name, cookie);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_async_end(category, name, cookie);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceAsyncEnd(*perfettoTeCategory, name, cookie);
}
}
-Result traceAsyncBeginForTrack(uint64_t category, const char* name,
+void traceAsyncBeginForTrack(uint64_t category, const char* name,
const char* trackName, int32_t cookie) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_async_for_track_begin(category, trackName, name, cookie);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie);
}
}
-Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
+void traceAsyncEndForTrack(uint64_t category, const char* trackName,
int32_t cookie) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_async_for_track_end(category, trackName, cookie);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie);
}
}
-Result traceInstant(uint64_t category, const char* name) {
+void traceInstant(uint64_t category, const char* name) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceInstant(*perfettoTeCategory, name);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_instant(category, name);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceInstant(*perfettoTeCategory, name);
}
}
-Result traceInstantForTrack(uint64_t category, const char* trackName,
+void traceInstantForTrack(uint64_t category, const char* trackName,
const char* name) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceInstantForTrack(*perfettoTeCategory, trackName, name);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_instant_for_track(category, trackName, name);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceInstantForTrack(*perfettoTeCategory, trackName, name);
}
}
-Result traceCounter(uint64_t category, const char* name, int64_t value) {
+void traceCounter(uint64_t category, const char* name, int64_t value) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return internal::perfettoTraceCounter(*perfettoTeCategory, name, value);
- } else {
+
+ if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
atrace_int64(category, name, value);
- return Result::SUCCESS;
+ } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
+ internal::perfettoTraceCounter(*perfettoTeCategory, name, value);
}
}
bool isTagEnabled(uint64_t category) {
struct PerfettoTeCategory* perfettoTeCategory =
internal::toPerfettoCategory(category);
- if (perfettoTeCategory != nullptr) {
- return true;
- } else {
- return (atrace_get_enabled_tags() & category) != 0;
- }
+ return internal::isPerfettoCategoryEnabled(perfettoTeCategory)
+ || atrace_is_tag_enabled(category);
}
-
} // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.cpp b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
index 758ace6..9a0042a 100644
--- a/libs/tracing_perfetto/tracing_perfetto_internal.cpp
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
@@ -44,13 +44,13 @@
C(rro, "rro", "RRO category") \
C(thermal, "thermal", "Thermal category")
-#include "tracing_perfetto_internal.h"
-
-#include <inttypes.h>
-
+#include <atomic>
#include <mutex>
#include <android_os.h>
+#include <android-base/properties.h>
+#include <cutils/trace.h>
+#include <inttypes.h>
#include "perfetto/public/compiler.h"
#include "perfetto/public/producer.h"
@@ -58,19 +58,42 @@
#include "perfetto/public/te_macros.h"
#include "perfetto/public/track_event.h"
#include "trace_categories.h"
-#include "trace_result.h"
+#include "tracing_perfetto_internal.h"
+
+#ifdef __BIONIC__
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+#endif
namespace tracing_perfetto {
namespace internal {
namespace {
-
PERFETTO_TE_CATEGORIES_DECLARE(FRAMEWORK_CATEGORIES);
PERFETTO_TE_CATEGORIES_DEFINE(FRAMEWORK_CATEGORIES);
-std::atomic_bool is_perfetto_registered = false;
+static constexpr char kPreferFlagProperty[] = "debug.atrace.prefer_sdk";
+static std::atomic<const prop_info*> prefer_property_info = nullptr;
+static std::atomic_uint32_t last_prefer_seq_num = 0;
+static std::atomic_uint64_t prefer_flags = 0;
+
+static const prop_info* system_property_find(const char* name [[maybe_unused]]) {
+ #ifdef __BIONIC__
+ return __system_property_find(name);
+ #endif
+
+ return nullptr;
+}
+
+static uint32_t system_property_serial(const prop_info* pi [[maybe_unused]]) {
+ #ifdef __BIONIC__
+ return __system_property_serial(pi);
+ #endif
+
+ return last_prefer_seq_num;
+}
struct PerfettoTeCategory* toCategory(uint64_t inCategory) {
switch (inCategory) {
@@ -137,8 +160,60 @@
} // namespace
-bool isPerfettoRegistered() {
- return is_perfetto_registered;
+bool isPerfettoCategoryEnabled(PerfettoTeCategory* category) {
+ return category != nullptr;
+}
+
+/**
+ * Updates the cached |prefer_flags|.
+ *
+ * We cache the prefer_flags because reading it on every trace event is expensive.
+ * The cache is invalidated when a sys_prop sequence number changes.
+ */
+void updatePreferFlags() {
+ if (!prefer_property_info.load(std::memory_order_acquire)) {
+ auto* new_prefer_property_info = system_property_find(kPreferFlagProperty);
+ prefer_flags.store(android::base::GetIntProperty(kPreferFlagProperty, 0),
+ std::memory_order_relaxed);
+
+ if (!new_prefer_property_info) {
+ // This should never happen. If it does, we fail gracefully and end up reading the property
+ // traced event.
+ return;
+ }
+
+ last_prefer_seq_num = system_property_serial(new_prefer_property_info);
+ prefer_property_info.store(new_prefer_property_info, std::memory_order_release);
+ }
+
+ uint32_t prefer_seq_num = system_property_serial(prefer_property_info);
+ if (prefer_seq_num != last_prefer_seq_num.load(std::memory_order_acquire)) {
+ prefer_flags.store(android::base::GetIntProperty(kPreferFlagProperty, 0),
+ std::memory_order_relaxed);
+ last_prefer_seq_num.store(prefer_seq_num, std::memory_order_release);
+ }
+}
+
+bool shouldPreferAtrace(PerfettoTeCategory *perfettoCategory, uint64_t atraceCategory) {
+ // There are 3 cases:
+ // 1. Atrace is not enabled.
+ if (!atrace_is_tag_enabled(atraceCategory)) {
+ return false;
+ }
+
+ // 2. Atrace is enabled but perfetto is not enabled.
+ if (!isPerfettoCategoryEnabled(perfettoCategory)) {
+ return true;
+ }
+
+ // Update prefer_flags before checking it below
+ updatePreferFlags();
+
+ // 3. Atrace and perfetto are enabled.
+ // Even though this category is enabled for track events, the config mandates that we downgrade
+ // it to atrace if the same atrace category is currently enabled. This prevents missing the
+ // event from a concurrent session that needs the same category in atrace.
+ return (atraceCategory & prefer_flags.load(std::memory_order_relaxed)) == 0;
}
struct PerfettoTeCategory* toPerfettoCategory(uint64_t category) {
@@ -148,7 +223,7 @@
}
bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
- (*perfettoCategory).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
+ (*perfettoCategory).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
return enabled ? perfettoCategory : nullptr;
}
@@ -164,70 +239,57 @@
PerfettoProducerInit(args);
PerfettoTeInit();
PERFETTO_TE_REGISTER_CATEGORIES(FRAMEWORK_CATEGORIES);
- is_perfetto_registered = true;
});
}
-Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name) {
+void perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name) {
PERFETTO_TE(category, PERFETTO_TE_SLICE_BEGIN(name));
- return Result::SUCCESS;
}
-Result perfettoTraceEnd(const struct PerfettoTeCategory& category) {
+void perfettoTraceEnd(const struct PerfettoTeCategory& category) {
PERFETTO_TE(category, PERFETTO_TE_SLICE_END());
- return Result::SUCCESS;
}
-Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
const char* trackName, uint64_t cookie) {
PERFETTO_TE(
category, PERFETTO_TE_SLICE_BEGIN(name),
PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
- return Result::SUCCESS;
}
-Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
+void perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
const char* trackName, uint64_t cookie) {
PERFETTO_TE(
category, PERFETTO_TE_SLICE_END(),
PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
- return Result::SUCCESS;
}
-Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
uint64_t cookie) {
- return perfettoTraceAsyncBeginForTrack(category, name, name, cookie);
+ perfettoTraceAsyncBeginForTrack(category, name, name, cookie);
}
-Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
uint64_t cookie) {
- return perfettoTraceAsyncEndForTrack(category, name, cookie);
+ perfettoTraceAsyncEndForTrack(category, name, cookie);
}
-Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name) {
+void perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name) {
PERFETTO_TE(category, PERFETTO_TE_INSTANT(name));
- return Result::SUCCESS;
}
-Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
+void perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
const char* trackName, const char* name) {
PERFETTO_TE(
category, PERFETTO_TE_INSTANT(name),
PERFETTO_TE_NAMED_TRACK(trackName, 1, PerfettoTeProcessTrackUuid()));
- return Result::SUCCESS;
}
-Result perfettoTraceCounter(const struct PerfettoTeCategory& category,
+void perfettoTraceCounter(const struct PerfettoTeCategory& category,
[[maybe_unused]] const char* name, int64_t value) {
PERFETTO_TE(category, PERFETTO_TE_COUNTER(),
PERFETTO_TE_INT_COUNTER(value));
- return Result::SUCCESS;
}
-
-uint64_t getDefaultCategories() {
- return TRACE_CATEGORIES;
-}
-
} // namespace internal
} // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.h b/libs/tracing_perfetto/tracing_perfetto_internal.h
index 79e4b8f..3e1ac2a 100644
--- a/libs/tracing_perfetto/tracing_perfetto_internal.h
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.h
@@ -19,7 +19,6 @@
#include <stdint.h>
-#include "include/trace_result.h"
#include "perfetto/public/te_category_macros.h"
namespace tracing_perfetto {
@@ -32,31 +31,33 @@
void registerWithPerfetto(bool test = false);
-Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name);
+void perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name);
-Result perfettoTraceEnd(const struct PerfettoTeCategory& category);
+void perfettoTraceEnd(const struct PerfettoTeCategory& category);
-Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
uint64_t cookie);
-Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
uint64_t cookie);
-Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
const char* trackName, uint64_t cookie);
-Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
+void perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
const char* trackName, uint64_t cookie);
-Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name);
+void perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name);
-Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
+void perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
const char* trackName, const char* name);
-Result perfettoTraceCounter(const struct PerfettoTeCategory& category, const char* name,
+void perfettoTraceCounter(const struct PerfettoTeCategory& category, const char* name,
int64_t value);
-uint64_t getDefaultCategories();
+bool isPerfettoCategoryEnabled(PerfettoTeCategory *perfettoTeCategory);
+
+bool shouldPreferAtrace(PerfettoTeCategory *perfettoTeCategory, uint64_t category);
} // namespace internal
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 20fd359..b72cc6e 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -27,11 +27,14 @@
namespace android {
+constexpr float kDefaultScaleFactor = 1.0f;
+
RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext,
const InputReaderConfiguration& readerConfig)
- : InputMapper(deviceContext, readerConfig), mOrientation(ui::ROTATION_0) {
- mSource = AINPUT_SOURCE_ROTARY_ENCODER;
-}
+ : InputMapper(deviceContext, readerConfig),
+ mSource(AINPUT_SOURCE_ROTARY_ENCODER),
+ mScalingFactor(kDefaultScaleFactor),
+ mOrientation(ui::ROTATION_0) {}
RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {}
@@ -51,9 +54,10 @@
std::optional<float> scalingFactor = config.getFloat("device.scalingFactor");
if (!scalingFactor.has_value()) {
ALOGW("Rotary Encoder device configuration file didn't specify scaling factor,"
- "default to 1.0!\n");
+ "default to %f!\n",
+ kDefaultScaleFactor);
}
- mScalingFactor = scalingFactor.value_or(1.0f);
+ mScalingFactor = scalingFactor.value_or(kDefaultScaleFactor);
info.addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
res.value_or(0.0f) * mScalingFactor);
}
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index daab636..5c5fd3f 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -258,11 +258,9 @@
// 2) TouchpadInputMapper is stored as a unique_ptr and not moved.
mGestureInterpreter->SetPropProvider(const_cast<GesturesPropProvider*>(&gesturePropProvider),
&mPropertyProvider);
- if (input_flags::enable_gestures_library_timer_provider()) {
- mGestureInterpreter->SetTimerProvider(const_cast<GesturesTimerProvider*>(
- &kGestureTimerProvider),
- &mTimerProvider);
- }
+ mGestureInterpreter->SetTimerProvider(const_cast<GesturesTimerProvider*>(
+ &kGestureTimerProvider),
+ &mTimerProvider);
mGestureInterpreter->SetCallback(gestureInterpreterCallback, this);
}
@@ -300,12 +298,8 @@
dump += addLinePrefix(mGestureConverter.dump(), INDENT4);
dump += INDENT3 "Gesture properties:\n";
dump += addLinePrefix(mPropertyProvider.dump(), INDENT4);
- if (input_flags::enable_gestures_library_timer_provider()) {
- dump += INDENT3 "Timer provider:\n";
- dump += addLinePrefix(mTimerProvider.dump(), INDENT4);
- } else {
- dump += INDENT3 "Timer provider: disabled by flag\n";
- }
+ dump += INDENT3 "Timer provider:\n";
+ dump += addLinePrefix(mTimerProvider.dump(), INDENT4);
dump += INDENT3 "Captured event converter:\n";
dump += addLinePrefix(mCapturedEventConverter.dump(), INDENT4);
dump += StringPrintf(INDENT3 "DisplayId: %s\n",
@@ -468,9 +462,6 @@
}
std::list<NotifyArgs> TouchpadInputMapper::timeoutExpired(nsecs_t when) {
- if (!input_flags::enable_gestures_library_timer_provider()) {
- return {};
- }
mTimerProvider.triggerCallbacks(when);
return processGestures(when, when);
}
diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp
index 06315e2..5373440 100644
--- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp
+++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp
@@ -55,14 +55,14 @@
switch (rawEvent.code) {
case REL_WHEEL_HI_RES:
if (mHaveRelWheelHighRes) {
- mRelWheel = rawEvent.value /
- static_cast<float>(kEvdevMouseHighResScrollUnitsPerDetent);
+ mRelWheel =
+ rawEvent.value / static_cast<float>(kEvdevHighResScrollUnitsPerDetent);
}
break;
case REL_HWHEEL_HI_RES:
if (mHaveRelHWheelHighRes) {
- mRelHWheel = rawEvent.value /
- static_cast<float>(kEvdevMouseHighResScrollUnitsPerDetent);
+ mRelHWheel =
+ rawEvent.value / static_cast<float>(kEvdevHighResScrollUnitsPerDetent);
}
break;
case REL_WHEEL:
diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
index 6990d20..d3373cc 100644
--- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
@@ -16,8 +16,6 @@
#pragma once
-#include <stdint.h>
-
namespace android {
class InputDeviceContext;
@@ -36,8 +34,6 @@
inline bool haveRelativeVWheel() const { return mHaveRelWheel; }
inline bool haveRelativeHWheel() const { return mHaveRelHWheel; }
- inline int32_t getRelativeX() const { return mRelX; }
- inline int32_t getRelativeY() const { return mRelY; }
inline float getRelativeVWheel() const { return mRelWheel; }
inline float getRelativeHWheel() const { return mRelHWheel; }
@@ -47,8 +43,6 @@
bool mHaveRelWheelHighRes;
bool mHaveRelHWheelHighRes;
- int32_t mRelX;
- int32_t mRelY;
float mRelWheel;
float mRelHWheel;
diff --git a/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp b/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
index 2b8071b..366b3dc 100644
--- a/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
+++ b/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
@@ -22,6 +22,7 @@
#include <variant>
#include <android-base/logging.h>
+#include <android_companion_virtualdevice_flags.h>
#include <gtest/gtest.h>
#include <input/DisplayViewport.h>
#include <linux/input-event-codes.h>
@@ -109,6 +110,8 @@
} // namespace
+namespace vd_flags = android::companion::virtualdevice::flags;
+
/**
* Unit tests for RotaryEncoderInputMapper.
*/
@@ -170,4 +173,53 @@
WithDisplayId(ui::LogicalDisplayId::INVALID)))));
}
+TEST_F(RotaryEncoderInputMapperTest, ProcessRegularScroll) {
+ createDevice();
+ mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
+
+ std::list<NotifyArgs> args;
+ args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
+ WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(1.0f)))));
+}
+
+TEST_F(RotaryEncoderInputMapperTest, ProcessHighResScroll) {
+ vd_flags::high_resolution_scroll(true);
+ EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
+ .WillRepeatedly(Return(true));
+ createDevice();
+ mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
+
+ std::list<NotifyArgs> args;
+ args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
+ WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f)))));
+}
+
+TEST_F(RotaryEncoderInputMapperTest, HighResScrollIgnoresRegularScroll) {
+ vd_flags::high_resolution_scroll(true);
+ EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
+ .WillRepeatedly(Return(true));
+ createDevice();
+ mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
+
+ std::list<NotifyArgs> args;
+ args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60);
+ args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
+ WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f)))));
+}
+
} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index f643fb1..f8e3c22 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -697,6 +697,12 @@
return argDistance == distance;
}
+MATCHER_P(WithScroll, scroll, "InputEvent with specified scroll value") {
+ const auto argScroll = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SCROLL);
+ *result_listener << "expected scroll value " << scroll << ", but got " << argScroll;
+ return argScroll == scroll;
+}
+
MATCHER_P2(WithScroll, scrollX, scrollY, "InputEvent with specified scroll values") {
const auto argScrollX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_HSCROLL);
const auto argScrollY = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_VSCROLL);
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index da56014..334c104 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -211,7 +211,7 @@
return;
}
SFTRACE_CALL();
- if (sTraceHintSessionData) ATRACE_INT("Session hint", static_cast<int>(hint));
+ if (sTraceHintSessionData) SFTRACE_INT("Session hint", static_cast<int>(hint));
{
std::scoped_lock lock(mHintSessionMutex);
if (!ensurePowerHintSessionRunning()) {
@@ -298,7 +298,7 @@
SFTRACE_CALL();
{
mTargetDuration = targetDuration;
- if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns());
+ if (sTraceHintSessionData) SFTRACE_INT64("Time target", targetDuration.ns());
if (targetDuration == mLastTargetDurationSent) return;
std::scoped_lock lock(mHintSessionMutex);
if (!ensurePowerHintSessionRunning()) {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index bc4a41b..1076b2b 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -300,7 +300,7 @@
bool mSessionConfigSupported = true;
bool mFirstConfigSupportCheck = true;
- // Whether we should emit ATRACE_INT data for hint sessions
+ // Whether we should emit SFTRACE_INT data for hint sessions
static const bool sTraceHintSessionData;
// Default target duration for the hint session
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 5550565..2a0ee5a 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -359,7 +359,11 @@
void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {
std::scoped_lock lock(mMutex);
- mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
+ if (CC_UNLIKELY(acquireFenceTime == Fence::SIGNAL_TIME_PENDING)) {
+ mActuals.endTime = mActualQueueTime;
+ } else {
+ mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
+ }
}
void SurfaceFrame::setDropTime(nsecs_t dropTime) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 86c7d16..a6d2b15 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3060,6 +3060,8 @@
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
mDrawingState.acquireFence);
+ const int32_t layerId = getSequence();
+ mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber);
decrementPendingBufferCount();
if (mDrawingState.bufferSurfaceFrameTX != nullptr &&
mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) {
@@ -3238,7 +3240,7 @@
return static_cast<nsecs_t>(0);
}();
- if (ATRACE_ENABLED() && presentTime > 0) {
+ if (SFTRACE_ENABLED() && presentTime > 0) {
const auto presentIn = TimePoint::fromNs(presentTime) - TimePoint::now();
SFTRACE_FORMAT_INSTANT("presentIn %s", to_string(presentIn).c_str());
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d3b56f8..52f169e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1265,7 +1265,7 @@
const std::string mBlastTransactionName{"BufferTX - " + mName};
// This integer is incremented everytime a buffer arrives at the server for this layer,
// and decremented when a buffer is dropped or latched. When changed the integer is exported
- // to systrace with ATRACE_INT and mBlastTransactionName. This way when debugging perf it is
+ // to systrace with SFTRACE_INT and mBlastTransactionName. This way when debugging perf it is
// possible to see when a buffer arrived at the server, and in which frame it latched.
//
// You can understand the trace this way:
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 0b17c84..a20cf9a 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -1065,7 +1065,7 @@
ALOGV("%s: overriding to %s for uid=%d", __func__, to_string(overrideFps).c_str(), uid);
SFTRACE_FORMAT_INSTANT("%s: overriding to %s for uid=%d", __func__,
to_string(overrideFps).c_str(), uid);
- if (ATRACE_ENABLED() && FlagManager::getInstance().trace_frame_rate_override()) {
+ if (SFTRACE_ENABLED() && FlagManager::getInstance().trace_frame_rate_override()) {
std::stringstream ss;
ss << "FrameRateOverride " << uid;
SFTRACE_INT(ss.str().c_str(), overrideFps.getIntValue());
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 8dae3ca..900bce0 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -45,7 +45,7 @@
}
void traceEntry(const VSyncDispatchTimerQueueEntry& entry, nsecs_t now) {
- if (!ATRACE_ENABLED() || !entry.wakeupTime().has_value() || !entry.targetVsync().has_value()) {
+ if (!SFTRACE_ENABLED() || !entry.wakeupTime().has_value() || !entry.targetVsync().has_value()) {
return;
}
diff --git a/services/surfaceflinger/Scheduler/src/Timer.cpp b/services/surfaceflinger/Scheduler/src/Timer.cpp
index fba3d58..20c58eb 100644
--- a/services/surfaceflinger/Scheduler/src/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/src/Timer.cpp
@@ -188,7 +188,7 @@
int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);
setDebugState(DebugState::Running);
- if (ATRACE_ENABLED()) {
+ if (SFTRACE_ENABLED()) {
ftl::Concat trace("TimerIteration #", iteration++);
SFTRACE_NAME(trace.c_str());
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d00e762..c75c9f5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3320,9 +3320,9 @@
});
}
- // Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the
+ // Even though SFTRACE_INT64 already checks if tracing is enabled, it doesn't prevent the
// side-effect of getTotalSize(), so we check that again here
- if (ATRACE_ENABLED()) {
+ if (SFTRACE_ENABLED()) {
// getTotalSize returns the total number of buffers that were allocated by SurfaceFlinger
SFTRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize());
}
@@ -4259,6 +4259,11 @@
getHwComposer().setVsyncEnabled(displayId, enable ? hal::Vsync::ENABLE : hal::Vsync::DISABLE);
}
+// This callback originates from Scheduler::applyPolicy, whose thread context may be the main thread
+// (via Scheduler::chooseRefreshRateForContent) or a OneShotTimer thread. The latter case imposes a
+// deadlock prevention rule: If the main thread is processing hotplug, then mStateLock is locked as
+// the main thread stops the OneShotTimer and joins with its thread. Hence, the OneShotTimer thread
+// must not lock mStateLock in this callback, which would deadlock with the join.
void SurfaceFlinger::requestDisplayModes(std::vector<display::DisplayModeRequest> modeRequests) {
if (mBootStage != BootStage::FINISHED) {
ALOGV("Currently in the boot stage, skipping display mode changes");
@@ -4267,21 +4272,14 @@
SFTRACE_CALL();
- // If this is called from the main thread mStateLock must be locked before
- // Currently the only way to call this function from the main thread is from
- // Scheduler::chooseRefreshRateForContent
-
- ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
-
for (auto& request : modeRequests) {
const auto& modePtr = request.mode.modePtr;
-
const auto displayId = modePtr->getPhysicalDisplayId();
- const auto display = getDisplayDeviceLocked(displayId);
- if (!display) continue;
+ const auto selectorPtr = mDisplayModeController.selectorPtrFor(displayId);
+ if (!selectorPtr) continue;
- if (display->refreshRateSelector().isModeAllowed(request.mode)) {
+ if (selectorPtr->isModeAllowed(request.mode)) {
setDesiredMode(std::move(request));
} else {
ALOGV("%s: Mode %d is disallowed for display %s", __func__,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8242844..65bfce2 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -733,7 +733,7 @@
// Show hdr sdr ratio overlay
bool mHdrSdrRatioOverlay = false;
- void setDesiredMode(display::DisplayModeRequest&&) REQUIRES(mStateLock);
+ void setDesiredMode(display::DisplayModeRequest&&);
status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId, Fps minFps,
Fps maxFps);
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
index eba1ecf..51f33a6 100644
--- a/services/surfaceflinger/TracedOrdinal.h
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -79,7 +79,7 @@
private:
void trace() {
- if (CC_LIKELY(!ATRACE_ENABLED())) {
+ if (CC_LIKELY(!SFTRACE_ENABLED())) {
return;
}
diff --git a/services/surfaceflinger/common/include/common/trace.h b/services/surfaceflinger/common/include/common/trace.h
index c13cdde..344359e 100644
--- a/services/surfaceflinger/common/include/common/trace.h
+++ b/services/surfaceflinger/common/include/common/trace.h
@@ -20,6 +20,10 @@
#include <cutils/trace.h>
#include <stdint.h>
+#ifndef ATRACE_TAG
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#endif
+
#define SFTRACE_ENABLED() ATRACE_ENABLED()
#define SFTRACE_BEGIN(name) ATRACE_BEGIN(name)
#define SFTRACE_END() ATRACE_END()
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 25437ca..9be0fc3 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -479,6 +479,16 @@
EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
}
+TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceUnsignaled) {
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne,
+ "acquireFenceAfterQueue",
+ "acquireFenceAfterQueue",
+ /*isBuffer*/ true, sGameMode);
+ surfaceFrame->setActualQueueTime(123);
+ surfaceFrame->setAcquireFenceTime(Fence::SIGNAL_TIME_PENDING);
+ EXPECT_EQ(surfaceFrame->getActuals().endTime, 123);
+}
+
TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) {
auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne,
"acquireFenceAfterQueue",