Merge "Revert "Allow metaState changes from keys not declared by the keyboard"" into main
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4e3889a..d427ecf 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -3538,7 +3538,7 @@
// the dumpstate's own activity which is irrelevant.
RunCommand(
SERIALIZE_PERFETTO_TRACE_TASK, {"perfetto", "--save-for-bugreport"},
- CommandOptions::WithTimeout(10).DropRoot().CloseAllFileDescriptorsOnExec().Build(),
+ CommandOptions::WithTimeout(30).DropRoot().CloseAllFileDescriptorsOnExec().Build(),
false, outFd);
// MaybeAddSystemTraceToZip() will take care of copying the trace in the zip
// file in the later stages.
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index c98b9cf..228347d 100644
--- a/include/input/InputConsumerNoResampling.h
+++ b/include/input/InputConsumerNoResampling.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <map>
#include <memory>
#include <optional>
@@ -75,12 +76,13 @@
* the event is ready to consume.
* @param looper needs to be sp and not shared_ptr because it inherits from
* RefBase
- * @param resampler the resampling strategy to use. If null, no resampling will be
- * performed.
+ * @param resamplerCreator callable that returns the resampling strategy to be used. If null, no
+ * resampling will be performed. resamplerCreator must never return nullptr.
*/
- explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- sp<Looper> looper, InputConsumerCallbacks& callbacks,
- std::unique_ptr<Resampler> resampler);
+ explicit InputConsumerNoResampling(
+ const std::shared_ptr<InputChannel>& channel, sp<Looper> looper,
+ InputConsumerCallbacks& callbacks,
+ std::function<std::unique_ptr<Resampler>()> resamplerCreator);
~InputConsumerNoResampling();
@@ -117,7 +119,13 @@
std::shared_ptr<InputChannel> mChannel;
sp<Looper> mLooper;
InputConsumerCallbacks& mCallbacks;
- std::unique_ptr<Resampler> mResampler;
+ const std::function<std::unique_ptr<Resampler>()> mResamplerCreator;
+
+ /**
+ * A map to manage multidevice resampling. Each contained resampler is never null. This map is
+ * only modified by handleMessages.
+ */
+ std::map<DeviceId, std::unique_ptr<Resampler>> mResamplers;
// Looper-related infrastructure
/**
@@ -190,7 +198,10 @@
/**
* Batch messages that can be batched. When an unbatchable message is encountered, send it
* to the InputConsumerCallbacks immediately. If there are batches remaining,
- * notify InputConsumerCallbacks.
+ * notify InputConsumerCallbacks. If a resampleable ACTION_DOWN message is received, then a
+ * resampler is inserted for that deviceId in mResamplers. If a resampleable ACTION_UP or
+ * ACTION_CANCEL message is received then the resampler associated to that deviceId is erased
+ * from mResamplers.
*/
void handleMessages(std::vector<InputMessage>&& messages);
/**
diff --git a/include/input/Resampler.h b/include/input/Resampler.h
index dcb25b7..4aaeddd 100644
--- a/include/input/Resampler.h
+++ b/include/input/Resampler.h
@@ -92,12 +92,6 @@
};
/**
- * Keeps track of the previous MotionEvent deviceId to enable comparison between the previous
- * and the current deviceId.
- */
- std::optional<DeviceId> mPreviousDeviceId;
-
- /**
* Up to two latest samples from MotionEvent. Updated every time resampleMotionEvent is called.
* Note: We store up to two samples in order to simplify the implementation. Although,
* calculations are possible with only one previous sample.
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index 04869a1..64b1fd4 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -27,6 +27,7 @@
LIBBINDER_EXPORTED void trace_begin(uint64_t tag, const char* name);
LIBBINDER_EXPORTED void trace_end(uint64_t tag);
LIBBINDER_EXPORTED void trace_int(uint64_t tag, const char* name, int32_t value);
+LIBBINDER_EXPORTED uint64_t get_trace_enabled_tags();
status_t setNonBlocking(borrowed_fd fd);
diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp
index 893ee15..4e9230c 100644
--- a/libs/binder/OS_android.cpp
+++ b/libs/binder/OS_android.cpp
@@ -48,6 +48,10 @@
atrace_int(tag, name, value);
}
+uint64_t get_trace_enabled_tags() {
+ return atrace_enabled_tags;
+}
+
} // namespace os
// Legacy trace symbol. To be removed once all of downstream rebuilds.
diff --git a/libs/binder/OS_non_android_linux.cpp b/libs/binder/OS_non_android_linux.cpp
index 0c64eb6..6bba823 100644
--- a/libs/binder/OS_non_android_linux.cpp
+++ b/libs/binder/OS_non_android_linux.cpp
@@ -41,6 +41,10 @@
void trace_int(uint64_t, const char*, int32_t) {}
+uint64_t get_trace_enabled_tags() {
+ return 0;
+}
+
uint64_t GetThreadId() {
return syscall(__NR_gettid);
}
diff --git a/libs/binder/include/binder/Trace.h b/libs/binder/include/binder/Trace.h
index 2f450cb..a3e6c8a 100644
--- a/libs/binder/include/binder/Trace.h
+++ b/libs/binder/include/binder/Trace.h
@@ -42,6 +42,7 @@
void trace_begin(uint64_t tag, const char* name);
void trace_end(uint64_t tag);
void trace_int(uint64_t tag, const char* name, int32_t value);
+uint64_t get_trace_enabled_tags();
} // namespace os
class LIBBINDER_EXPORTED ScopedTrace {
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index af280d3..ff31dd0 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -18,8 +18,10 @@
#include <android/binder_ibinder_platform.h>
#include <android/binder_stability.h>
#include <android/binder_status.h>
+#include <binder/Functional.h>
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
+#include <binder/Trace.h>
#if __has_include(<private/android_filesystem_config.h>)
#include <private/android_filesystem_config.h>
#endif
@@ -40,6 +42,23 @@
using ::android::String16;
using ::android::String8;
using ::android::wp;
+using ::android::binder::impl::make_scope_guard;
+using ::android::binder::impl::scope_guard;
+using ::android::binder::os::get_trace_enabled_tags;
+using ::android::binder::os::trace_begin;
+using ::android::binder::os::trace_end;
+
+// transaction codes for getInterfaceHash and getInterfaceVersion are defined
+// in file : system/tools/aidl/aidl.cpp
+static constexpr int kGetInterfaceVersionId = 0x00fffffe;
+static const char* kInterfaceVersion = "getInterfaceVersion";
+static constexpr int kGetInterfaceHashId = 0x00fffffd;
+static const char* kInterfaceHash = "getInterfaceHash";
+static const char* kNdkTrace = "AIDL::ndk::";
+static const char* kServerTrace = "::server";
+static const char* kClientTrace = "::client";
+static const char* kSeparator = "::";
+static const char* kUnknownCode = "Unknown_Transaction_Code:";
namespace ABBinderTag {
@@ -90,6 +109,51 @@
return sanitized;
}
+const std::string getMethodName(const AIBinder_Class* clazz, transaction_code_t code) {
+ // TODO(b/150155678) - Move getInterfaceHash and getInterfaceVersion to libbinder and remove
+ // hardcoded cases.
+ if (code <= clazz->getTransactionCodeToFunctionLength() && code >= FIRST_CALL_TRANSACTION) {
+ // Codes have FIRST_CALL_TRANSACTION as added offset. Subtract to access function name
+ return clazz->getFunctionName(code);
+ } else if (code == kGetInterfaceVersionId) {
+ return kInterfaceVersion;
+ } else if (code == kGetInterfaceHashId) {
+ return kInterfaceHash;
+ }
+ return kUnknownCode + std::to_string(code);
+}
+
+const std::string getTraceSectionName(const AIBinder_Class* clazz, transaction_code_t code,
+ bool isServer) {
+ if (clazz == nullptr) {
+ ALOGE("class associated with binder is null. Class is needed to add trace with interface "
+ "name and function name");
+ return kNdkTrace;
+ }
+
+ const std::string descriptor = clazz->getInterfaceDescriptorUtf8();
+ const std::string methodName = getMethodName(clazz, code);
+
+ size_t traceSize =
+ strlen(kNdkTrace) + descriptor.size() + strlen(kSeparator) + methodName.size();
+ traceSize += isServer ? strlen(kServerTrace) : strlen(kClientTrace);
+
+ std::string trace;
+ // reserve to avoid repeated allocations
+ trace.reserve(traceSize);
+
+ trace += kNdkTrace;
+ trace += clazz->getInterfaceDescriptorUtf8();
+ trace += kSeparator;
+ trace += methodName;
+ trace += isServer ? kServerTrace : kClientTrace;
+
+ LOG_ALWAYS_FATAL_IF(trace.size() != traceSize, "Trace size mismatch. Expected %zu, got %zu",
+ traceSize, trace.size());
+
+ return trace;
+}
+
bool AIBinder::associateClass(const AIBinder_Class* clazz) {
if (clazz == nullptr) return false;
@@ -203,6 +267,17 @@
status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
binder_flags_t flags) {
+ std::string sectionName;
+ bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL;
+ if (tracingEnabled) {
+ sectionName = getTraceSectionName(getClass(), code, true /*isServer*/);
+ trace_begin(ATRACE_TAG_AIDL, sectionName.c_str());
+ }
+
+ scope_guard guard = make_scope_guard([&]() {
+ if (tracingEnabled) trace_end(ATRACE_TAG_AIDL);
+ });
+
if (isUserCommand(code)) {
if (getClass()->writeHeader && !data.checkInterface(this)) {
return STATUS_BAD_TYPE;
@@ -385,6 +460,31 @@
mInterfaceDescriptor(interfaceDescriptor),
mWideInterfaceDescriptor(interfaceDescriptor) {}
+bool AIBinder_Class::setTransactionCodeMap(const char** transactionCodeMap, size_t length) {
+ if (mTransactionCodeToFunction != nullptr) {
+ ALOGE("mTransactionCodeToFunction is already set!");
+ return false;
+ }
+ mTransactionCodeToFunction = transactionCodeMap;
+ mTransactionCodeToFunctionLength = length;
+ return true;
+}
+
+const char* AIBinder_Class::getFunctionName(transaction_code_t code) const {
+ if (mTransactionCodeToFunction == nullptr) {
+ ALOGE("mTransactionCodeToFunction is not set!");
+ return nullptr;
+ }
+
+ if (code < FIRST_CALL_TRANSACTION ||
+ code - FIRST_CALL_TRANSACTION >= mTransactionCodeToFunctionLength) {
+ ALOGE("Function name for requested code not found!");
+ return nullptr;
+ }
+
+ return mTransactionCodeToFunction[code - FIRST_CALL_TRANSACTION];
+}
+
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy,
@@ -404,6 +504,24 @@
clazz->onDump = onDump;
}
+void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz,
+ const char** transactionCodeToFunction,
+ size_t length) {
+ LOG_ALWAYS_FATAL_IF(clazz == nullptr || transactionCodeToFunction == nullptr,
+ "Valid clazz and transactionCodeToFunction are needed to set code to "
+ "function mapping.");
+ LOG_ALWAYS_FATAL_IF(!clazz->setTransactionCodeMap(transactionCodeToFunction, length),
+ "Failed to set transactionCodeToFunction to clazz! Is "
+ "transactionCodeToFunction already set?");
+}
+
+const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code) {
+ LOG_ALWAYS_FATAL_IF(
+ clazz == nullptr,
+ "Valid clazz is needed to get function name for requested transaction code");
+ return clazz->getFunctionName(code);
+}
+
void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) {
LOG_ALWAYS_FATAL_IF(clazz == nullptr, "disableInterfaceTokenHeader requires non-null clazz");
@@ -734,6 +852,19 @@
binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
AParcel** out, binder_flags_t flags) {
+ const AIBinder_Class* clazz = binder ? binder->getClass() : nullptr;
+
+ std::string sectionName;
+ bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL;
+ if (tracingEnabled) {
+ sectionName = getTraceSectionName(clazz, code, false /*isServer*/);
+ trace_begin(ATRACE_TAG_AIDL, sectionName.c_str());
+ }
+
+ scope_guard guard = make_scope_guard([&]() {
+ if (tracingEnabled) trace_end(ATRACE_TAG_AIDL);
+ });
+
if (in == nullptr) {
ALOGE("%s: requires non-null in parameter", __func__);
return STATUS_UNEXPECTED_NULL;
@@ -872,4 +1003,4 @@
"AIBinder_setInheritRt must be called on a local binder");
localBinder->setInheritRt(inheritRt);
-}
+}
\ No newline at end of file
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index f5b738c..a93dc1f 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -132,6 +132,9 @@
const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; }
const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); }
+ bool setTransactionCodeMap(const char** transactionCodeMap, size_t transactionCodeMapSize);
+ const char* getFunctionName(transaction_code_t code) const;
+ size_t getTransactionCodeToFunctionLength() const { return mTransactionCodeToFunctionLength; }
// whether a transaction header should be written
bool writeHeader = true;
@@ -151,6 +154,10 @@
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
// one.
const ::android::String16 mWideInterfaceDescriptor;
+ // Array which holds names of the functions
+ const char** mTransactionCodeToFunction = nullptr;
+ // length of mmTransactionCodeToFunctionLength array
+ size_t mTransactionCodeToFunctionLength = 0;
};
// Ownership is like this (when linked to death):
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index af56bf0..8296356 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -30,6 +30,17 @@
#include <android/binder_auto_utils.h>
#include <android/binder_ibinder.h>
+#if defined(__ANDROID_VENDOR__)
+#include <android/llndk-versioning.h>
+#elif !defined(API_LEVEL_AT_LEAST)
+#if defined(__BIONIC__)
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \
+ (__builtin_available(android sdk_api_level, *))
+#else
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true)
+#endif // __BIONIC__
+#endif // __ANDROID_VENDOR__
+
#if __has_include(<android/binder_shell.h>)
#include <android/binder_shell.h>
#define HAS_BINDER_SHELL_COMMAND
@@ -164,6 +175,10 @@
* Helper method to create a class
*/
static inline AIBinder_Class* defineClass(const char* interfaceDescriptor,
+ AIBinder_Class_onTransact onTransact,
+ const char** codeToFunction, size_t functionCount);
+
+ static inline AIBinder_Class* defineClass(const char* interfaceDescriptor,
AIBinder_Class_onTransact onTransact);
private:
@@ -256,6 +271,13 @@
AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
AIBinder_Class_onTransact onTransact) {
+
+ return defineClass(interfaceDescriptor, onTransact, nullptr, 0);
+}
+
+AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
+ AIBinder_Class_onTransact onTransact,
+ const char** codeToFunction, size_t functionCount) {
AIBinder_Class* clazz = AIBinder_Class_define(interfaceDescriptor, ICInterfaceData::onCreate,
ICInterfaceData::onDestroy, onTransact);
if (clazz == nullptr) {
@@ -274,6 +296,20 @@
AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
}
#endif
+
+// TODO(b/368559337): fix versioning on product partition
+#if !defined(__ANDROID_PRODUCT__) && \
+ (defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36)
+ if API_LEVEL_AT_LEAST (36, 202504) {
+ if (codeToFunction != nullptr) {
+ AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction,
+ functionCount);
+ }
+ }
+#else
+ (void)codeToFunction;
+ (void)functionCount;
+#endif // defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36
return clazz;
}
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 72d255e..2f6c4e3 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -219,6 +219,50 @@
void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
/**
+ * Associates a mapping of transaction codes(transaction_code_t) to function names for the given
+ * class.
+ *
+ * Trace messages will use the provided names instead of bare integer codes when set. If not set by
+ * this function, trace messages will only be identified by the bare code. This should be called one
+ * time during clazz initialization. clazz and transactionCodeToFunctionMap should have same
+ * lifetime. Resetting/clearing the transactionCodeToFunctionMap is not allowed.
+ *
+ * Available since API level 36.
+ *
+ * \param clazz class which should use this transaction to code function map.
+ * \param transactionCodeToFunctionMap array of function names indexed by transaction code.
+ * Transaction codes start from 1, functions with transaction code 1 will correspond to index 0 in
+ * transactionCodeToFunctionMap. When defining methods, transaction codes are expected to be
+ * contiguous, and this is required for maximum memory efficiency.
+ * You can use nullptr if certain transaction codes are not used. Lifetime should be same as clazz.
+ * \param length number of elements in the transactionCodeToFunctionMap
+ *
+ * \return true if setting codeToFunction to clazz is successful. return false if clazz or
+ * codeToFunction is nullptr.
+ */
+void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz,
+ const char** transactionCodeToFunctionMap,
+ size_t length) __INTRODUCED_IN(36);
+
+/**
+ * Get function name associated with transaction code for given class
+ *
+ * This function returns function name associated with provided transaction code for given class.
+ * AIBinder_Class_setTransactionCodeToFunctionNameMap should be called first to associate function
+ * to transaction code mapping.
+ *
+ * Available since API level 36.
+ *
+ * \param clazz class for which function name is requested
+ * \param transactionCode transaction_code_t for which function name is requested.
+ *
+ * \return function name in form of const char* if transaction code is valid for given class.
+ * if transaction code is invalid or transactionCodeToFunctionMap is not set, nullptr is returned
+ */
+const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code)
+ __INTRODUCED_IN(36);
+
+/**
* This tells users of this class not to use a transaction header. By default, libbinder_ndk users
* read/write transaction headers implicitly (in the SDK, this must be manually written by
* android.os.Parcel#writeInterfaceToken, and it is read/checked with
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index c9e669e..c885816 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -250,6 +250,10 @@
LIBBINDER_NDK36 { # introduced=36
global:
+ AIBinder_Class_setTransactionCodeToFunctionNameMap;
+ AIBinder_Class_setTransactionCodeToFunctionNameMap; # llndk=202504
+ AIBinder_Class_getFunctionName;
+ AIBinder_Class_getFunctionName; # llndk=202504
ABinderRpc_registerAccessorProvider; # systemapi
ABinderRpc_unregisterAccessorProvider; # systemapi
ABinderRpc_Accessor_new; # systemapi
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 3cd2b9a..e5a3da4 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -1108,6 +1108,37 @@
EXPECT_EQ(deleteCount, 0);
}
+void* EmptyOnCreate(void* args) {
+ return args;
+}
+void EmptyOnDestroy(void* /*userData*/) {}
+binder_status_t EmptyOnTransact(AIBinder* /*binder*/, transaction_code_t /*code*/,
+ const AParcel* /*in*/, AParcel* /*out*/) {
+ return STATUS_OK;
+}
+
+TEST(NdkBinder_DeathTest, SetCodeMapTwice) {
+ const char* codeToFunction1[] = {"function-1", "function-2", "function-3"};
+ const char* codeToFunction2[] = {"function-4", "function-5"};
+ const char* interfaceName = "interface_descriptor";
+ AIBinder_Class* clazz =
+ AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact);
+ AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction1, 3);
+ // Reset/clear is not allowed
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction2, 2), "");
+}
+
+TEST(NdkBinder_DeathTest, SetNullCodeMap) {
+ const char* codeToFunction[] = {"function-1", "function-2", "function-3"};
+ const char* interfaceName = "interface_descriptor";
+ AIBinder_Class* clazz =
+ AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact);
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, codeToFunction, 3),
+ "");
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, nullptr, 0), "");
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, nullptr, 0), "");
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 11150bc..077a33a 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1544,15 +1544,6 @@
ABinderRpc_Accessor_delete(accessor);
}
-TEST_F(BinderARpcNdk, ARpcDoubleRemoveProvider) {
- ABinderRpc_AccessorProvider* provider =
- ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
- kARpcNumSupportedServices, nullptr, nullptr);
- ASSERT_NE(nullptr, provider);
- ABinderRpc_unregisterAccessorProvider(provider);
- EXPECT_DEATH(ABinderRpc_unregisterAccessorProvider(provider), " was already unregistered");
-}
-
TEST_F(BinderARpcNdk, ARpcNullArgs_ConnectionInfo_new) {
sockaddr_storage addr;
EXPECT_EQ(nullptr, ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&addr), 0));
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 3a1471e..e3a3371 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -49,7 +49,8 @@
return STATUS_UNKNOWN_TRANSACTION;
}
-static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact);
+static AIBinder_Class* g_class =
+ ::ndk::ICInterface::defineClass("ISomeInterface", onTransact, nullptr, 0);
class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> {
public:
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index 157ab3c..ba9e457 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -42,6 +42,10 @@
void trace_int(uint64_t, const char*, int32_t) {}
+uint64_t get_trace_enabled_tags() {
+ return 0;
+}
+
uint64_t GetThreadId() {
return 0;
}
diff --git a/libs/binder/trusty/ndk/include/android/llndk-versioning.h b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
new file mode 100644
index 0000000..e955a34
--- /dev/null
+++ b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+// TODO(b/349936395): set to true for Trusty
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (false)
diff --git a/libs/debugstore/rust/Android.bp b/libs/debugstore/rust/Android.bp
index 55ba3c3..9475333 100644
--- a/libs/debugstore/rust/Android.bp
+++ b/libs/debugstore/rust/Android.bp
@@ -23,7 +23,6 @@
rustlibs: [
"libcrossbeam_queue",
"libparking_lot",
- "libonce_cell",
"libcxx",
],
shared_libs: ["libutils"],
diff --git a/libs/debugstore/rust/src/core.rs b/libs/debugstore/rust/src/core.rs
index 1dfa512..6bf79d4 100644
--- a/libs/debugstore/rust/src/core.rs
+++ b/libs/debugstore/rust/src/core.rs
@@ -17,12 +17,14 @@
use super::event_type::EventType;
use super::storage::Storage;
use crate::cxxffi::uptimeMillis;
-use once_cell::sync::Lazy;
use std::fmt;
-use std::sync::atomic::{AtomicU64, Ordering};
+use std::sync::{
+ atomic::{AtomicU64, Ordering},
+ LazyLock,
+};
// Lazily initialized static instance of DebugStore.
-static INSTANCE: Lazy<DebugStore> = Lazy::new(DebugStore::new);
+static INSTANCE: LazyLock<DebugStore> = LazyLock::new(DebugStore::new);
/// The `DebugStore` struct is responsible for managing debug events and data.
pub struct DebugStore {
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index cdbc186..ce8bb43 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -17,8 +17,6 @@
#define LOG_TAG "InputConsumerNoResampling"
#define ATRACE_TAG ATRACE_TAG_INPUT
-#include <chrono>
-
#include <inttypes.h>
#include <android-base/logging.h>
@@ -39,6 +37,8 @@
using std::chrono::nanoseconds;
+using android::base::Result;
+
/**
* Log debug messages relating to the consumer end of the transport channel.
* Enable this via "adb shell setprop log.tag.InputTransportConsumer DEBUG" (requires restart)
@@ -169,24 +169,18 @@
msg.body.timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = presentTime;
return msg;
}
-
-bool isPointerEvent(const MotionEvent& motionEvent) {
- return (motionEvent.getSource() & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
-}
} // namespace
-using android::base::Result;
-
// --- InputConsumerNoResampling ---
-InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- sp<Looper> looper,
- InputConsumerCallbacks& callbacks,
- std::unique_ptr<Resampler> resampler)
+InputConsumerNoResampling::InputConsumerNoResampling(
+ const std::shared_ptr<InputChannel>& channel, sp<Looper> looper,
+ InputConsumerCallbacks& callbacks,
+ std::function<std::unique_ptr<Resampler>()> resamplerCreator)
: mChannel{channel},
mLooper{looper},
mCallbacks{callbacks},
- mResampler{std::move(resampler)},
+ mResamplerCreator{std::move(resamplerCreator)},
mFdEvents(0) {
LOG_ALWAYS_FATAL_IF(mLooper == nullptr);
mCallback = sp<LooperEventCallback>::make(
@@ -319,7 +313,6 @@
}
void InputConsumerNoResampling::handleMessages(std::vector<InputMessage>&& messages) {
- // TODO(b/297226446) : add resampling
for (const InputMessage& msg : messages) {
if (msg.header.type == InputMessage::Type::MOTION) {
const int32_t action = msg.body.motion.action;
@@ -329,12 +322,31 @@
action == AMOTION_EVENT_ACTION_HOVER_MOVE) &&
(isFromSource(source, AINPUT_SOURCE_CLASS_POINTER) ||
isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK));
+
+ const bool canResample = (mResamplerCreator != nullptr) &&
+ (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER));
+ if (canResample) {
+ if (action == AMOTION_EVENT_ACTION_DOWN) {
+ if (std::unique_ptr<Resampler> resampler = mResamplerCreator();
+ resampler != nullptr) {
+ const auto [_, inserted] =
+ mResamplers.insert(std::pair(deviceId, std::move(resampler)));
+ LOG_IF(WARNING, !inserted) << deviceId << "already exists in mResamplers";
+ }
+ }
+ }
+
if (batchableEvent) {
// add it to batch
mBatches[deviceId].emplace(msg);
} else {
// consume all pending batches for this device immediately
consumeBatchedInputEvents(deviceId, /*requestedFrameTime=*/std::nullopt);
+ if (canResample &&
+ (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL)) {
+ LOG_IF(INFO, mResamplers.erase(deviceId) == 0)
+ << deviceId << "does not exist in mResamplers";
+ }
handleMessage(msg);
}
} else {
@@ -456,8 +468,13 @@
std::queue<InputMessage>& messages) {
std::unique_ptr<MotionEvent> motionEvent;
std::optional<uint32_t> firstSeqForBatch;
- const nanoseconds resampleLatency =
- (mResampler != nullptr) ? mResampler->getResampleLatency() : nanoseconds{0};
+
+ LOG_IF(FATAL, messages.empty()) << "messages queue is empty!";
+ const DeviceId deviceId = messages.front().body.motion.deviceId;
+ const auto resampler = mResamplers.find(deviceId);
+ const nanoseconds resampleLatency = (resampler != mResamplers.cend())
+ ? resampler->second->getResampleLatency()
+ : nanoseconds{0};
const nanoseconds adjustedFrameTime = nanoseconds{requestedFrameTime} - resampleLatency;
while (!messages.empty() &&
@@ -474,15 +491,17 @@
}
messages.pop();
}
+
// Check if resampling should be performed.
- if (motionEvent != nullptr && isPointerEvent(*motionEvent) && mResampler != nullptr) {
- InputMessage* futureSample = nullptr;
- if (!messages.empty()) {
- futureSample = &messages.front();
- }
- mResampler->resampleMotionEvent(nanoseconds{requestedFrameTime}, *motionEvent,
- futureSample);
+ InputMessage* futureSample = nullptr;
+ if (!messages.empty()) {
+ futureSample = &messages.front();
}
+ if ((motionEvent != nullptr) && (resampler != mResamplers.cend())) {
+ resampler->second->resampleMotionEvent(nanoseconds{requestedFrameTime}, *motionEvent,
+ futureSample);
+ }
+
return std::make_pair(std::move(motionEvent), firstSeqForBatch);
}
diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp
index 51fadf8..328fa68 100644
--- a/libs/input/Resampler.cpp
+++ b/libs/input/Resampler.cpp
@@ -247,11 +247,6 @@
void LegacyResampler::resampleMotionEvent(nanoseconds frameTime, MotionEvent& motionEvent,
const InputMessage* futureSample) {
- if (mPreviousDeviceId && *mPreviousDeviceId != motionEvent.getDeviceId()) {
- mLatestSamples.clear();
- }
- mPreviousDeviceId = motionEvent.getDeviceId();
-
const nanoseconds resampleTime = frameTime - RESAMPLE_LATENCY;
updateLatestSamples(motionEvent);
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index e23fc94..31592cd 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -49,6 +49,12 @@
const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000;
/**
+ * The key event triggered a key gesture. Used in policy flag to notify that a key gesture was
+ * triggered using the event.
+ */
+ const int POLICY_FLAG_KEY_GESTURE_TRIGGERED = 0x40000;
+
+ /**
* Common input event flag used for both motion and key events for a gesture or pointer being
* canceled.
*/
diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp
index d708316..cbb332e 100644
--- a/libs/input/tests/InputConsumer_test.cpp
+++ b/libs/input/tests/InputConsumer_test.cpp
@@ -16,6 +16,9 @@
#include <input/InputConsumerNoResampling.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
#include <memory>
#include <optional>
@@ -25,7 +28,9 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <input/BlockingQueue.h>
+#include <input/Input.h>
#include <input/InputEventBuilders.h>
+#include <input/Resampler.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
@@ -37,8 +42,18 @@
using ::testing::AllOf;
using ::testing::Matcher;
-using ::testing::Not;
+struct Pointer {
+ int32_t id{0};
+ ToolType toolType{ToolType::FINGER};
+ float x{0.0f};
+ float y{0.0f};
+ bool isResampled{false};
+
+ PointerBuilder asPointerBuilder() const {
+ return PointerBuilder{id, toolType}.x(x).y(y).isResampled(isResampled);
+ }
+};
} // namespace
class InputConsumerTest : public testing::Test, public InputConsumerCallbacks {
@@ -47,9 +62,9 @@
: mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
mLooper{sp<Looper>::make(/*allowNonCallbacks=*/false)} {
Looper::setForThread(mLooper);
- mConsumer =
- std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mLooper, *this,
- std::make_unique<LegacyResampler>());
+ mConsumer = std::make_unique<
+ InputConsumerNoResampling>(mClientTestChannel, mLooper, *this,
+ []() { return std::make_unique<LegacyResampler>(); });
}
void invokeLooperCallback() const {
@@ -71,6 +86,9 @@
EXPECT_THAT(*motionEvent, matcher);
}
+ InputMessage nextPointerMessage(std::chrono::nanoseconds eventTime, DeviceId deviceId,
+ int32_t action, const Pointer& pointer);
+
std::shared_ptr<TestInputChannel> mClientTestChannel;
sp<Looper> mLooper;
std::unique_ptr<InputConsumerNoResampling> mConsumer;
@@ -83,6 +101,7 @@
BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
private:
+ uint32_t mLastSeq{0};
size_t mOnBatchedInputEventPendingInvocationCount{0};
// InputConsumerCallbacks interface
@@ -118,6 +137,19 @@
};
};
+InputMessage InputConsumerTest::nextPointerMessage(std::chrono::nanoseconds eventTime,
+ DeviceId deviceId, int32_t action,
+ const Pointer& pointer) {
+ ++mLastSeq;
+ return InputMessageBuilder{InputMessage::Type::MOTION, mLastSeq}
+ .eventTime(eventTime.count())
+ .deviceId(deviceId)
+ .source(AINPUT_SOURCE_TOUCHSCREEN)
+ .action(action)
+ .pointer(pointer.asPointerBuilder())
+ .build();
+}
+
TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {
mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}
.eventTime(nanoseconds{0ms}.count())
@@ -235,8 +267,7 @@
.build());
invokeLooperCallback();
- assertReceivedMotionEvent(AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- Not(MotionEventIsResampled())));
+ assertReceivedMotionEvent(AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_MOVE)));
mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true);
mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
@@ -244,4 +275,121 @@
mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
}
+
+/**
+ * The test supposes a 60Hz Vsync rate and a 200Hz input rate. The InputMessages are intertwined as
+ * in a real use cases. The test's two devices should be resampled independently. Moreover, the
+ * InputMessage stream layout for the test is:
+ *
+ * DOWN(0, 0ms)
+ * MOVE(0, 5ms)
+ * MOVE(0, 10ms)
+ * DOWN(1, 15ms)
+ *
+ * CONSUME(16ms)
+ *
+ * MOVE(1, 20ms)
+ * MOVE(1, 25ms)
+ * MOVE(0, 30ms)
+ *
+ * CONSUME(32ms)
+ *
+ * MOVE(0, 35ms)
+ * UP(1, 40ms)
+ * UP(0, 45ms)
+ *
+ * CONSUME(48ms)
+ *
+ * The first field is device ID, and the second field is event time.
+ */
+TEST_F(InputConsumerTest, MultiDeviceResampling) {
+ mClientTestChannel->enqueueMessage(nextPointerMessage(0ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_DOWN,
+ Pointer{.x = 0, .y = 0}));
+
+ mClientTestChannel->assertNoSentMessages();
+
+ invokeLooperCallback();
+ assertReceivedMotionEvent(AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithSampleCount(1)));
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(5ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 1.0f, .y = 2.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(10ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 2.0f, .y = 4.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(15ms, /*deviceId=*/1,
+ AMOTION_EVENT_ACTION_DOWN,
+ Pointer{.x = 10.0f, .y = 10.0f}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(16'000'000 /*ns*/);
+
+ assertReceivedMotionEvent(AllOf(WithDeviceId(1), WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithSampleCount(1)));
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithSampleCount(3),
+ WithSample(/*sampleIndex=*/2,
+ Sample{11ms,
+ {PointerArgs{.x = 2.2f, .y = 4.4f, .isResampled = true}}})));
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(20ms, /*deviceId=*/1,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 11.0f, .y = 12.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(25ms, /*deviceId=*/1,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 12.0f, .y = 14.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(30ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 5.0f, .y = 6.0f}));
+
+ invokeLooperCallback();
+ assertOnBatchedInputEventPendingWasCalled();
+ mConsumer->consumeBatchedInputEvents(32'000'000 /*ns*/);
+
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(1), WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithSampleCount(3),
+ WithSample(/*sampleIndex=*/2,
+ Sample{27ms,
+ {PointerArgs{.x = 12.4f, .y = 14.8f, .isResampled = true}}})));
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(35ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 8.0f, .y = 9.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(40ms, /*deviceId=*/1,
+ AMOTION_EVENT_ACTION_UP,
+ Pointer{.x = 12.0f, .y = 14.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(45ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_UP,
+ Pointer{.x = 8.0f, .y = 9.0f}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(48'000'000 /*ns*/);
+
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(1), WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSampleCount(1)));
+
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithSampleCount(3),
+ WithSample(/*sampleIndex=*/2,
+ Sample{37'500'000ns,
+ {PointerArgs{.x = 9.5f, .y = 10.5f, .isResampled = true}}})));
+
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSampleCount(1)));
+
+ // The sequence order is based on the expected consumption. Each sequence number corresponds to
+ // one of the previously enqueued messages.
+ mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/5, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/6, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/9, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/7, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/8, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/10, /*handled=*/true);
+}
} // namespace android
diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp
index 26dee39..fae8518 100644
--- a/libs/input/tests/Resampler_test.cpp
+++ b/libs/input/tests/Resampler_test.cpp
@@ -87,7 +87,6 @@
struct InputStream {
std::vector<InputSample> samples{};
int32_t action{0};
- DeviceId deviceId{0};
/**
* Converts from InputStream to MotionEvent. Enables calling LegacyResampler methods only with
* the relevant data for tests.
@@ -100,8 +99,8 @@
MotionEventBuilder motionEventBuilder =
MotionEventBuilder(action, AINPUT_SOURCE_CLASS_POINTER)
.downTime(0)
- .eventTime(static_cast<std::chrono::nanoseconds>(firstSample.eventTime).count())
- .deviceId(deviceId);
+ .eventTime(
+ static_cast<std::chrono::nanoseconds>(firstSample.eventTime).count());
for (const Pointer& pointer : firstSample.pointers) {
const PointerBuilder pointerBuilder =
PointerBuilder(pointer.id, pointer.toolType).x(pointer.x).y(pointer.y);
@@ -289,28 +288,6 @@
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
-TEST_F(ResamplerTest, SinglePointerDifferentDeviceIdBetweenMotionEvents) {
- MotionEvent motionFromFirstDevice =
- InputStream{{InputSample{4ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}},
- InputSample{8ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
- AMOTION_EVENT_ACTION_MOVE,
- .deviceId = 0};
-
- mResampler->resampleMotionEvent(10ms, motionFromFirstDevice, nullptr);
-
- MotionEvent motionFromSecondDevice =
- InputStream{{InputSample{11ms,
- {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}}}},
- AMOTION_EVENT_ACTION_MOVE,
- .deviceId = 1};
- const MotionEvent originalMotionEvent = motionFromSecondDevice;
-
- mResampler->resampleMotionEvent(12ms, motionFromSecondDevice, nullptr);
- // The MotionEvent should not be resampled because the second event came from a different device
- // than the previous event.
- assertMotionEventIsNotResampled(originalMotionEvent, motionFromSecondDevice);
-}
-
TEST_F(ResamplerTest, SinglePointerSingleSampleInterpolation) {
MotionEvent motionEvent =
InputStream{{InputSample{10ms,
diff --git a/libs/input/tests/TestEventMatchers.h b/libs/input/tests/TestEventMatchers.h
index dd2e40c..3589de5 100644
--- a/libs/input/tests/TestEventMatchers.h
+++ b/libs/input/tests/TestEventMatchers.h
@@ -16,18 +16,39 @@
#pragma once
+#include <chrono>
#include <ostream>
+#include <vector>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
#include <input/Input.h>
namespace android {
+namespace {
+
+using ::testing::Matcher;
+
+} // namespace
+
/**
* This file contains a copy of Matchers from .../inputflinger/tests/TestEventMatchers.h. Ideally,
* implementations must not be duplicated.
* TODO(b/365606513): Find a way to share TestEventMatchers.h between inputflinger and libinput.
*/
+struct PointerArgs {
+ float x{0.0f};
+ float y{0.0f};
+ bool isResampled{false};
+};
+
+struct Sample {
+ std::chrono::nanoseconds eventTime{0};
+ std::vector<PointerArgs> pointers{};
+};
+
class WithDeviceIdMatcher {
public:
using is_gtest_matcher = void;
@@ -79,32 +100,88 @@
return WithMotionActionMatcher(action);
}
-class MotionEventIsResampledMatcher {
+class WithSampleCountMatcher {
public:
using is_gtest_matcher = void;
+ explicit WithSampleCountMatcher(size_t sampleCount) : mExpectedSampleCount{sampleCount} {}
bool MatchAndExplain(const MotionEvent& motionEvent, std::ostream*) const {
- const size_t numSamples = motionEvent.getHistorySize() + 1;
- const size_t numPointers = motionEvent.getPointerCount();
- if (numPointers <= 0 || numSamples <= 0) {
+ return (motionEvent.getHistorySize() + 1) == mExpectedSampleCount;
+ }
+
+ void DescribeTo(std::ostream* os) const { *os << "sample count " << mExpectedSampleCount; }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "different sample count"; }
+
+private:
+ const size_t mExpectedSampleCount;
+};
+
+inline WithSampleCountMatcher WithSampleCount(size_t sampleCount) {
+ return WithSampleCountMatcher(sampleCount);
+}
+
+class WithSampleMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithSampleMatcher(size_t sampleIndex, const Sample& sample)
+ : mSampleIndex{sampleIndex}, mSample{sample} {}
+
+ bool MatchAndExplain(const MotionEvent& motionEvent, std::ostream* os) const {
+ if (motionEvent.getHistorySize() < mSampleIndex) {
+ *os << "sample index out of bounds";
return false;
}
- for (size_t i = 0; i < numPointers; ++i) {
+
+ if (motionEvent.getHistoricalEventTime(mSampleIndex) != mSample.eventTime.count()) {
+ *os << "event time mismatch. sample: "
+ << motionEvent.getHistoricalEventTime(mSampleIndex)
+ << " expected: " << mSample.eventTime.count();
+ return false;
+ }
+
+ if (motionEvent.getPointerCount() != mSample.pointers.size()) {
+ *os << "pointer count mismatch. sample: " << motionEvent.getPointerCount()
+ << " expected: " << mSample.pointers.size();
+ return false;
+ }
+
+ for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount();
+ ++pointerIndex) {
const PointerCoords& pointerCoords =
- motionEvent.getSamplePointerCoords()[numSamples * numPointers + i];
- if (!pointerCoords.isResampled) {
+ *(motionEvent.getHistoricalRawPointerCoords(pointerIndex, mSampleIndex));
+ if ((pointerCoords.getX() != mSample.pointers[pointerIndex].x) ||
+ (pointerCoords.getY() != mSample.pointers[pointerIndex].y)) {
+ *os << "sample coordinates mismatch at pointer index " << pointerIndex
+ << ". sample: (" << pointerCoords.getX() << ", " << pointerCoords.getY()
+ << ") expected: (" << mSample.pointers[pointerIndex].x << ", "
+ << mSample.pointers[pointerIndex].y << ")";
+ return false;
+ }
+ if (motionEvent.isResampled(pointerIndex, mSampleIndex) !=
+ mSample.pointers[pointerIndex].isResampled) {
+ *os << "resampling flag mismatch. sample: "
+ << motionEvent.isResampled(pointerIndex, mSampleIndex)
+ << " expected: " << mSample.pointers[pointerIndex].isResampled;
return false;
}
}
return true;
}
- void DescribeTo(std::ostream* os) const { *os << "MotionEvent is resampled."; }
+ void DescribeTo(std::ostream* os) const { *os << "motion event sample properties match."; }
- void DescribeNegationTo(std::ostream* os) const { *os << "MotionEvent is not resampled."; }
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "motion event sample properties do not match expected properties.";
+ }
+
+private:
+ const size_t mSampleIndex;
+ const Sample mSample;
};
-inline MotionEventIsResampledMatcher MotionEventIsResampled() {
- return MotionEventIsResampledMatcher();
+inline WithSampleMatcher WithSample(size_t sampleIndex, const Sample& sample) {
+ return WithSampleMatcher(sampleIndex, sample);
}
+
} // namespace android
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index a9264b3..595573d 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -17,6 +17,7 @@
#include <RenderEngineBench.h>
#include <android-base/file.h>
#include <benchmark/benchmark.h>
+#include <com_android_graphics_libgui_flags.h>
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
#include <renderengine/ExternalTexture.h>
@@ -321,5 +322,7 @@
BENCHMARK_CAPTURE(BM_homescreen, SkiaGLThreaded, RenderEngine::Threaded::YES,
RenderEngine::GraphicsApi::GL);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS_EDGE_EXTENSION_SHADER
BENCHMARK_CAPTURE(BM_homescreen_edgeExtension, SkiaGLThreaded, RenderEngine::Threaded::YES,
RenderEngine::GraphicsApi::GL);
+#endif
diff --git a/libs/vibrator/TEST_MAPPING b/libs/vibrator/TEST_MAPPING
index d782b43..e206761 100644
--- a/libs/vibrator/TEST_MAPPING
+++ b/libs/vibrator/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "libvibrator_test"
}
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 6e35041..6713a5c 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -2141,6 +2141,10 @@
}
egl_surface_t const* const s = get_surface(surface);
+ if (!s->getNativeWindow()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_FALSE;
+ }
native_window_set_buffers_timestamp(s->getNativeWindow(), time);
return EGL_TRUE;
@@ -2405,7 +2409,7 @@
case 0:
return EGL_TRUE;
case -ENOENT:
- return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
+ return setErrorQuiet(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
case -ENOSYS:
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
case -EINVAL:
diff --git a/services/vibratorservice/TEST_MAPPING b/services/vibratorservice/TEST_MAPPING
index af48673..1eb3a58 100644
--- a/services/vibratorservice/TEST_MAPPING
+++ b/services/vibratorservice/TEST_MAPPING
@@ -4,11 +4,6 @@
"name": "libvibratorservice_test"
}
],
- "postsubmit": [
- {
- "name": "libvibratorservice_test"
- }
- ],
"imports": [
{
"path": "cts/tests/vibrator"