diff options
97 files changed, 1465 insertions, 676 deletions
diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 82caccaf68..bf9acb37da 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -145,6 +145,9 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; * Buffers which are replaced or removed from the scene in the transaction invoking * this callback may be reused after this point. * + * Starting with API level 36, prefer using \a ASurfaceTransaction_OnBufferRelease to listen + * to when a buffer is ready to be reused. + * * \param context Optional context provided by the client that is passed into * the callback. * @@ -157,8 +160,7 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; * Available since API level 29. */ typedef void (*ASurfaceTransaction_OnComplete)(void* _Null_unspecified context, - ASurfaceTransactionStats* _Nonnull stats) - __INTRODUCED_IN(29); + ASurfaceTransactionStats* _Nonnull stats); /** * The ASurfaceTransaction_OnCommit callback is invoked when transaction is applied and the updates @@ -186,8 +188,36 @@ typedef void (*ASurfaceTransaction_OnComplete)(void* _Null_unspecified context, * Available since API level 31. */ typedef void (*ASurfaceTransaction_OnCommit)(void* _Null_unspecified context, - ASurfaceTransactionStats* _Nonnull stats) - __INTRODUCED_IN(31); + ASurfaceTransactionStats* _Nonnull stats); + +/** + * The ASurfaceTransaction_OnBufferRelease callback is invoked when a buffer that was passed in + * ASurfaceTransaction_setBuffer is ready to be reused. + * + * This callback is guaranteed to be invoked if ASurfaceTransaction_setBuffer is called with a non + * null buffer. If the buffer in the transaction is replaced via another call to + * ASurfaceTransaction_setBuffer, the callback will be invoked immediately. Otherwise the callback + * will be invoked before the ASurfaceTransaction_OnComplete callback after the buffer was + * presented. + * + * If this callback is set, caller should not release the buffer using the + * ASurfaceTransaction_OnComplete. + * + * \param context Optional context provided by the client that is passed into the callback. + * + * \param release_fence_fd Returns the fence file descriptor used to signal the release of buffer + * associated with this callback. If this fence is valid (>=0), the buffer has not yet been released + * and the fence will signal when the buffer has been released. If the fence is -1 , the buffer is + * already released. The recipient of the callback takes ownership of the fence fd and is + * responsible for closing it. + * + * THREADING + * The callback can be invoked on any thread. + * + * Available since API level 36. + */ +typedef void (*ASurfaceTransaction_OnBufferRelease)(void* _Null_unspecified context, + int release_fence_fd); /** * Returns the timestamp of when the frame was latched by the framework. Once a frame is @@ -251,7 +281,7 @@ int64_t ASurfaceTransactionStats_getAcquireTime( /** * The returns the fence used to signal the release of the PREVIOUS buffer set on * this surface. If this fence is valid (>=0), the PREVIOUS buffer has not yet been released and the - * fence will signal when the PREVIOUS buffer has been released. If the fence is -1 , the PREVIOUS + * fence will signal when the PREVIOUS buffer has been released. If the fence is -1, the PREVIOUS * buffer is already released. The recipient of the callback takes ownership of the * previousReleaseFenceFd and is responsible for closing it. * @@ -353,6 +383,9 @@ void ASurfaceTransaction_setZOrder(ASurfaceTransaction* _Nonnull transaction, * Note that the buffer must be allocated with AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE * as the surface control might be composited using the GPU. * + * Starting with API level 36, prefer using \a ASurfaceTransaction_setBufferWithRelease to + * set a buffer and a callback which will be invoked when the buffer is ready to be reused. + * * Available since API level 29. */ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* _Nonnull transaction, @@ -361,6 +394,29 @@ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* _Nonnull transaction, __INTRODUCED_IN(29); /** + * Updates the AHardwareBuffer displayed for \a surface_control. If not -1, the + * acquire_fence_fd should be a file descriptor that is signaled when all pending work + * for the buffer is complete and the buffer can be safely read. + * + * The frameworks takes ownership of the \a acquire_fence_fd passed and is responsible + * for closing it. + * + * Note that the buffer must be allocated with AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE + * as the surface control might be composited using the GPU. + * + * When the buffer is ready to be reused, the ASurfaceTransaction_OnBufferRelease + * callback will be invoked. If the buffer is null, the callback will not be invoked. + * + * Available since API level 36. + */ +void ASurfaceTransaction_setBufferWithRelease(ASurfaceTransaction* _Nonnull transaction, + ASurfaceControl* _Nonnull surface_control, + AHardwareBuffer* _Nonnull buffer, + int acquire_fence_fd, void* _Null_unspecified context, + ASurfaceTransaction_OnBufferRelease _Nonnull func) + __INTRODUCED_IN(36); + +/** * Updates the color for \a surface_control. This will make the background color for the * ASurfaceControl visible in transparent regions of the surface. Colors \a r, \a g, * and \a b must be within the range that is valid for \a dataspace. \a dataspace and \a alpha diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h index 358a19158e..c98b9cf8c1 100644 --- a/include/input/InputConsumerNoResampling.h +++ b/include/input/InputConsumerNoResampling.h @@ -16,8 +16,12 @@ #pragma once +#include <map> +#include <memory> +#include <optional> + +#include <input/Input.h> #include <input/InputTransport.h> -#include <input/LooperInterface.h> #include <input/Resampler.h> #include <utils/Looper.h> @@ -36,7 +40,7 @@ public: /** * When you receive this callback, you must (eventually) call "consumeBatchedInputEvents". * If you don't want batching, then call "consumeBatchedInputEvents" immediately with - * std::nullopt frameTime to receive the pending motion event(s). + * std::nullopt requestedFrameTime to receive the pending motion event(s). * @param pendingBatchSource the source of the pending batch. */ virtual void onBatchedInputEventPending(int32_t pendingBatchSource) = 0; @@ -67,16 +71,6 @@ public: class InputConsumerNoResampling final { public: /** - * This constructor is exclusively for test code. Any real use of InputConsumerNoResampling must - * use the constructor that takes an sp<Looper> parameter instead of - * std::shared_ptr<LooperInterface>. - */ - explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, - std::shared_ptr<LooperInterface> looper, - InputConsumerCallbacks& callbacks, - std::unique_ptr<Resampler> resampler); - - /** * @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever * the event is ready to consume. * @param looper needs to be sp and not shared_ptr because it inherits from @@ -96,15 +90,17 @@ public: void finishInputEvent(uint32_t seq, bool handled); void reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime); /** - * If you want to consume all events immediately (disable batching), the you still must call - * this. For frameTime, use a std::nullopt. - * @param frameTime the time up to which consume the events. When there's double (or triple) - * buffering, you may want to not consume all events currently available, because you could be - * still working on an older frame, but there could already have been events that arrived that - * are more recent. + * If you want to consume all events immediately (disable batching), then you still must call + * this. For requestedFrameTime, use a std::nullopt. It is not guaranteed that the consumption + * will occur at requestedFrameTime. The resampling strategy may modify it. + * @param requestedFrameTime the time up to which consume the events. When there's double (or + * triple) buffering, you may want to not consume all events currently available, because you + * could be still working on an older frame, but there could already have been events that + * arrived that are more recent. * @return whether any events were actually consumed */ - bool consumeBatchedInputEvents(std::optional<nsecs_t> frameTime); + bool consumeBatchedInputEvents(std::optional<nsecs_t> requestedFrameTime); + /** * Returns true when there is *likely* a pending batch or a pending event in the channel. * @@ -119,7 +115,7 @@ public: private: std::shared_ptr<InputChannel> mChannel; - std::shared_ptr<LooperInterface> mLooper; + sp<Looper> mLooper; InputConsumerCallbacks& mCallbacks; std::unique_ptr<Resampler> mResampler; @@ -200,20 +196,33 @@ private: /** * Batched InputMessages, per deviceId. * For each device, we are storing a queue of batched messages. These will all be collapsed into - * a single MotionEvent (up to a specific frameTime) when the consumer calls + * a single MotionEvent (up to a specific requestedFrameTime) when the consumer calls * `consumeBatchedInputEvents`. */ std::map<DeviceId, std::queue<InputMessage>> mBatches; /** * Creates a MotionEvent by consuming samples from the provided queue. If one message has - * eventTime > frameTime, all subsequent messages in the queue will be skipped. It is assumed - * that messages are queued in chronological order. In other words, only events that occurred - * prior to the requested frameTime will be consumed. - * @param frameTime the time up to which to consume events + * eventTime > adjustedFrameTime, all subsequent messages in the queue will be skipped. It is + * assumed that messages are queued in chronological order. In other words, only events that + * occurred prior to the adjustedFrameTime will be consumed. + * @param requestedFrameTime the time up to which to consume events. * @param messages the queue of messages to consume from */ std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>> createBatchedMotionEvent( - const nsecs_t frameTime, std::queue<InputMessage>& messages); + const nsecs_t requestedFrameTime, std::queue<InputMessage>& messages); + + /** + * Consumes the batched input events, optionally allowing the caller to specify a device id + * and/or requestedFrameTime threshold. It is not guaranteed that consumption will occur at + * requestedFrameTime. + * @param deviceId The device id from which to consume events. If std::nullopt, consumes events + * from any device id. + * @param requestedFrameTime The time up to which consume the events. If std::nullopt, consumes + * input events with any timestamp. + * @return Whether or not any events were consumed. + */ + bool consumeBatchedInputEvents(std::optional<DeviceId> deviceId, + std::optional<nsecs_t> requestedFrameTime); /** * A map from a single sequence number to several sequence numbers. This is needed because of * batching. When batching is enabled, a single MotionEvent will contain several samples. Each diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index 92d5ec4d4e..67b37b1213 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -126,9 +126,9 @@ public: bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, Vector<KeyEvent>& outEvents) const; - /* Maps an Android key code to another Android key code. This mapping is applied after scanCode - * and usageCodes are mapped to corresponding Android Keycode */ - void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode); + /* Maps some Android key code to another Android key code. This mapping is applied after + * scanCode and usageCodes are mapped to corresponding Android Keycode */ + void setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping); /* Maps a scan code and usage code to a key code, in case this key map overrides * the mapping in some way. */ diff --git a/include/input/LooperInterface.h b/include/input/LooperInterface.h deleted file mode 100644 index 2d6719c965..0000000000 --- a/include/input/LooperInterface.h +++ /dev/null @@ -1,39 +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. - */ - -#pragma once - -#include <utils/Looper.h> -#include <utils/StrongPointer.h> - -namespace android { - -/** - * LooperInterface allows the use of TestLooper in InputConsumerNoResampling without reassigning to - * Looper. LooperInterface is needed to control how InputConsumerNoResampling consumes and batches - * InputMessages. - */ -class LooperInterface { -public: - virtual ~LooperInterface() = default; - - virtual int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, - void* data) = 0; - virtual int removeFd(int fd) = 0; - - virtual sp<Looper> getLooper() const = 0; -}; -} // namespace android diff --git a/include/input/Resampler.h b/include/input/Resampler.h index 2892137ae7..dcb25b729f 100644 --- a/include/input/Resampler.h +++ b/include/input/Resampler.h @@ -35,9 +35,9 @@ struct Resampler { virtual ~Resampler() = default; /** - * Tries to resample motionEvent at resampleTime. The provided resampleTime must be greater than + * Tries to resample motionEvent at frameTime. The provided frameTime must be greater than * the latest sample time of motionEvent. It is not guaranteed that resampling occurs at - * resampleTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent + * frameTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent * may be resampled by another method, or not resampled at all. Furthermore, it is the * implementer's responsibility to guarantee the following: * - If resampling occurs, a single additional sample should be added to motionEvent. That is, @@ -45,15 +45,21 @@ struct Resampler { * samples by the end of the resampling. No other field of motionEvent should be modified. * - If resampling does not occur, then motionEvent must not be modified in any way. */ - virtual void resampleMotionEvent(std::chrono::nanoseconds resampleTime, - MotionEvent& motionEvent, + virtual void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent, const InputMessage* futureSample) = 0; + + /** + * Returns resample latency. Resample latency is the time difference between frame time and + * resample time. More precisely, let frameTime and resampleTime be two timestamps, and + * frameTime > resampleTime. Resample latency is defined as frameTime - resampleTime. + */ + virtual std::chrono::nanoseconds getResampleLatency() const = 0; }; class LegacyResampler final : public Resampler { public: /** - * Tries to resample `motionEvent` at `resampleTime` by adding a resampled sample at the end of + * Tries to resample `motionEvent` at `frameTime` by adding a resampled sample at the end of * `motionEvent` with eventTime equal to `resampleTime` and pointer coordinates determined by * linear interpolation or linear extrapolation. An earlier `resampleTime` will be used if * extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is @@ -61,9 +67,11 @@ public: * data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and * `motionEvent` is unmodified. */ - void resampleMotionEvent(std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent, + void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent, const InputMessage* futureSample) override; + std::chrono::nanoseconds getResampleLatency() const override; + private: struct Pointer { PointerProperties properties; diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 319716ec81..cbba7118b6 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -40,6 +40,7 @@ ndk_headers { cc_library_headers { name: "libarect_headers", + host_supported: true, vendor_available: true, min_sdk_version: "29", // TODO(b/153609531): remove when no longer needed. diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 1d26d8543d..6698d0c0cd 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -232,6 +232,15 @@ static const void* printReturnCommand(std::ostream& out, const void* _cmd) { return cmd; } +static void printReturnCommandParcel(std::ostream& out, const Parcel& parcel) { + const void* cmds = parcel.data(); + out << "\t" << HexDump(cmds, parcel.dataSize()) << "\n"; + IF_LOG_COMMANDS() { + const void* end = parcel.data() + parcel.dataSize(); + while (cmds < end) cmds = printReturnCommand(out, cmds); + } +} + static const void* printCommand(std::ostream& out, const void* _cmd) { static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; @@ -1235,13 +1244,15 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) if (err >= NO_ERROR) { if (bwr.write_consumed > 0) { - if (bwr.write_consumed < mOut.dataSize()) + if (bwr.write_consumed < mOut.dataSize()) { + std::ostringstream logStream; + printReturnCommandParcel(logStream, mIn); LOG_ALWAYS_FATAL("Driver did not consume write buffer. " - "err: %s consumed: %zu of %zu", - statusToString(err).c_str(), - (size_t)bwr.write_consumed, - mOut.dataSize()); - else { + "err: %s consumed: %zu of %zu.\n" + "Return command: %s", + statusToString(err).c_str(), (size_t)bwr.write_consumed, + mOut.dataSize(), logStream.str().c_str()); + } else { mOut.setDataSize(0); processPostWriteDerefs(); } @@ -1252,14 +1263,8 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) } IF_LOG_COMMANDS() { std::ostringstream logStream; - logStream << "Remaining data size: " << mOut.dataSize() << "\n"; - logStream << "Received commands from driver: "; - const void* cmds = mIn.data(); - const void* end = mIn.data() + mIn.dataSize(); - logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n"; - while (cmds < end) cmds = printReturnCommand(logStream, cmds); - std::string message = logStream.str(); - ALOGI("%s", message.c_str()); + printReturnCommandParcel(logStream, mIn); + ALOGI("%s", logStream.str().c_str()); } return NO_ERROR; } diff --git a/libs/binder/ndk/include_ndk/android/persistable_bundle.h b/libs/binder/ndk/include_ndk/android/persistable_bundle.h index 5e0d4da97b..1d516aea9d 100644 --- a/libs/binder/ndk/include_ndk/android/persistable_bundle.h +++ b/libs/binder/ndk/include_ndk/android/persistable_bundle.h @@ -17,13 +17,6 @@ #pragma once #include <android/binder_parcel.h> -#if defined(__ANDROID_VENDOR__) -#include <android/llndk-versioning.h> -#else -#if !defined(__INTRODUCED_IN_LLNDK) -#define __INTRODUCED_IN_LLNDK(level) __attribute__((annotate("introduced_in_llndk=" #level))) -#endif -#endif // __ANDROID_VENDOR__ #include <stdbool.h> #include <stdint.h> #include <sys/cdefs.h> @@ -83,8 +76,7 @@ typedef char* _Nullable (*_Nonnull APersistableBundle_stringAllocator)(int32_t s * * \return Pointer to a new APersistableBundle */ -APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); +APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__); /** * Create a new APersistableBundle based off an existing APersistableBundle. @@ -98,7 +90,7 @@ APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID * \return Pointer to a new APersistableBundle */ APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _Nonnull pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Delete an APersistableBundle. This must always be called when finished using @@ -109,7 +101,7 @@ APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _ * Available since API level 202404. */ void APersistableBundle_delete(APersistableBundle* _Nullable pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Check for equality of APersistableBundles. @@ -123,7 +115,7 @@ void APersistableBundle_delete(APersistableBundle* _Nullable pBundle) */ bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs, const APersistableBundle* _Nonnull rhs) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Read an APersistableBundle from an AParcel. @@ -142,7 +134,7 @@ bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs, */ binder_status_t APersistableBundle_readFromParcel( const AParcel* _Nonnull parcel, APersistableBundle* _Nullable* _Nonnull outPBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Write an APersistableBundle to an AParcel. @@ -162,7 +154,7 @@ binder_status_t APersistableBundle_readFromParcel( */ binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonnull pBundle, AParcel* _Nonnull parcel) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get the size of an APersistableBundle. This is the number of mappings in the @@ -175,7 +167,7 @@ binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonn * \return number of mappings in the object */ int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Erase any entries added with the provided key. @@ -188,7 +180,7 @@ int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle) * \return number of entries erased. Either 0 or 1. */ int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a boolean associated with the provided key. @@ -201,8 +193,7 @@ int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const cha * Available since API level 202404. */ void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - bool val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + bool val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int32_t associated with the provided key. @@ -215,8 +206,7 @@ void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const c * Available since API level 202404. */ void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int32_t val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int64_t associated with the provided key. @@ -229,8 +219,7 @@ void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char* * Available since API level 202404. */ void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int64_t val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int64_t val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a double associated with the provided key. @@ -243,8 +232,7 @@ void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char * Available since API level 202404. */ void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - double val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + double val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a string associated with the provided key. @@ -258,8 +246,7 @@ void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const ch * Available since API level 202404. */ void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a boolean vector associated with the provided key. @@ -275,8 +262,7 @@ void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const ch */ void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const bool* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int32_t vector associated with the provided key. @@ -292,7 +278,7 @@ void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle, */ void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const int32_t* _Nonnull vec, int32_t num) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int64_t vector associated with the provided key. @@ -308,8 +294,7 @@ void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const */ void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const int64_t* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a double vector associated with the provided key. @@ -325,8 +310,7 @@ void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle, */ void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const double* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a string vector associated with the provided key. @@ -343,7 +327,7 @@ void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle, void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const char* _Nullable const* _Nullable vec, int32_t num) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an APersistableBundle associated with the provided key. @@ -359,7 +343,7 @@ void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle, void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const APersistableBundle* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a boolean associated with the provided key. @@ -374,7 +358,7 @@ void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundl */ bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, bool* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int32_t associated with the provided key. @@ -388,8 +372,7 @@ bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle, * \return true if a value exists for the provided key */ bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int64_t associated with the provided key. @@ -404,7 +387,7 @@ bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const */ bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int64_t* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a double associated with the provided key. @@ -419,7 +402,7 @@ bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle, */ bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, double* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a string associated with the provided key. @@ -440,8 +423,7 @@ bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle, int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, char* _Nullable* _Nonnull val, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a boolean vector associated with the provided key and place it in the @@ -468,7 +450,7 @@ int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle, int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, bool* _Nullable buffer, int32_t bufferSizeBytes) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int32_t vector associated with the provided key and place it in the @@ -494,8 +476,7 @@ int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull p */ int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int32_t* _Nullable buffer, - int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int64_t vector associated with the provided key and place it in the @@ -521,8 +502,8 @@ int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBund */ int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int64_t* _Nullable buffer, - int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t bufferSizeBytes) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a double vector associated with the provided key and place it in the @@ -549,7 +530,7 @@ int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBun int32_t APersistableBundle_getDoubleVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, double* _Nullable buffer, int32_t bufferSizeBytes) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a string vector associated with the provided key and place it in the @@ -586,7 +567,7 @@ int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pB int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an APersistableBundle* associated with the provided key. @@ -605,7 +586,7 @@ int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pB bool APersistableBundle_getPersistableBundle(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, APersistableBundle* _Nullable* _Nonnull outBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -638,7 +619,7 @@ int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBu int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -669,8 +650,7 @@ int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBu int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -701,8 +681,7 @@ int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle int32_t APersistableBundle_getLongKeys(const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -734,8 +713,8 @@ int32_t APersistableBundle_getDoubleKeys(const APersistableBundle* _Nonnull pBun char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -767,8 +746,8 @@ int32_t APersistableBundle_getStringKeys(const APersistableBundle* _Nonnull pBun char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -801,7 +780,7 @@ int32_t APersistableBundle_getBooleanVectorKeys(const APersistableBundle* _Nonnu int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -834,7 +813,7 @@ int32_t APersistableBundle_getIntVectorKeys(const APersistableBundle* _Nonnull p int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -867,7 +846,7 @@ int32_t APersistableBundle_getLongVectorKeys(const APersistableBundle* _Nonnull int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -899,7 +878,7 @@ int32_t APersistableBundle_getDoubleVectorKeys(const APersistableBundle* _Nonnul int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -932,7 +911,7 @@ int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnul int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -963,6 +942,6 @@ int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnul int32_t APersistableBundle_getPersistableBundleKeys( const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); __END_DECLS diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 41b30a0a0f..cc4943b9c3 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -18,7 +18,6 @@ #include <android/binder_ibinder.h> #include <android/binder_status.h> -#include <android/llndk-versioning.h> #include <sys/cdefs.h> __BEGIN_DECLS @@ -257,8 +256,7 @@ void AServiceManager_getUpdatableApexName(const char* instance, void* context, * \return the result of dlopen of the specified HAL */ void* AServiceManager_openDeclaredPassthroughHal(const char* interface, const char* instance, - int flag) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int flag) __INTRODUCED_IN(__ANDROID_API_V__); /** * Prevent lazy services without client from shutting down their process diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index f518a22902..3cd2b9a891 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -46,6 +46,7 @@ #include "android/binder_ibinder.h" using namespace android; +using namespace std::chrono_literals; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest"; @@ -54,7 +55,7 @@ constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestServi constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService"; constexpr char kBinderNdkUnitTestServiceFlagged[] = "BinderNdkUnitTestFlagged"; -constexpr unsigned int kShutdownWaitTime = 11; +constexpr auto kShutdownWaitTime = 30s; constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715; class MyTestFoo : public IFoo { @@ -253,12 +254,22 @@ int lazyService(const char* instance) { } bool isServiceRunning(const char* serviceName) { - AIBinder* binder = AServiceManager_checkService(serviceName); - if (binder == nullptr) { - return false; + static const sp<android::IServiceManager> sm(android::defaultServiceManager()); + const Vector<String16> services = sm->listServices(); + for (const auto service : services) { + if (service == String16(serviceName)) return true; } - AIBinder_decStrong(binder); + return false; +} +bool isServiceShutdownWithWait(const char* serviceName) { + LOG(INFO) << "About to check and wait for shutdown of " << std::string(serviceName); + const auto before = std::chrono::steady_clock::now(); + while (isServiceRunning(serviceName)) { + sleep(1); + const auto after = std::chrono::steady_clock::now(); + if (after - before >= kShutdownWaitTime) return false; + } return true; } @@ -450,8 +461,8 @@ TEST(NdkBinder, CheckLazyServiceShutDown) { service = nullptr; IPCThreadState::self()->flushCommands(); // Make sure the service is dead after some time of no use - sleep(kShutdownWaitTime); - ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService)); + ASSERT_TRUE(isServiceShutdownWithWait(kLazyBinderNdkUnitTestService)) + << "Service failed to shut down"; } TEST(NdkBinder, ForcedPersistenceTest) { @@ -466,14 +477,12 @@ TEST(NdkBinder, ForcedPersistenceTest) { service = nullptr; IPCThreadState::self()->flushCommands(); - sleep(kShutdownWaitTime); - - bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService); - if (i == 0) { - ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have."; + ASSERT_TRUE(isServiceRunning(kForcePersistNdkUnitTestService)) + << "Service shut down when it shouldn't have."; } else { - ASSERT_FALSE(isRunning) << "Service failed to shut down."; + ASSERT_TRUE(isServiceShutdownWithWait(kForcePersistNdkUnitTestService)) + << "Service failed to shut down"; } } } @@ -491,10 +500,7 @@ TEST(NdkBinder, ActiveServicesCallbackTest) { service = nullptr; IPCThreadState::self()->flushCommands(); - LOG(INFO) << "ActiveServicesCallbackTest about to sleep"; - sleep(kShutdownWaitTime); - - ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService)) + ASSERT_TRUE(isServiceShutdownWithWait(kActiveServicesNdkUnitTestService)) << "Service failed to shut down."; } diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp index 92dab19a63..482d197688 100644 --- a/libs/binder/tests/binderCacheUnitTest.cpp +++ b/libs/binder/tests/binderCacheUnitTest.cpp @@ -137,9 +137,9 @@ TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) { ASSERT_EQ(binder1, result); // Kill the server, this should remove from cache. - foo.killServer(binder1); pid_t pid; ASSERT_EQ(OK, binder1->getDebugPid(&pid)); + foo.killServer(binder1); system(("kill -9 " + std::to_string(pid)).c_str()); sp<IBinder> binder2 = sp<BBinder>::make(); diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index fbca35e81f..0ef200bcbe 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -454,7 +454,7 @@ TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) { GTEST_SKIP() << "This test requires multiple threads"; } - constexpr size_t kNumThreads = 10; + constexpr size_t kNumThreads = 5; auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); @@ -499,11 +499,11 @@ static void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCall EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs); - // Potential flake, but make sure calls are handled in parallel. Due - // to past flakes, this only checks that the amount of time taken has - // some parallelism. Other tests such as ThreadPoolGreaterThanEqualRequested - // check this more exactly. - EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs); + // b/272429574, b/365294257 + // This flakes too much to test. Parallelization is tested + // in ThreadPoolGreaterThanEqualRequested and other tests. + // Test to make sure calls are handled in parallel. + // EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs); } TEST_P(BinderRpc, ThreadPoolOverSaturated) { @@ -515,8 +515,7 @@ TEST_P(BinderRpc, ThreadPoolOverSaturated) { constexpr size_t kNumCalls = kNumThreads + 3; auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); - // b/272429574 - below 500ms, the test fails - testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/); + testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/); } TEST_P(BinderRpc, ThreadPoolLimitOutgoing) { @@ -530,8 +529,7 @@ TEST_P(BinderRpc, ThreadPoolLimitOutgoing) { auto proc = createRpcTestSocketServerProcess( {.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections}); - // b/272429574 - below 500ms, the test fails - testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/); + testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/); } TEST_P(BinderRpc, ThreadingStressTest) { diff --git a/libs/debugstore/OWNERS b/libs/debugstore/OWNERS index 428a1a2215..c8e22b70ff 100644 --- a/libs/debugstore/OWNERS +++ b/libs/debugstore/OWNERS @@ -1,3 +1,2 @@ benmiles@google.com -gaillard@google.com mohamadmahmoud@google.com diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3c1971fd81..25e6a52ed1 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -1124,6 +1124,17 @@ public: AsyncWorker::getInstance().post( [listener = mListener, slots = slots]() { listener->onBuffersDiscarded(slots); }); } + + void onBufferDetached(int slot) override { + AsyncWorker::getInstance().post( + [listener = mListener, slot = slot]() { listener->onBufferDetached(slot); }); + } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + void onBufferAttached() override { + AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferAttached(); }); + } +#endif }; // Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls @@ -1255,6 +1266,11 @@ void BLASTBufferQueue::setTransactionHangCallback( mTransactionHangCallback = std::move(callback); } +void BLASTBufferQueue::setApplyToken(sp<IBinder> applyToken) { + std::lock_guard _lock{mMutex}; + mApplyToken = std::move(applyToken); +} + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index a4d105d320..da74e9cde6 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -45,7 +45,10 @@ #include <system/window.h> +#include <com_android_graphics_libgui_flags.h> + namespace android { +using namespace com::android::graphics::libgui; // Macros for include BufferQueueCore information in log messages #define BQ_LOGV(x, ...) \ @@ -924,6 +927,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, uint64_t currentFrameNumber = 0; BufferItem item; int connectedApi; + bool enableEglCpuThrottling = true; sp<Fence> lastQueuedFence; { // Autolock scope @@ -1097,6 +1101,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, VALIDATE_CONSISTENCY(); connectedApi = mCore->mConnectedApi; + if (flags::bq_producer_throttles_only_async_mode()) { + enableEglCpuThrottling = mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock; + } lastQueuedFence = std::move(mLastQueueBufferFence); mLastQueueBufferFence = std::move(acquireFence); @@ -1142,7 +1149,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, } // Wait without lock held - if (connectedApi == NATIVE_WINDOW_API_EGL) { + if (connectedApi == NATIVE_WINDOW_API_EGL && enableEglCpuThrottling) { // Waiting here allows for two full buffers to be queued but not a // third. In the event that frames take varying time, this makes a // small trade-off in favor of latency rather than throughput. diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 7700795e1d..8b9b090496 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -184,4 +184,10 @@ bool BnProducerListener::needsReleaseNotify() { void BnProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*discardedSlots*/) { } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) +bool BnProducerListener::needsAttachNotify() { + return true; +} +#endif + } // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index c5f9c38ca3..f126c0be2f 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -139,9 +139,9 @@ sp<Surface> SurfaceControl::generateSurfaceLocked() uint32_t ignore; auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow | ISurfaceComposerClient::eOpaque); - mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat, + mBbqChild = mClient->createSurface(String8::format("[BBQ] %s", mName.c_str()), 0, 0, mFormat, flags, mHandle, {}, &ignore); - mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); + mBbq = sp<BLASTBufferQueue>::make("[BBQ]" + mName, mBbqChild, mWidth, mHeight, mFormat); // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d787d6cc45..8592cffd15 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -142,7 +142,7 @@ public: * indicates the reason for the hang. */ void setTransactionHangCallback(std::function<void(const std::string&)> callback); - + void setApplyToken(sp<IBinder>); virtual ~BLASTBufferQueue(); void onFirstRef() override; @@ -271,7 +271,7 @@ private: // Queues up transactions using this token in SurfaceFlinger. This prevents queued up // transactions from other parts of the client from blocking this transaction. - const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = sp<BBinder>::make(); + sp<IBinder> mApplyToken GUARDED_BY(mMutex) = sp<BBinder>::make(); // Guards access to mDequeueTimestamps since we cannot hold to mMutex in onFrameDequeued or // we will deadlock. diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index 3dcc6b6670..43bf6a7d4b 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -90,6 +90,9 @@ public: Parcel* reply, uint32_t flags = 0); virtual bool needsReleaseNotify(); virtual void onBuffersDiscarded(const std::vector<int32_t>& slots); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual bool needsAttachNotify(); +#endif }; #else @@ -103,6 +106,9 @@ public: virtual ~StubProducerListener(); virtual void onBufferReleased() {} virtual bool needsReleaseNotify() { return false; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual bool needsAttachNotify() { return false; } +#endif }; } // namespace android diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig index df9b73bfcd..d3f2899ba3 100644 --- a/libs/gui/libgui_flags.aconfig +++ b/libs/gui/libgui_flags.aconfig @@ -106,4 +106,12 @@ flag { description: "Remove usage of IGBPs in the libcameraservice." bug: "342197849" is_fixed_read_only: true -} # wb_libcameraservice
\ No newline at end of file +} # wb_libcameraservice + +flag { + name: "bq_producer_throttles_only_async_mode" + namespace: "core_graphics" + description: "BufferQueueProducer only CPU throttle on queueBuffer() in async mode." + bug: "359252619" + is_fixed_read_only: true +} # bq_producer_throttles_only_async_mode diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index eb2a61d151..53f4a36c42 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -186,6 +186,10 @@ public: mBlastBufferQueueAdapter->mergeWithNextTransaction(merge, frameNumber); } + void setApplyToken(sp<IBinder> applyToken) { + mBlastBufferQueueAdapter->setApplyToken(std::move(applyToken)); + } + private: sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter; }; @@ -511,6 +515,69 @@ TEST_F(BLASTBufferQueueTest, TripleBuffering) { adapter.waitForCallbacks(); } +class WaitForCommittedCallback { +public: + WaitForCommittedCallback() = default; + ~WaitForCommittedCallback() = default; + + void wait() { + std::unique_lock lock(mMutex); + cv.wait(lock, [this] { return mCallbackReceived; }); + } + + void notify() { + std::unique_lock lock(mMutex); + mCallbackReceived = true; + cv.notify_one(); + mCallbackReceivedTimeStamp = std::chrono::system_clock::now(); + } + auto getCallback() { + return [this](void* /* unused context */, nsecs_t /* latchTime */, + const sp<Fence>& /* presentFence */, + const std::vector<SurfaceControlStats>& /* stats */) { notify(); }; + } + std::chrono::time_point<std::chrono::system_clock> mCallbackReceivedTimeStamp; + +private: + std::mutex mMutex; + std::condition_variable cv; + bool mCallbackReceived = false; +}; + +TEST_F(BLASTBufferQueueTest, setApplyToken) { + sp<IBinder> applyToken = sp<BBinder>::make(); + WaitForCommittedCallback firstTransaction; + WaitForCommittedCallback secondTransaction; + { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + adapter.setApplyToken(applyToken); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + Transaction t; + t.addTransactionCommittedCallback(firstTransaction.getCallback(), nullptr); + adapter.mergeWithNextTransaction(&t, 1); + queueBuffer(igbProducer, 127, 127, 127, + /*presentTimeDelay*/ std::chrono::nanoseconds(500ms).count()); + } + { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + adapter.setApplyToken(applyToken); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + Transaction t; + t.addTransactionCommittedCallback(secondTransaction.getCallback(), nullptr); + adapter.mergeWithNextTransaction(&t, 1); + queueBuffer(igbProducer, 127, 127, 127, /*presentTimeDelay*/ 0); + } + + firstTransaction.wait(); + secondTransaction.wait(); + EXPECT_GT(secondTransaction.mCallbackReceivedTimeStamp, + firstTransaction.mCallbackReceivedTimeStamp); +} + TEST_F(BLASTBufferQueueTest, SetCrop_Item) { uint8_t r = 255; uint8_t g = 0; diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp index eb419180e7..cdbc1869c3 100644 --- a/libs/input/InputConsumerNoResampling.cpp +++ b/libs/input/InputConsumerNoResampling.cpp @@ -37,6 +37,8 @@ namespace android { namespace { +using std::chrono::nanoseconds; + /** * Log debug messages relating to the consumer end of the transport channel. * Enable this via "adb shell setprop log.tag.InputTransportConsumer DEBUG" (requires restart) @@ -44,27 +46,6 @@ namespace { const bool DEBUG_TRANSPORT_CONSUMER = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO); -/** - * RealLooper is a wrapper of Looper. All the member functions exclusively call the internal looper. - * This class' behavior is the same as Looper. - */ -class RealLooper final : public LooperInterface { -public: - RealLooper(sp<Looper> looper) : mLooper{looper} {} - - int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, - void* data) override { - return mLooper->addFd(fd, ident, events, callback, data); - } - - int removeFd(int fd) override { return mLooper->removeFd(fd); } - - sp<Looper> getLooper() const override { return mLooper; } - -private: - sp<Looper> mLooper; -}; - std::unique_ptr<KeyEvent> createKeyEvent(const InputMessage& msg) { std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>(); event->initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source, @@ -199,12 +180,12 @@ using android::base::Result; // --- InputConsumerNoResampling --- InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, - std::shared_ptr<LooperInterface> looper, + sp<Looper> looper, InputConsumerCallbacks& callbacks, std::unique_ptr<Resampler> resampler) : mChannel{channel}, mLooper{looper}, - mCallbacks(callbacks), + mCallbacks{callbacks}, mResampler{std::move(resampler)}, mFdEvents(0) { LOG_ALWAYS_FATAL_IF(mLooper == nullptr); @@ -216,16 +197,9 @@ InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<Input setFdEvents(ALOOPER_EVENT_INPUT); } -InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, - sp<Looper> looper, - InputConsumerCallbacks& callbacks, - std::unique_ptr<Resampler> resampler) - : InputConsumerNoResampling(channel, std::make_shared<RealLooper>(looper), callbacks, - std::move(resampler)) {} - InputConsumerNoResampling::~InputConsumerNoResampling() { ensureCalledOnLooperThread(__func__); - consumeBatchedInputEvents(std::nullopt); + consumeBatchedInputEvents(/*requestedFrameTime=*/std::nullopt); while (!mOutboundQueue.empty()) { processOutboundEvents(); // This is our last chance to ack the events. If we don't ack them here, we will get an ANR, @@ -251,8 +225,7 @@ int InputConsumerNoResampling::handleReceiveCallback(int events) { int handledEvents = 0; if (events & ALOOPER_EVENT_INPUT) { - std::vector<InputMessage> messages = readAllMessages(); - handleMessages(std::move(messages)); + handleMessages(readAllMessages()); handledEvents |= ALOOPER_EVENT_INPUT; } @@ -360,10 +333,8 @@ void InputConsumerNoResampling::handleMessages(std::vector<InputMessage>&& messa // add it to batch mBatches[deviceId].emplace(msg); } else { - // consume all pending batches for this event immediately - // TODO(b/329776327): figure out if this could be smarter by limiting the - // consumption only to the current device. - consumeBatchedInputEvents(std::nullopt); + // consume all pending batches for this device immediately + consumeBatchedInputEvents(deviceId, /*requestedFrameTime=*/std::nullopt); handleMessage(msg); } } else { @@ -481,11 +452,16 @@ void InputConsumerNoResampling::handleMessage(const InputMessage& msg) const { } std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>> -InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t frameTime, +InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t requestedFrameTime, std::queue<InputMessage>& messages) { std::unique_ptr<MotionEvent> motionEvent; std::optional<uint32_t> firstSeqForBatch; - while (!messages.empty() && !(messages.front().body.motion.eventTime > frameTime)) { + const nanoseconds resampleLatency = + (mResampler != nullptr) ? mResampler->getResampleLatency() : nanoseconds{0}; + const nanoseconds adjustedFrameTime = nanoseconds{requestedFrameTime} - resampleLatency; + + while (!messages.empty() && + (messages.front().body.motion.eventTime <= adjustedFrameTime.count())) { if (motionEvent == nullptr) { motionEvent = createMotionEvent(messages.front()); firstSeqForBatch = messages.front().header.seq; @@ -504,40 +480,55 @@ InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t frameTime, if (!messages.empty()) { futureSample = &messages.front(); } - mResampler->resampleMotionEvent(static_cast<std::chrono::nanoseconds>(frameTime), - *motionEvent, futureSample); + mResampler->resampleMotionEvent(nanoseconds{requestedFrameTime}, *motionEvent, + futureSample); } return std::make_pair(std::move(motionEvent), firstSeqForBatch); } bool InputConsumerNoResampling::consumeBatchedInputEvents( - std::optional<nsecs_t> requestedFrameTime) { + std::optional<DeviceId> deviceId, std::optional<nsecs_t> requestedFrameTime) { ensureCalledOnLooperThread(__func__); // When batching is not enabled, we want to consume all events. That's equivalent to having an - // infinite frameTime. - const nsecs_t frameTime = requestedFrameTime.value_or(std::numeric_limits<nsecs_t>::max()); + // infinite requestedFrameTime. + requestedFrameTime = requestedFrameTime.value_or(std::numeric_limits<nsecs_t>::max()); bool producedEvents = false; - for (auto& [_, messages] : mBatches) { - auto [motion, firstSeqForBatch] = createBatchedMotionEvent(frameTime, messages); + + for (auto deviceIdIter = (deviceId.has_value()) ? (mBatches.find(*deviceId)) + : (mBatches.begin()); + deviceIdIter != mBatches.cend(); ++deviceIdIter) { + std::queue<InputMessage>& messages = deviceIdIter->second; + auto [motion, firstSeqForBatch] = createBatchedMotionEvent(*requestedFrameTime, messages); if (motion != nullptr) { LOG_ALWAYS_FATAL_IF(!firstSeqForBatch.has_value()); mCallbacks.onMotionEvent(std::move(motion), *firstSeqForBatch); producedEvents = true; } else { - // This is OK, it just means that the frameTime is too old (all events that we have - // pending are in the future of the frametime). Maybe print a - // warning? If there are multiple devices active though, this might be normal and can - // just be ignored, unless none of them resulted in any consumption (in that case, this - // function would already return "false" so we could just leave it up to the caller). + // This is OK, it just means that the requestedFrameTime is too old (all events that we + // have pending are in the future of the requestedFrameTime). Maybe print a warning? If + // there are multiple devices active though, this might be normal and can just be + // ignored, unless none of them resulted in any consumption (in that case, this function + // would already return "false" so we could just leave it up to the caller). + } + + if (deviceId.has_value()) { + // We already consumed events for this device. Break here to prevent iterating over the + // other devices. + break; } } std::erase_if(mBatches, [](const auto& pair) { return pair.second.empty(); }); return producedEvents; } +bool InputConsumerNoResampling::consumeBatchedInputEvents( + std::optional<nsecs_t> requestedFrameTime) { + return consumeBatchedInputEvents(/*deviceId=*/std::nullopt, requestedFrameTime); +} + void InputConsumerNoResampling::ensureCalledOnLooperThread(const char* func) const { sp<Looper> callingThreadLooper = Looper::getForThread(); - if (callingThreadLooper != mLooper->getLooper()) { + if (callingThreadLooper != mLooper) { LOG(FATAL) << "The function " << func << " can only be called on the looper thread"; } } diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 1cf5612d45..b0563abaf7 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -317,19 +317,8 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t return true; } -void KeyCharacterMap::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) { - if (fromKeyCode == toKeyCode) { - mKeyRemapping.erase(fromKeyCode); -#if DEBUG_MAPPING - ALOGD("addKeyRemapping: Cleared remapping forKeyCode=%d ~ Result Successful.", fromKeyCode); -#endif - return; - } - mKeyRemapping.insert_or_assign(fromKeyCode, toKeyCode); -#if DEBUG_MAPPING - ALOGD("addKeyRemapping: fromKeyCode=%d, toKeyCode=%d ~ Result Successful.", fromKeyCode, - toKeyCode); -#endif +void KeyCharacterMap::setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping) { + mKeyRemapping = keyRemapping; } status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const { diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp index c663649091..51fadf8ec1 100644 --- a/libs/input/Resampler.cpp +++ b/libs/input/Resampler.cpp @@ -241,13 +241,19 @@ inline void LegacyResampler::addSampleToMotionEvent(const Sample& sample, motionEvent.getId()); } -void LegacyResampler::resampleMotionEvent(nanoseconds resampleTime, MotionEvent& motionEvent, +nanoseconds LegacyResampler::getResampleLatency() const { + return RESAMPLE_LATENCY; +} + +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); const std::optional<Sample> sample = (futureSample != nullptr) diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index f1c4aed7af..60fb00e128 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -192,3 +192,18 @@ flag { description: "Prevents touchpad gesture changing window focus." bug: "364460018" } + +flag { + name: "enable_input_policy_profile" + namespace: "input" + description: "Apply input policy profile for input threads." + bug: "347122505" + is_fixed_read_only: true +} + +flag { + name: "keyboard_repeat_keys" + namespace: "input" + description: "Allow user to enable key repeats or configure timeout before key repeat and key repeat delay rates." + bug: "336585002" +} diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 43bc8948dd..81c6175805 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -27,7 +27,6 @@ cc_test { "Resampler_test.cpp", "RingBuffer_test.cpp", "TestInputChannel.cpp", - "TestLooper.cpp", "TfLiteMotionPredictor_test.cpp", "TouchResampling_test.cpp", "TouchVideoFrame_test.cpp", @@ -95,6 +94,7 @@ cc_test { }, }, }, + native_coverage: false, } // NOTE: This is a compile time test, and does not need to be diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp index c30f243398..d708316236 100644 --- a/libs/input/tests/InputConsumer_test.cpp +++ b/libs/input/tests/InputConsumer_test.cpp @@ -18,32 +18,61 @@ #include <memory> #include <optional> -#include <utility> +#include <TestEventMatchers.h> #include <TestInputChannel.h> -#include <TestLooper.h> #include <android-base/logging.h> +#include <gmock/gmock.h> #include <gtest/gtest.h> #include <input/BlockingQueue.h> #include <input/InputEventBuilders.h> +#include <utils/Looper.h> #include <utils/StrongPointer.h> namespace android { +namespace { + +using std::chrono::nanoseconds; + +using ::testing::AllOf; +using ::testing::Matcher; +using ::testing::Not; + +} // namespace + class InputConsumerTest : public testing::Test, public InputConsumerCallbacks { protected: InputConsumerTest() : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")}, - mTestLooper{std::make_shared<TestLooper>()} { - Looper::setForThread(mTestLooper->getLooper()); - mConsumer = std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper, - *this, /*resampler=*/nullptr); + mLooper{sp<Looper>::make(/*allowNonCallbacks=*/false)} { + Looper::setForThread(mLooper); + mConsumer = + std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mLooper, *this, + std::make_unique<LegacyResampler>()); } - void assertOnBatchedInputEventPendingWasCalled(); + void invokeLooperCallback() const { + sp<LooperCallback> callback; + ASSERT_TRUE(mLooper->getFdStateDebug(mClientTestChannel->getFd(), /*ident=*/nullptr, + /*events=*/nullptr, &callback, /*data=*/nullptr)); + callback->handleEvent(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT, /*data=*/nullptr); + } + + void assertOnBatchedInputEventPendingWasCalled() { + ASSERT_GT(mOnBatchedInputEventPendingInvocationCount, 0UL) + << "onBatchedInputEventPending has not been called."; + --mOnBatchedInputEventPendingInvocationCount; + } + + void assertReceivedMotionEvent(const Matcher<MotionEvent>& matcher) { + std::unique_ptr<MotionEvent> motionEvent = mMotionEvents.pop(); + ASSERT_NE(motionEvent, nullptr); + EXPECT_THAT(*motionEvent, matcher); + } std::shared_ptr<TestInputChannel> mClientTestChannel; - std::shared_ptr<TestLooper> mTestLooper; + sp<Looper> mLooper; std::unique_ptr<InputConsumerNoResampling> mConsumer; BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents; @@ -54,7 +83,7 @@ protected: BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents; private: - size_t onBatchedInputEventPendingInvocationCount{0}; + size_t mOnBatchedInputEventPendingInvocationCount{0}; // InputConsumerCallbacks interface void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override { @@ -69,7 +98,7 @@ private: if (!mConsumer->probablyHasInput()) { ADD_FAILURE() << "should deterministically have input because there is a batch"; } - ++onBatchedInputEventPendingInvocationCount; + ++mOnBatchedInputEventPendingInvocationCount; }; void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override { mFocusEvents.push(std::move(event)); @@ -89,35 +118,130 @@ private: }; }; -void InputConsumerTest::assertOnBatchedInputEventPendingWasCalled() { - ASSERT_GT(onBatchedInputEventPendingInvocationCount, 0UL) - << "onBatchedInputEventPending has not been called."; - --onBatchedInputEventPendingInvocationCount; +TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) { + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0} + .eventTime(nanoseconds{0ms}.count()) + .action(AMOTION_EVENT_ACTION_DOWN) + .build()); + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1} + .eventTime(nanoseconds{5ms}.count()) + .action(AMOTION_EVENT_ACTION_MOVE) + .build()); + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2} + .eventTime(nanoseconds{10ms}.count()) + .action(AMOTION_EVENT_ACTION_MOVE) + .build()); + + mClientTestChannel->assertNoSentMessages(); + + invokeLooperCallback(); + + assertOnBatchedInputEventPendingWasCalled(); + + mConsumer->consumeBatchedInputEvents(/*frameTime=*/std::nullopt); + + std::unique_ptr<MotionEvent> downMotionEvent = mMotionEvents.pop(); + ASSERT_NE(downMotionEvent, nullptr); + + std::unique_ptr<MotionEvent> moveMotionEvent = mMotionEvents.pop(); + ASSERT_NE(moveMotionEvent, nullptr); + EXPECT_EQ(moveMotionEvent->getHistorySize() + 1, 3UL); + + mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true); + mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true); + mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true); } -TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) { - mClientTestChannel->enqueueMessage( - InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}.build()); - mClientTestChannel->enqueueMessage( - InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}.build()); - mClientTestChannel->enqueueMessage( - InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}.build()); +TEST_F(InputConsumerTest, LastBatchedSampleIsLessThanResampleTime) { + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0} + .eventTime(nanoseconds{0ms}.count()) + .action(AMOTION_EVENT_ACTION_DOWN) + .build()); + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1} + .eventTime(nanoseconds{5ms}.count()) + .action(AMOTION_EVENT_ACTION_MOVE) + .build()); + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2} + .eventTime(nanoseconds{10ms}.count()) + .action(AMOTION_EVENT_ACTION_MOVE) + .build()); + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/3} + .eventTime(nanoseconds{15ms}.count()) + .action(AMOTION_EVENT_ACTION_MOVE) + .build()); mClientTestChannel->assertNoSentMessages(); - mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT); + invokeLooperCallback(); assertOnBatchedInputEventPendingWasCalled(); + mConsumer->consumeBatchedInputEvents(16'000'000 /*ns*/); + + std::unique_ptr<MotionEvent> downMotionEvent = mMotionEvents.pop(); + ASSERT_NE(downMotionEvent, nullptr); + + std::unique_ptr<MotionEvent> moveMotionEvent = mMotionEvents.pop(); + ASSERT_NE(moveMotionEvent, nullptr); + const size_t numSamples = moveMotionEvent->getHistorySize() + 1; + EXPECT_LT(moveMotionEvent->getHistoricalEventTime(numSamples - 2), + moveMotionEvent->getEventTime()); + + // Consume all remaining events before ending the test. Otherwise, the smart pointer that owns + // consumer is set to null before destroying consumer. This leads to a member function call on a + // null object. + // TODO(b/332613662): Remove this workaround. mConsumer->consumeBatchedInputEvents(std::nullopt); - std::unique_ptr<MotionEvent> batchedMotionEvent = mMotionEvents.pop(); - ASSERT_NE(batchedMotionEvent, nullptr); + mClientTestChannel->assertFinishMessage(/*seq=*/0, true); + mClientTestChannel->assertFinishMessage(/*seq=*/1, true); + mClientTestChannel->assertFinishMessage(/*seq=*/2, true); + mClientTestChannel->assertFinishMessage(/*seq=*/3, true); +} + +TEST_F(InputConsumerTest, BatchedEventsMultiDeviceConsumption) { + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0} + .deviceId(0) + .action(AMOTION_EVENT_ACTION_DOWN) + .build()); + + invokeLooperCallback(); + assertReceivedMotionEvent(AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_DOWN))); + + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1} + .deviceId(0) + .action(AMOTION_EVENT_ACTION_MOVE) + .build()); + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2} + .deviceId(0) + .action(AMOTION_EVENT_ACTION_MOVE) + .build()); + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/3} + .deviceId(0) + .action(AMOTION_EVENT_ACTION_MOVE) + .build()); + + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/4} + .deviceId(1) + .action(AMOTION_EVENT_ACTION_DOWN) + .build()); + + invokeLooperCallback(); + assertReceivedMotionEvent(AllOf(WithDeviceId(1), WithMotionAction(AMOTION_EVENT_ACTION_DOWN))); + + mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/5} + .deviceId(0) + .action(AMOTION_EVENT_ACTION_UP) + .build()); + + invokeLooperCallback(); + assertReceivedMotionEvent(AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + Not(MotionEventIsResampled()))); mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true); + mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true); mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true); mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true); - - EXPECT_EQ(batchedMotionEvent->getHistorySize() + 1, 3UL); + mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true); } } // namespace android diff --git a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp index 467c3b46ce..1210f711de 100644 --- a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp @@ -364,7 +364,7 @@ private: if (!mConsumer->probablyHasInput()) { ADD_FAILURE() << "should deterministically have input because there is a batch"; } - mConsumer->consumeBatchedInputEvents(std::nullopt); + mConsumer->consumeBatchedInputEvents(/*frameTime=*/std::nullopt); }; void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override { mFocusEvents.push(std::move(event)); diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp index 7ae9a28664..26dee393c1 100644 --- a/libs/input/tests/Resampler_test.cpp +++ b/libs/input/tests/Resampler_test.cpp @@ -120,6 +120,47 @@ InputStream::operator MotionEvent() const { } // namespace +/** + * The testing setup assumes an input rate of 200 Hz and a display rate of 60 Hz. This implies that + * input events are received every 5 milliseconds, while the display consumes batched events every + * ~16 milliseconds. The resampler's RESAMPLE_LATENCY constant determines the resample time, which + * is calculated as frameTime - RESAMPLE_LATENCY. resampleTime specifies the time used for + * resampling. For example, if the desired frame time consumption is ~16 milliseconds, the resample + * time would be ~11 milliseconds. Consequenly, the last added sample to the motion event has an + * event time of ~11 milliseconds. Note that there are specific scenarios where resampleMotionEvent + * is not called with a multiple of ~16 milliseconds. These cases are primarily for data addition + * or to test other functionalities of the resampler. + * + * Coordinates are calculated using linear interpolation (lerp) based on the last two available + * samples. Linear interpolation is defined as (a + alpha*(b - a)). Let t_b and t_a be the + * timestamps of samples a and b, respectively. The interpolation factor alpha is calculated as + * (resampleTime - t_a) / (t_b - t_a). The value of alpha determines whether the resampled + * coordinates are interpolated or extrapolated. If alpha falls within the semi-closed interval [0, + * 1), the coordinates are interpolated. If alpha is greater than or equal to 1, the coordinates are + * extrapolated. + * + * The timeline below depics an interpolation scenario + * -----------------------------------|---------|---------|---------|---------- + * 10ms 11ms 15ms 16ms + * MOVE | MOVE | + * resampleTime frameTime + * Based on the timeline alpha is (11 - 10)/(15 - 10) = 1/5. Thus, coordinates are interpolated. + * + * The following timeline portrays an extrapolation scenario + * -------------------------|---------|---------|-------------------|---------- + * 5ms 10ms 11ms 16ms + * MOVE MOVE | | + * resampleTime frameTime + * Likewise, alpha = (11 - 5)/(10 - 5) = 6/5. Hence, coordinates are extrapolated. + * + * If a motion event was resampled, the tests will check that the following conditions are satisfied + * to guarantee resampling correctness: + * - The motion event metadata must not change. + * - The number of samples in the motion event must only increment by 1. + * - The resampled values must be at the end of motion event coordinates. + * - The rasamples values must be near the hand calculations. + * - The resampled time must be the most recent one in motion event. + */ class ResamplerTest : public testing::Test { protected: ResamplerTest() : mResampler(std::make_unique<LegacyResampler>()) {} @@ -225,7 +266,7 @@ TEST_F(ResamplerTest, NonResampledAxesArePreserved) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); EXPECT_EQ(motionEvent.getTouchMajor(0), TOUCH_MAJOR_VALUE); @@ -243,7 +284,7 @@ TEST_F(ResamplerTest, SinglePointerNotEnoughDataToResample) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } @@ -270,23 +311,6 @@ TEST_F(ResamplerTest, SinglePointerDifferentDeviceIdBetweenMotionEvents) { assertMotionEventIsNotResampled(originalMotionEvent, motionFromSecondDevice); } -// Increments of 16 ms for display refresh rate -// Increments of 6 ms for input frequency -// Resampling latency is known to be 5 ms -// Therefore, first resampling time will be 11 ms - -/** - * Timeline - * ----+----------------------+---------+---------+---------+---------- - * 0ms 10ms 11ms 15ms 16ms - * DOWN MOVE | MSG | - * resample frame - * Resampling occurs at 11ms. It is possible to interpolate because there is a sample available - * after the resample time. It is assumed that the InputMessage frequency is 100Hz, and the frame - * frequency is 60Hz. This means the time between InputMessage samples is 10ms, and the time between - * frames is ~16ms. Resample time is frameTime - RESAMPLE_LATENCY. The resampled sample must be the - * last one in the batch to consume. - */ TEST_F(ResamplerTest, SinglePointerSingleSampleInterpolation) { MotionEvent motionEvent = InputStream{{InputSample{10ms, @@ -297,7 +321,7 @@ TEST_F(ResamplerTest, SinglePointerSingleSampleInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, {Pointer{.id = 0, @@ -338,18 +362,13 @@ TEST_F(ResamplerTest, SinglePointerSingleSampleExtrapolation) { const MotionEvent originalMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(11ms, secondMotionEvent, nullptr); + mResampler->resampleMotionEvent(16ms, secondMotionEvent, nullptr); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, secondMotionEvent, {Pointer{.id = 0, .x = 2.2f, .y = 4.4f, .isResampled = true}}); - // Integrity of the whole motionEvent - // History size should increment by 1 - // Check if the resampled value is the last one - // Check if the resampleTime is correct - // Check if the PointerCoords are consistent with the other computations } TEST_F(ResamplerTest, SinglePointerMultipleSampleInterpolation) { @@ -364,7 +383,7 @@ TEST_F(ResamplerTest, SinglePointerMultipleSampleInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, {Pointer{.id = 0, @@ -382,7 +401,7 @@ TEST_F(ResamplerTest, SinglePointerMultipleSampleExtrapolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, nullptr); + mResampler->resampleMotionEvent(16ms, motionEvent, nullptr); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, {Pointer{.id = 0, @@ -400,7 +419,7 @@ TEST_F(ResamplerTest, SinglePointerDeltaTooSmallExtrapolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, nullptr); + mResampler->resampleMotionEvent(16ms, motionEvent, nullptr); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } @@ -414,7 +433,7 @@ TEST_F(ResamplerTest, SinglePointerDeltaTooLargeExtrapolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(27ms, motionEvent, nullptr); + mResampler->resampleMotionEvent(32ms, motionEvent, nullptr); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } @@ -428,7 +447,7 @@ TEST_F(ResamplerTest, SinglePointerResampleTimeTooFarExtrapolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(43ms, motionEvent, nullptr); + mResampler->resampleMotionEvent(48ms, motionEvent, nullptr); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, {Pointer{.id = 0, @@ -451,7 +470,7 @@ TEST_F(ResamplerTest, MultiplePointerSingleSampleInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, {Pointer{.x = 2.2f, .y = 2.2f, .isResampled = true}, @@ -475,7 +494,7 @@ TEST_F(ResamplerTest, MultiplePointerSingleSampleExtrapolation) { const MotionEvent originalMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, secondMotionEvent, {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true}, @@ -498,7 +517,7 @@ TEST_F(ResamplerTest, MultiplePointerMultipleSampleInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true}, @@ -517,7 +536,7 @@ TEST_F(ResamplerTest, MultiplePointerMultipleSampleExtrapolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true}, @@ -539,7 +558,7 @@ TEST_F(ResamplerTest, MultiplePointerIncreaseNumPointersInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, {Pointer{.x = 1.4f, .y = 1.4f, .isResampled = true}, @@ -560,7 +579,7 @@ TEST_F(ResamplerTest, MultiplePointerIncreaseNumPointersInterpolation) { const MotionEvent originalSecondMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(27ms, secondMotionEvent, &secondFutureSample); + mResampler->resampleMotionEvent(32ms, secondMotionEvent, &secondFutureSample); assertMotionEventIsResampledAndCoordsNear(originalSecondMotionEvent, secondMotionEvent, {Pointer{.x = 3.8f, .y = 3.8f, .isResampled = true}, @@ -586,7 +605,7 @@ TEST_F(ResamplerTest, MultiplePointerIncreaseNumPointersExtrapolation) { const MotionEvent secondOriginalMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr); assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); } @@ -606,7 +625,7 @@ TEST_F(ResamplerTest, MultiplePointerDecreaseNumPointersInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } @@ -629,7 +648,7 @@ TEST_F(ResamplerTest, MultiplePointerDecreaseNumPointersExtrapolation) { const MotionEvent secondOriginalMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr); assertMotionEventIsResampledAndCoordsNear(secondOriginalMotionEvent, secondMotionEvent, {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true}, @@ -650,7 +669,7 @@ TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } @@ -672,7 +691,7 @@ TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderExtrapolation) { const MotionEvent secondOriginalMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr); assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); } @@ -691,7 +710,7 @@ TEST_F(ResamplerTest, MultiplePointerDifferentIdsInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } @@ -713,7 +732,7 @@ TEST_F(ResamplerTest, MultiplePointerDifferentIdsExtrapolation) { const MotionEvent secondOriginalMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr); assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); } @@ -746,7 +765,7 @@ TEST_F(ResamplerTest, MultiplePointerDifferentToolTypeInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } @@ -782,7 +801,7 @@ TEST_F(ResamplerTest, MultiplePointerDifferentToolTypeExtrapolation) { const MotionEvent secondOriginalMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr); assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); } @@ -815,7 +834,7 @@ TEST_F(ResamplerTest, MultiplePointerShouldNotResampleToolTypeInterpolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } @@ -847,7 +866,7 @@ TEST_F(ResamplerTest, MultiplePointerShouldNotResampleToolTypeExtrapolation) { const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr); + mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr); assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } diff --git a/libs/input/tests/TestEventMatchers.h b/libs/input/tests/TestEventMatchers.h new file mode 100644 index 0000000000..dd2e40c025 --- /dev/null +++ b/libs/input/tests/TestEventMatchers.h @@ -0,0 +1,110 @@ +/** + * 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. + */ + +#pragma once + +#include <ostream> + +#include <input/Input.h> + +namespace android { + +/** + * 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. + */ + +class WithDeviceIdMatcher { +public: + using is_gtest_matcher = void; + explicit WithDeviceIdMatcher(DeviceId deviceId) : mDeviceId(deviceId) {} + + bool MatchAndExplain(const InputEvent& event, std::ostream*) const { + return mDeviceId == event.getDeviceId(); + } + + void DescribeTo(std::ostream* os) const { *os << "with device id " << mDeviceId; } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong device id"; } + +private: + const DeviceId mDeviceId; +}; + +inline WithDeviceIdMatcher WithDeviceId(int32_t deviceId) { + return WithDeviceIdMatcher(deviceId); +} + +class WithMotionActionMatcher { +public: + using is_gtest_matcher = void; + explicit WithMotionActionMatcher(int32_t action) : mAction(action) {} + + bool MatchAndExplain(const MotionEvent& event, std::ostream*) const { + bool matches = mAction == event.getAction(); + if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL) { + matches &= (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0; + } + return matches; + } + + void DescribeTo(std::ostream* os) const { + *os << "with motion action " << MotionEvent::actionToString(mAction); + if (mAction == AMOTION_EVENT_ACTION_CANCEL) { + *os << " and FLAG_CANCELED"; + } + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong action"; } + +private: + const int32_t mAction; +}; + +inline WithMotionActionMatcher WithMotionAction(int32_t action) { + return WithMotionActionMatcher(action); +} + +class MotionEventIsResampledMatcher { +public: + using is_gtest_matcher = void; + + 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 false; + } + for (size_t i = 0; i < numPointers; ++i) { + const PointerCoords& pointerCoords = + motionEvent.getSamplePointerCoords()[numSamples * numPointers + i]; + if (!pointerCoords.isResampled) { + return false; + } + } + return true; + } + + void DescribeTo(std::ostream* os) const { *os << "MotionEvent is resampled."; } + + void DescribeNegationTo(std::ostream* os) const { *os << "MotionEvent is not resampled."; } +}; + +inline MotionEventIsResampledMatcher MotionEventIsResampled() { + return MotionEventIsResampledMatcher(); +} +} // namespace android diff --git a/libs/input/tests/TestInputChannel.cpp b/libs/input/tests/TestInputChannel.cpp index d5f00b699b..26a0ca2106 100644 --- a/libs/input/tests/TestInputChannel.cpp +++ b/libs/input/tests/TestInputChannel.cpp @@ -19,6 +19,11 @@ #include <TestInputChannel.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <array> + #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <binder/IBinder.h> @@ -27,13 +32,25 @@ namespace android { namespace { -constexpr int FAKE_FD{-1}; + +/** + * Returns a stub file descriptor by opening a socket pair and closing one of the fds. The returned + * fd can be used to construct an InputChannel. + */ +base::unique_fd generateFileDescriptor() { + std::array<int, 2> kFileDescriptors; + LOG_IF(FATAL, ::socketpair(AF_UNIX, SOCK_SEQPACKET, 0, kFileDescriptors.data()) != 0) + << "TestInputChannel. Failed to create socket pair."; + LOG_IF(FATAL, ::close(kFileDescriptors[1]) != 0) + << "TestInputChannel. Failed to close file descriptor."; + return base::unique_fd{kFileDescriptors[0]}; +} } // namespace // --- TestInputChannel --- TestInputChannel::TestInputChannel(const std::string& name) - : InputChannel{name, base::unique_fd(FAKE_FD), sp<BBinder>::make()} {} + : InputChannel{name, generateFileDescriptor(), sp<BBinder>::make()} {} void TestInputChannel::enqueueMessage(const InputMessage& message) { mReceivedMessages.push(message); diff --git a/libs/input/tests/TestLooper.cpp b/libs/input/tests/TestLooper.cpp deleted file mode 100644 index e0f01ed25d..0000000000 --- a/libs/input/tests/TestLooper.cpp +++ /dev/null @@ -1,51 +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. - */ - -#include <TestLooper.h> - -#include <android-base/logging.h> - -namespace android { - -TestLooper::TestLooper() : mLooper(sp<Looper>::make(/*allowNonCallbacks=*/false)) {} - -int TestLooper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, - void* data) { - mCallbacks[fd] = callback; - constexpr int SUCCESS{1}; - return SUCCESS; -} - -int TestLooper::removeFd(int fd) { - if (auto it = mCallbacks.find(fd); it != mCallbacks.cend()) { - mCallbacks.erase(fd); - constexpr int SUCCESS{1}; - return SUCCESS; - } - constexpr int FAILURE{0}; - return FAILURE; -} - -void TestLooper::invokeCallback(int fd, int events) { - auto it = mCallbacks.find(fd); - LOG_IF(FATAL, it == mCallbacks.cend()) << "Fd does not exist in mCallbacks."; - mCallbacks[fd]->handleEvent(fd, events, /*data=*/nullptr); -} - -sp<Looper> TestLooper::getLooper() const { - return mLooper; -} -} // namespace android
\ No newline at end of file diff --git a/libs/input/tests/TestLooper.h b/libs/input/tests/TestLooper.h deleted file mode 100644 index 3242bc7699..0000000000 --- a/libs/input/tests/TestLooper.h +++ /dev/null @@ -1,56 +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. - */ - -#pragma once - -#include <map> - -#include <input/LooperInterface.h> - -namespace android { -/** - * TestLooper provides a mechanism to directly trigger Looper's callback. - */ -class TestLooper final : public LooperInterface { -public: - TestLooper(); - - /** - * Adds a file descriptor to mCallbacks. Ident, events, and data parameters are ignored. If - * addFd is called with an existent file descriptor and a different callback, the previous - * callback is overwritten. - */ - int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, - void* data) override; - - /** - * Removes a file descriptor from mCallbacks. If fd is not in mCallbacks, returns FAILURE. - */ - int removeFd(int fd) override; - - /** - * Calls handleEvent of the file descriptor. Fd must be in mCallbacks. Otherwise, invokeCallback - * fatally logs. - */ - void invokeCallback(int fd, int events); - - sp<Looper> getLooper() const override; - -private: - std::map<int /*fd*/, sp<LooperCallback>> mCallbacks; - sp<Looper> mLooper; -}; -} // namespace android
\ No newline at end of file diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp index e3be3bc8f8..d0ca78e658 100644 --- a/libs/nativedisplay/ADisplay.cpp +++ b/libs/nativedisplay/ADisplay.cpp @@ -129,7 +129,7 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { std::vector<DisplayConfigImpl> modesPerDisplay[size]; ui::DisplayConnectionType displayConnectionTypes[size]; int numModes = 0; - for (int i = 0; i < size; ++i) { + for (size_t i = 0; i < size; ++i) { ui::StaticDisplayInfo staticInfo; if (const status_t status = SurfaceComposerClient::getStaticDisplayInfo(ids[i].value, &staticInfo); @@ -151,7 +151,7 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { numModes += modes.size(); modesPerDisplay[i].reserve(modes.size()); - for (int j = 0; j < modes.size(); ++j) { + for (size_t j = 0; j < modes.size(); ++j) { const ui::DisplayMode& mode = modes[j]; modesPerDisplay[i].emplace_back( DisplayConfigImpl{static_cast<size_t>(mode.id), mode.resolution.getWidth(), @@ -224,7 +224,7 @@ float ADisplay_getMaxSupportedFps(ADisplay* display) { CHECK_NOT_NULL(display); DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display); float maxFps = 0.0; - for (int i = 0; i < impl->numConfigs; ++i) { + for (size_t i = 0; i < impl->numConfigs; ++i) { maxFps = std::max(maxFps, impl->configs[i].fps); } return maxFps; @@ -261,7 +261,7 @@ int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig) { for (size_t i = 0; i < impl->numConfigs; i++) { auto* config = impl->configs + i; - if (config->id == info.activeDisplayModeId) { + if (info.activeDisplayModeId >= 0 && config->id == (size_t)info.activeDisplayModeId) { *outConfig = reinterpret_cast<ADisplayConfig*>(config); return OK; } diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs index a3a9dc6258..c41ab8d1b8 100644 --- a/libs/nativewindow/rust/src/handle.rs +++ b/libs/nativewindow/rust/src/handle.rs @@ -12,7 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{mem::forget, ptr::NonNull}; +use std::{ + ffi::c_int, + mem::forget, + os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}, + ptr::NonNull, +}; /// Rust wrapper around `native_handle_t`. /// @@ -22,6 +27,108 @@ use std::{mem::forget, ptr::NonNull}; pub struct NativeHandle(NonNull<ffi::native_handle_t>); impl NativeHandle { + /// Creates a new `NativeHandle` with the given file descriptors and integer values. + /// + /// The `NativeHandle` will take ownership of the file descriptors and close them when it is + /// dropped. + pub fn new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self> { + let fd_count = fds.len(); + // SAFETY: native_handle_create doesn't have any safety requirements. + let handle = unsafe { + ffi::native_handle_create(fd_count.try_into().unwrap(), ints.len().try_into().unwrap()) + }; + let handle = NonNull::new(handle)?; + for (i, fd) in fds.into_iter().enumerate() { + // SAFETY: `handle` must be valid because it was just created, and the array offset is + // within the bounds of what we allocated above. + unsafe { + *(*handle.as_ptr()).data.as_mut_ptr().add(i) = fd.into_raw_fd(); + } + } + for (i, value) in ints.iter().enumerate() { + // SAFETY: `handle` must be valid because it was just created, and the array offset is + // within the bounds of what we allocated above. Note that `data` is uninitialized + // until after this so we can't use `slice::from_raw_parts_mut` or similar to create a + // reference to it so we use raw pointers arithmetic instead. + unsafe { + *(*handle.as_ptr()).data.as_mut_ptr().add(fd_count + i) = *value; + } + } + // SAFETY: `handle` must be valid because it was just created. + unsafe { + ffi::native_handle_set_fdsan_tag(handle.as_ptr()); + } + Some(Self(handle)) + } + + /// Returns a borrowed view of all the file descriptors in this native handle. + pub fn fds(&self) -> Vec<BorrowedFd> { + self.data()[..self.fd_count()] + .iter() + .map(|fd| { + // SAFETY: The `native_handle_t` maintains ownership of the file descriptor so it + // won't be closed until this `NativeHandle` is destroyed. The `BorrowedFd` will + // have a lifetime constrained to that of `&self`, so it can't outlive it. + unsafe { BorrowedFd::borrow_raw(*fd) } + }) + .collect() + } + + /// Returns the integer values in this native handle. + pub fn ints(&self) -> &[c_int] { + &self.data()[self.fd_count()..] + } + + /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained. + pub fn into_fds(self) -> Vec<OwnedFd> { + let fds = self.data()[..self.fd_count()] + .iter() + .map(|fd| { + // SAFETY: The `native_handle_t` has ownership of the file descriptor, and + // after this we destroy it without closing the file descriptor so we can take over + // ownership of it. + unsafe { OwnedFd::from_raw_fd(*fd) } + }) + .collect(); + + // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed + // after this because we own it and forget it. + unsafe { + assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0); + } + // Don't drop self, as that would cause `native_handle_close` to be called and close the + // file descriptors. + forget(self); + fds + } + + /// Returns a reference to the underlying `native_handle_t`. + fn as_ref(&self) -> &ffi::native_handle_t { + // SAFETY: All the ways of creating a `NativeHandle` ensure that the `native_handle_t` is + // valid and initialised, and lives as long as the `NativeHandle`. We enforce Rust's + // aliasing rules by giving the reference a lifetime matching that of `&self`. + unsafe { self.0.as_ref() } + } + + /// Returns the number of file descriptors included in the native handle. + fn fd_count(&self) -> usize { + self.as_ref().numFds.try_into().unwrap() + } + + /// Returns the number of integer values included in the native handle. + fn int_count(&self) -> usize { + self.as_ref().numInts.try_into().unwrap() + } + + /// Returns a slice reference for all the used `data` field of the native handle, including both + /// file descriptors and integers. + fn data(&self) -> &[c_int] { + let total_count = self.fd_count() + self.int_count(); + // SAFETY: The data must have been initialised with this number of elements when the + // `NativeHandle` was created. + unsafe { self.as_ref().data.as_slice(total_count) } + } + /// Wraps a raw `native_handle_t` pointer, taking ownership of it. /// /// # Safety @@ -90,3 +197,47 @@ unsafe impl Send for NativeHandle {} // SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just // integers and file descriptors. unsafe impl Sync for NativeHandle {} + +#[cfg(test)] +mod test { + use super::*; + use std::fs::File; + + #[test] + fn create_empty() { + let handle = NativeHandle::new(vec![], &[]).unwrap(); + assert_eq!(handle.fds().len(), 0); + assert_eq!(handle.ints(), &[]); + } + + #[test] + fn create_with_ints() { + let handle = NativeHandle::new(vec![], &[1, 2, 42]).unwrap(); + assert_eq!(handle.fds().len(), 0); + assert_eq!(handle.ints(), &[1, 2, 42]); + } + + #[test] + fn create_with_fd() { + let file = File::open("/dev/null").unwrap(); + let handle = NativeHandle::new(vec![file.into()], &[]).unwrap(); + assert_eq!(handle.fds().len(), 1); + assert_eq!(handle.ints(), &[]); + } + + #[test] + fn clone() { + let file = File::open("/dev/null").unwrap(); + let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); + assert_eq!(original.ints(), &[42]); + assert_eq!(original.fds().len(), 1); + + let cloned = original.clone(); + drop(original); + + assert_eq!(cloned.ints(), &[42]); + assert_eq!(cloned.fds().len(), 1); + + drop(cloned); + } +} diff --git a/libs/renderengine/benchmark/AndroidTest.xml b/libs/renderengine/benchmark/AndroidTest.xml new file mode 100644 index 0000000000..3b923cb3a8 --- /dev/null +++ b/libs/renderengine/benchmark/AndroidTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<configuration description="Config for librenderengine_bench."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-native-metric" /> + + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="librenderengine_bench->/data/local/tmp/librenderengine_bench" /> + </target_preparer> + <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" > + <option name="native-benchmark-device-path" value="/data/local/tmp" /> + <option name="benchmark-module-name" value="librenderengine_bench" /> + <option name="file-exclusion-filter-regex" value=".*\.config$" /> + <option name="file-exclusion-filter-regex" value=".*/resources/.*" /> + </test> +</configuration> diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 1954fc52e9..0fd982e812 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -97,6 +97,7 @@ struct PrimeCacheConfig { bool cacheImageDimmedLayers = true; bool cacheClippedLayers = true; bool cacheShadowLayers = true; + bool cacheEdgeExtension = true; bool cachePIPImageLayers = true; bool cacheTransparentImageDimmedLayers = true; bool cacheClippedDimmedImageLayers = true; diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 59b06568a0..57041ee6a1 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -27,6 +27,8 @@ #include "ui/Rect.h" #include "utils/Timers.h" +#include <com_android_graphics_libgui_flags.h> + namespace android::renderengine::skia { namespace { @@ -619,6 +621,32 @@ static void drawP3ImageLayers(SkiaRenderEngine* renderengine, const DisplaySetti } } +static void drawEdgeExtensionLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, + const std::shared_ptr<ExternalTexture>& dstTexture, + const std::shared_ptr<ExternalTexture>& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + // Make the layer + LayerSettings layer{ + // Make the layer bigger than the texture + .geometry = Geometry{.boundaries = FloatRect(0, 0, displayRect.width(), + displayRect.height())}, + .source = PixelSource{.buffer = + Buffer{ + .buffer = srcTexture, + .isOpaque = 1, + }}, + // The type of effect does not affect the shader's uniforms, but the layer must have a + // valid EdgeExtensionEffect to apply the shader + .edgeExtensionEffect = + EdgeExtensionEffect(true /* left */, false, false, true /* bottom */), + }; + for (float alpha : {0.5, 0.0, 1.0}) { + layer.alpha = alpha; + auto layers = std::vector<LayerSettings>{layer}; + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); + } +} + // // The collection of shaders cached here were found by using perfetto to record shader compiles // during actions that involve RenderEngine, logging the layer settings, and the shader code @@ -761,6 +789,12 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine, PrimeCacheConfig co // Draw layers for b/185569240. drawClippedLayers(renderengine, display, dstTexture, texture); } + + if (com::android::graphics::libgui::flags::edge_extension_shader() && + config.cacheEdgeExtension) { + drawEdgeExtensionLayers(renderengine, display, dstTexture, texture); + drawEdgeExtensionLayers(renderengine, p3Display, dstTexture, texture); + } } if (config.cachePIPImageLayers) { diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index ffb6cdb6ef..b0c6e44b2b 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -388,8 +388,8 @@ status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage, uint64_t inConsumerU } } - const uint64_t usage = static_cast<uint64_t>( - android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage)); + const uint64_t usage = static_cast<uint64_t>(ANDROID_NATIVE_UNSIGNED_CAST( + android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage))); auto result = getBufferMapper().lock(handle, usage, rect, base::unique_fd{fenceFd}); diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index b6ab2f5a47..7b5a27d9e1 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -208,8 +208,10 @@ status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds, void** vaddr, int fenceFd) { - return lockAsync(handle, android_convertGralloc1To0Usage(producerUsage, consumerUsage), bounds, - vaddr, fenceFd); + return lockAsync(handle, + ANDROID_NATIVE_UNSIGNED_CAST( + android_convertGralloc1To0Usage(producerUsage, consumerUsage)), + bounds, vaddr, fenceFd); } status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, uint32_t usage, diff --git a/services/gpuservice/vts/TEST_MAPPING b/services/gpuservice/vts/TEST_MAPPING index b33e9624e2..a809be18e1 100644 --- a/services/gpuservice/vts/TEST_MAPPING +++ b/services/gpuservice/vts/TEST_MAPPING @@ -1,7 +1,13 @@ { "presubmit": [ { - "name": "GpuServiceVendorTests" + "name": "GpuServiceVendorTests", + "options": [ + { + // Exclude test methods that require a physical device to run. + "exclude-annotation": "android.platform.test.annotations.RequiresDevice" + } + ] } ] } diff --git a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java index 6c16335359..5c12323633 100644 --- a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java +++ b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; -import android.platform.test.annotations.RestrictedBuildTest; +import android.platform.test.annotations.RequiresDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; @@ -63,7 +63,7 @@ public class GpuWorkTracepointTest extends BaseHostJUnit4Test { } @VsrTest(requirements={"VSR-3.3-004"}) - @RestrictedBuildTest + @RequiresDevice @Test public void testGpuWorkPeriodTracepointFormat() throws Exception { CommandResult commandResult = getDevice().executeShellV2Command( diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index cb220abd80..ca92ab5aca 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -217,6 +217,7 @@ cc_defaults { "libcutils", "libinput", "liblog", + "libprocessgroup", "libstatslog", "libutils", ], diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp index e74f258168..449eb45b4b 100644 --- a/services/inputflinger/InputThread.cpp +++ b/services/inputflinger/InputThread.cpp @@ -16,8 +16,14 @@ #include "InputThread.h" +#include <android-base/logging.h> +#include <com_android_input_flags.h> +#include <processgroup/processgroup.h> + namespace android { +namespace input_flags = com::android::input::flags; + namespace { // Implementation of Thread from libutils. @@ -43,6 +49,11 @@ InputThread::InputThread(std::string name, std::function<void()> loop, std::func : mName(name), mThreadWake(wake) { mThread = sp<InputThreadImpl>::make(loop); mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY); + if (input_flags::enable_input_policy_profile()) { + if (!applyInputEventProfile()) { + LOG(ERROR) << "Couldn't apply input policy profile for " << name; + } + } } InputThread::~InputThread() { @@ -63,4 +74,14 @@ bool InputThread::isCallingThread() { #endif } +bool InputThread::applyInputEventProfile() { +#if defined(__ANDROID__) + return SetTaskProfiles(mThread->getTid(), {"InputPolicy"}); +#else + // Since thread information is not available and there's no benefit of + // applying the task profile on host, return directly. + return true; +#endif +} + } // namespace android
\ No newline at end of file diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 397fedac4c..006d507a40 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -407,7 +407,8 @@ void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed // immediately by a DOWN event. pc.fade(PointerControllerInterface::Transition::IMMEDIATE); - pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED); + pc.updatePointerIcon(mShowTouchesEnabled ? PointerIconStyle::TYPE_SPOT_HOVER + : PointerIconStyle::TYPE_NOT_SPECIFIED); } else if (canUnfadeOnDisplay(args.displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } @@ -792,6 +793,13 @@ bool PointerChoreographer::setPointerIcon( if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) { auto it = mStylusPointersByDevice.find(deviceId); if (it != mStylusPointersByDevice.end()) { + if (mShowTouchesEnabled) { + // If an app doesn't override the icon for the hovering stylus, show the hover icon. + auto* style = std::get_if<PointerIconStyle>(&icon); + if (style != nullptr && *style == PointerIconStyle::TYPE_NOT_SPECIFIED) { + *style = PointerIconStyle::TYPE_SPOT_HOVER; + } + } setIconForController(icon, *it->second); return true; } diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index af9d2ebeda..10fec7480d 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -298,9 +298,14 @@ "name": "CtsInputRootTestCases" } ], - "staged-platinum-postsubmit": [ + "platinum-postsubmit": [ { "name": "inputflinger_tests" } + ], + "staged-platinum-postsubmit": [ + { + "name": "libinput_tests" + } ] } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 250e72cfa8..75b494bfd1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4491,6 +4491,10 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs& args) { { // acquire lock mLock.lock(); + if (input_flags::keyboard_repeat_keys() && !mConfig.keyRepeatEnabled) { + policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; + } + if (shouldSendKeyToInputFilterLocked(args)) { mLock.unlock(); @@ -7209,11 +7213,13 @@ sp<WindowInfoHandle> InputDispatcher::findWallpaperWindowBelow( } void InputDispatcher::setKeyRepeatConfiguration(std::chrono::nanoseconds timeout, - std::chrono::nanoseconds delay) { + std::chrono::nanoseconds delay, + bool keyRepeatEnabled) { std::scoped_lock _l(mLock); mConfig.keyRepeatTimeout = timeout.count(); mConfig.keyRepeatDelay = delay.count(); + mConfig.keyRepeatEnabled = keyRepeatEnabled; } bool InputDispatcher::isPointerInWindow(const sp<android::IBinder>& token, diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 87dfd1d8a4..1904058080 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -153,8 +153,8 @@ public: // Public to allow tests to verify that a Monitor can get ANR. void setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout); - void setKeyRepeatConfiguration(std::chrono::nanoseconds timeout, - std::chrono::nanoseconds delay) override; + void setKeyRepeatConfiguration(std::chrono::nanoseconds timeout, std::chrono::nanoseconds delay, + bool keyRepeatEnabled) override; bool isPointerInWindow(const sp<IBinder>& token, ui::LogicalDisplayId displayId, DeviceId deviceId, int32_t pointerId) override; diff --git a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h index 5eb3a32ef9..ba197d45fd 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h @@ -34,8 +34,13 @@ struct InputDispatcherConfiguration { // The key repeat inter-key delay. nsecs_t keyRepeatDelay; + // Whether key repeat is enabled. + bool keyRepeatEnabled; + InputDispatcherConfiguration() - : keyRepeatTimeout(500 * 1000000LL), keyRepeatDelay(50 * 1000000LL) {} + : keyRepeatTimeout(500 * 1000000LL), + keyRepeatDelay(50 * 1000000LL), + keyRepeatEnabled(true) {} }; } // namespace android diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 653f595670..463a95238b 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -227,10 +227,11 @@ public: virtual void cancelCurrentTouch() = 0; /* - * Updates key repeat configuration timeout and delay. + * Updates whether key repeat is enabled and key repeat configuration timeout and delay. */ virtual void setKeyRepeatConfiguration(std::chrono::nanoseconds timeout, - std::chrono::nanoseconds delay) = 0; + std::chrono::nanoseconds delay, + bool keyRepeatEnabled) = 0; /* * Determine if a pointer from a device is being dispatched to the given window. diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 7bec94eea1..2f6c6d74e7 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -93,6 +93,9 @@ struct InputReaderConfiguration { // The touchpad settings changed. TOUCHPAD_SETTINGS = 1u << 13, + // The key remapping has changed. + KEY_REMAPPING = 1u << 14, + // All devices must be reopened. MUST_REOPEN = 1u << 31, }; @@ -246,6 +249,9 @@ struct InputReaderConfiguration { // True if a pointer icon should be shown for direct stylus pointers. bool stylusPointerIconEnabled; + // Keycodes to be remapped. + std::map<int32_t /* fromKeyCode */, int32_t /* toKeyCode */> keyRemapping; + InputReaderConfiguration() : virtualKeyQuietTime(0), defaultPointerDisplayId(ui::LogicalDisplayId::DEFAULT), @@ -333,9 +339,6 @@ public: virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) = 0; virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) = 0; - virtual void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, - int32_t toKeyCode) const = 0; - virtual int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const = 0; /* Toggle Caps Lock */ @@ -466,6 +469,9 @@ public: virtual void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, int32_t deviceId) = 0; + /* Sends the Info of gestures that happen on the touchpad. */ + virtual void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) = 0; + /* Gets the keyboard layout for a particular input device. */ virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier& identifier, diff --git a/services/inputflinger/include/InputThread.h b/services/inputflinger/include/InputThread.h index 5e75027056..fcd913db7c 100644 --- a/services/inputflinger/include/InputThread.h +++ b/services/inputflinger/include/InputThread.h @@ -38,6 +38,7 @@ private: std::string mName; std::function<void()> mThreadWake; sp<Thread> mThread; + bool applyInputEventProfile(); }; } // namespace android diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index e34ed0fbd8..8f3d9ca778 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -72,10 +72,6 @@ public: /* Dumps the state of the pointer controller. */ virtual std::string dump() = 0; - /* Gets the bounds of the region that the pointer can traverse. - * Returns true if the bounds are available. */ - virtual std::optional<FloatRect> getBounds() const = 0; - /* Move the pointer. */ virtual void move(float deltaX, float deltaY) = 0; diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index e11adb8c76..0865eed4a2 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -1177,7 +1177,8 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t return false; } -void EventHub::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const { +void EventHub::setKeyRemapping(int32_t deviceId, + const std::map<int32_t, int32_t>& keyRemapping) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); if (device == nullptr) { @@ -1185,7 +1186,7 @@ void EventHub::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t to } const std::shared_ptr<KeyCharacterMap> kcm = device->getKeyCharacterMap(); if (kcm) { - kcm->addKeyRemapping(fromKeyCode, toKeyCode); + kcm->setKeyRemapping(keyRemapping); } } diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 70f024ea96..6185f1ab9e 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -365,6 +365,18 @@ std::list<NotifyArgs> InputDevice::configureInternal(nsecs_t when, // so update the enabled state when there is a change in display info. out += updateEnableState(when, readerConfig, forceEnable); } + + if (!changes.any() || changes.test(InputReaderConfiguration::Change::KEY_REMAPPING)) { + const bool isFullKeyboard = + (mSources & AINPUT_SOURCE_KEYBOARD) == AINPUT_SOURCE_KEYBOARD && + mKeyboardType == KeyboardType::ALPHABETIC; + if (isFullKeyboard) { + for_each_subdevice([&readerConfig](auto& context) { + context.setKeyRemapping(readerConfig.keyRemapping); + }); + bumpGeneration(); + } + } } return out; } @@ -689,12 +701,6 @@ void InputDevice::updateMetaState(int32_t keyCode) { }); } -void InputDevice::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) { - for_each_subdevice([fromKeyCode, toKeyCode](auto& context) { - context.addKeyRemapping(fromKeyCode, toKeyCode); - }); -} - void InputDevice::bumpGeneration() { mGeneration = mContext->bumpGeneration(); } diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index a5b12490a3..e579390005 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -625,15 +625,6 @@ bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceM return result; } -void InputReader::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const { - std::scoped_lock _l(mLock); - - InputDevice* device = findInputDeviceLocked(deviceId); - if (device != nullptr) { - device->addKeyRemapping(fromKeyCode, toKeyCode); - } -} - int32_t InputReader::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const { std::scoped_lock _l(mLock); diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 657126a825..edc30379b2 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -281,8 +281,8 @@ public: virtual bool hasMscEvent(int32_t deviceId, int mscEvent) const = 0; - virtual void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, - int32_t toKeyCode) const = 0; + virtual void setKeyRemapping(int32_t deviceId, + const std::map<int32_t, int32_t>& keyRemapping) const = 0; virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, @@ -513,8 +513,8 @@ public: bool hasMscEvent(int32_t deviceId, int mscEvent) const override final; - void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, - int32_t toKeyCode) const override final; + void setKeyRemapping(int32_t deviceId, + const std::map<int32_t, int32_t>& keyRemapping) const override final; status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 021978dee7..62cc4da5ec 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -124,8 +124,6 @@ public: int32_t getMetaState(); void updateMetaState(int32_t keyCode); - void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode); - void setKeyboardType(KeyboardType keyboardType); void bumpGeneration(); @@ -329,8 +327,8 @@ public: inline bool hasMscEvent(int mscEvent) const { return mEventHub->hasMscEvent(mId, mscEvent); } - inline void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) const { - mEventHub->addKeyRemapping(mId, fromKeyCode, toKeyCode); + inline void setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping) const { + mEventHub->setKeyRemapping(mId, keyRemapping); } inline status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t metaState, diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 2cc0a00496..100387195a 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -65,8 +65,6 @@ public: int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) override; int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) override; - void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const override; - int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override; void toggleCapsLockState(int32_t deviceId) override; diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp index c8e7790c86..dd46bbc543 100644 --- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp +++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp @@ -20,14 +20,19 @@ #include <sstream> #include <android-base/stringprintf.h> +#include <com_android_input_flags.h> #include <input/PrintTools.h> #include <linux/input-event-codes.h> #include <log/log_main.h> +namespace input_flags = com::android::input::flags; + namespace android { namespace { +static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD; + int32_t actionWithIndex(int32_t action, int32_t index) { return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } @@ -43,6 +48,12 @@ size_t firstUnmarkedBit(T set) { return i; } +void addRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis, + RawAbsoluteAxisInfo& evdevAxis) { + deviceInfo.addMotionRange(androidAxis, SOURCE, evdevAxis.minValue, evdevAxis.maxValue, + evdevAxis.flat, evdevAxis.fuzz, evdevAxis.resolution); +} + } // namespace CapturedTouchpadEventConverter::CapturedTouchpadEventConverter( @@ -108,8 +119,15 @@ std::string CapturedTouchpadEventConverter::dump() const { } void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const { - tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X); - tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y); + if (input_flags::include_relative_axis_values_for_captured_touchpads()) { + tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X, + AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X); + tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y, + AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y); + } else { + tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X); + tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y); + } tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR); tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR); tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR); @@ -135,8 +153,23 @@ void CapturedTouchpadEventConverter::tryAddRawMotionRange(InputDeviceInfo& devic int32_t evdevAxis) const { std::optional<RawAbsoluteAxisInfo> info = mDeviceContext.getAbsoluteAxisInfo(evdevAxis); if (info) { - deviceInfo.addMotionRange(androidAxis, SOURCE, info->minValue, info->maxValue, info->flat, - info->fuzz, info->resolution); + addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *info); + } +} + +void CapturedTouchpadEventConverter::tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, + int32_t androidAxis, + int32_t androidRelativeAxis, + int32_t evdevAxis) const { + std::optional<RawAbsoluteAxisInfo> axisInfo = mDeviceContext.getAbsoluteAxisInfo(evdevAxis); + if (axisInfo) { + addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *axisInfo); + + // The largest movement we could possibly report on a relative axis is from the minimum to + // the maximum (or vice versa) of the absolute axis. + float range = axisInfo->maxValue - axisInfo->minValue; + deviceInfo.addMotionRange(androidRelativeAxis, SOURCE, -range, range, axisInfo->flat, + axisInfo->fuzz, axisInfo->resolution); } } @@ -163,7 +196,7 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t std::list<NotifyArgs> out; std::vector<PointerCoords> coords; std::vector<PointerProperties> properties; - std::map<size_t, size_t> coordsIndexForSlotNumber; + std::map<size_t /*slotNumber*/, size_t /*coordsIndex*/> coordsIndexForSlotNumber; // For all the touches that were already down, send a MOVE event with their updated coordinates. // A convention of the MotionEvent API is that pointer coordinates in UP events match the @@ -175,11 +208,19 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t // to stay perfectly still between frames, and if it does the worst that can happen is // an extra MOVE event, so it's not worth the overhead of checking for changes. coordsIndexForSlotNumber[slotNumber] = coords.size(); - coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber))); + coords.push_back(makePointerCoordsForSlot(slotNumber)); properties.push_back({.id = pointerId, .toolType = ToolType::FINGER}); } out.push_back( makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties)); + if (input_flags::include_relative_axis_values_for_captured_touchpads()) { + // For any further events we send from this sync, the pointers won't have moved relative + // to the positions we just reported in this MOVE event, so zero out the relative axes. + for (PointerCoords& pointer : coords) { + pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0); + pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0); + } + } } std::vector<size_t> upSlots, downSlots; @@ -234,6 +275,9 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t /*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0)); freePointerIdForSlot(slotNumber); + if (input_flags::include_relative_axis_values_for_captured_touchpads()) { + mPreviousCoordsForSlotNumber.erase(slotNumber); + } coords.erase(coords.begin() + indexToRemove); properties.erase(properties.begin() + indexToRemove); // Now that we've removed some coords and properties, we might have to update the slot @@ -254,7 +298,7 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t : actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex); coordsIndexForSlotNumber[slotNumber] = coordsIndex; - coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber))); + coords.push_back(makePointerCoordsForSlot(slotNumber)); properties.push_back( {.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER}); @@ -286,12 +330,22 @@ NotifyMotionArgs CapturedTouchpadEventConverter::makeMotionArgs( AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{}); } -PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot( - const MultiTouchMotionAccumulator::Slot& slot) const { +PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(size_t slotNumber) { + const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(slotNumber); PointerCoords coords; coords.clear(); coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX()); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY()); + if (input_flags::include_relative_axis_values_for_captured_touchpads()) { + if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber); + it != mPreviousCoordsForSlotNumber.end()) { + auto [oldX, oldY] = it->second; + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX); + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY); + } + mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY()); + } + coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor()); coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor()); coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor()); diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h index 9b6df7a222..d6c0708f4a 100644 --- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h +++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h @@ -21,6 +21,7 @@ #include <map> #include <set> #include <string> +#include <utility> #include <vector> #include <android/input.h> @@ -49,12 +50,14 @@ public: private: void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis, int32_t evdevAxis) const; + void tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, int32_t androidAxis, + int32_t androidRelativeAxis, int32_t evdevAxis) const; [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime); [[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action, const std::vector<PointerCoords>& coords, const std::vector<PointerProperties>& properties, int32_t actionButton = 0, int32_t flags = 0); - PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const; + PointerCoords makePointerCoordsForSlot(size_t slotNumber); int32_t allocatePointerIdToSlot(size_t slotNumber); void freePointerIdForSlot(size_t slotNumber); @@ -76,8 +79,7 @@ private: std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse; std::map<size_t, int32_t> mPointerIdForSlotNumber; - - static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD; + std::map<size_t, std::pair<float, float>> mPreviousCoordsForSlotNumber; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index b17e79a250..9a36bfbeaf 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -480,6 +480,9 @@ void TouchpadInputMapper::consumeGesture(const Gesture* gesture) { return; } mGesturesToProcess.push_back(*gesture); + if (mTouchpadHardwareStateNotificationsEnabled) { + getPolicy()->notifyTouchpadGestureInfo(gesture->type, getDeviceId()); + } } std::list<NotifyArgs> TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t readTime) { diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 95283ba6ab..744cf4a514 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -123,4 +123,5 @@ cc_test { "device-tests", "device-platinum-tests", ], + native_coverage: false, } diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp index f20c43c523..353011aa5c 100644 --- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp +++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp @@ -20,6 +20,7 @@ #include <memory> #include <EventHub.h> +#include <com_android_input_flags.h> #include <gtest/gtest.h> #include <linux/input-event-codes.h> #include <linux/input.h> @@ -32,6 +33,8 @@ #include "TestEventMatchers.h" #include "TestInputListener.h" +namespace input_flags = com::android::input::flags; + namespace android { using testing::AllOf; @@ -47,6 +50,8 @@ public: mReader(mFakeEventHub, mFakePolicy, mFakeListener), mDevice(newDevice()), mDeviceContext(*mDevice, EVENTHUB_ID) { + input_flags::include_relative_axis_values_for_captured_touchpads(true); + const size_t slotCount = 8; mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0); mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true); @@ -126,7 +131,7 @@ protected: TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populatedCorrectly) { mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, 0, 4000, 0, 0, 45); - mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, 0, 2500, 0, 0, 40); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 2000, 0, 0, 40); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, 0, 1100, 0, 0, 35); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 1000, 0, 0, 30); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 900, 0, 0, 25); @@ -150,8 +155,8 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated const InputDeviceInfo::MotionRange* posY = info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, posY); - EXPECT_NEAR(0, posY->min, EPSILON); - EXPECT_NEAR(2500, posY->max, EPSILON); + EXPECT_NEAR(-500, posY->min, EPSILON); + EXPECT_NEAR(2000, posY->max, EPSILON); EXPECT_NEAR(40, posY->resolution, EPSILON); const InputDeviceInfo::MotionRange* touchMajor = @@ -182,8 +187,22 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated EXPECT_NEAR(800, toolMinor->max, EPSILON); EXPECT_NEAR(20, toolMinor->resolution, EPSILON); - // ...except orientation and pressure, which get scaled, and size, which is generated from other - // values. + // ...except for the relative motion axes, derived from the corresponding absolute ones: + const InputDeviceInfo::MotionRange* relX = + info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD); + ASSERT_NE(nullptr, relX); + EXPECT_NEAR(-4000, relX->min, EPSILON); + EXPECT_NEAR(4000, relX->max, EPSILON); + EXPECT_NEAR(45, relX->resolution, EPSILON); + + const InputDeviceInfo::MotionRange* relY = + info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD); + ASSERT_NE(nullptr, relY); + EXPECT_NEAR(-2500, relY->min, EPSILON); + EXPECT_NEAR(2500, relY->max, EPSILON); + EXPECT_NEAR(40, relY->resolution, EPSILON); + + // ...orientation and pressure, which get scaled: const InputDeviceInfo::MotionRange* orientation = info.getMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, orientation); @@ -198,6 +217,7 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated EXPECT_NEAR(1, pressure->max, EPSILON); EXPECT_NEAR(0, pressure->resolution, EPSILON); + // ... and size, which is generated from other values. const InputDeviceInfo::MotionRange* size = info.getMotionRange(AMOTION_EVENT_AXIS_SIZE, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, size); @@ -219,7 +239,9 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_bareMinimumAxesPresent_p // present, since it's generated from axes that aren't provided by this device). EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHPAD)); EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD)); - EXPECT_EQ(2u, info.getMotionRanges().size()); + EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD)); + EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD)); + EXPECT_EQ(4u, info.getMotionRanges().size()); } TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { @@ -235,14 +257,16 @@ TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(50, 100), WithToolType(ToolType::FINGER))); + WithCoords(50, 100), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 99); EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(52, 99), WithToolType(ToolType::FINGER))); + WithCoords(52, 99), WithRelativeMotion(2, -1), + WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); processAxis(conv, EV_KEY, BTN_TOUCH, 0); @@ -255,8 +279,9 @@ TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { VariantWith<NotifyMotionArgs>( WithMotionAction(AMOTION_EVENT_ACTION_UP)))); EXPECT_THAT(args, - Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(52, 99), WithPointerCount(1u), - WithToolType(ToolType::FINGER))))); + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithCoords(52, 99), WithRelativeMotion(0, 0), WithPointerCount(1u), + WithToolType(ToolType::FINGER))))); } TEST_F(CapturedTouchpadEventConverterTest, OneFinger_touchDimensionsPassedThrough) { @@ -507,13 +532,13 @@ TEST_F(CapturedTouchpadEventConverterTest, PalmTurningIntoFinger_reported) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(51, 100))); + WithCoords(51, 100), WithRelativeMotion(0, 0))); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(52, 100))); + WithCoords(52, 100), WithRelativeMotion(1, 0))); } TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) { @@ -553,7 +578,7 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerRep EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(98, 148))); + WithCoords(98, 148), WithRelativeMotion(-2, -2))); } TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) { @@ -660,7 +685,8 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(50, 100), WithToolType(ToolType::FINGER))); + WithCoords(50, 100), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); @@ -678,13 +704,16 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), WithCoords(52, 99), + WithRelativeMotion(2, -1), WithToolType(ToolType::FINGER))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_DOWN | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithPointerCount(2u), WithPointerCoords(0, 52, 99), + WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 250, 200), + WithPointerRelativeMotion(1, 0, 0), WithPointerToolType(0, ToolType::FINGER), WithPointerToolType(1, ToolType::FINGER))))); @@ -700,14 +729,17 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { std::list<NotifyArgs> args = processSync(conv); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), - VariantWith<NotifyMotionArgs>(WithMotionAction( - AMOTION_EVENT_ACTION_POINTER_UP | - 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithPointerRelativeMotion(1, 5, 2))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithPointerRelativeMotion(1, 0, 0))))); EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>( AllOf(WithPointerCount(2u), WithPointerCoords(0, 52, 99), - WithPointerCoords(1, 255, 202), + WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 255, 202), WithPointerToolType(1, ToolType::FINGER), WithPointerToolType(0, ToolType::FINGER))))); @@ -723,9 +755,69 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { WithMotionAction(AMOTION_EVENT_ACTION_UP)))); EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(AllOf(WithPointerCount(1u), WithCoords(255, 202), + WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER))))); } +TEST_F(CapturedTouchpadEventConverterTest, RelativeMotionAxesClearedForNewFingerInSlot) { + CapturedTouchpadEventConverter conv = createConverter(); + // Put down one finger. + processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); + processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1); + processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50); + processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100); + + processAxis(conv, EV_KEY, BTN_TOUCH, 1); + processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); + + EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), + WithCoords(50, 100), WithRelativeMotion(0, 0))); + + // Move it in negative X and Y directions. + processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 47); + processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 97); + + EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(47, 97), + WithRelativeMotion(-3, -3))); + + // Lift it. + processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); + processAxis(conv, EV_KEY, BTN_TOUCH, 0); + processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); + + std::list<NotifyArgs> args = processSync(conv); + EXPECT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_UP)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(47, 97), + WithRelativeMotion(0, 0), + WithPointerCount(1u))))); + + // Put down another finger using the same slot. Relative axis values should be cleared. + processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2); + processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 60); + processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 60); + + processAxis(conv, EV_KEY, BTN_TOUCH, 1); + processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); + + EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), + WithCoords(60, 60), WithRelativeMotion(0, 0))); + + processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 64); + processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 58); + + EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), + WithCoords(64, 58), WithRelativeMotion(4, -2))); +} + // Pointer IDs max out at 31, and so must be reused once a touch is lifted to avoid running out. TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) { CapturedTouchpadEventConverter conv = createConverter(); diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp index 31fbf209a3..943de6e3cf 100644 --- a/services/inputflinger/tests/FakeEventHub.cpp +++ b/services/inputflinger/tests/FakeEventHub.cpp @@ -151,9 +151,10 @@ void FakeEventHub::addKeyCodeMapping(int32_t deviceId, int32_t fromKeyCode, int3 getDevice(deviceId)->keyCodeMapping.insert_or_assign(fromKeyCode, toKeyCode); } -void FakeEventHub::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const { +void FakeEventHub::setKeyRemapping(int32_t deviceId, + const std::map<int32_t, int32_t>& keyRemapping) const { Device* device = getDevice(deviceId); - device->keyRemapping.insert_or_assign(fromKeyCode, toKeyCode); + device->keyRemapping = keyRemapping; } void FakeEventHub::addLed(int32_t deviceId, int32_t led, bool initialState) { diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h index 3d8dddd532..2dfbb2388a 100644 --- a/services/inputflinger/tests/FakeEventHub.h +++ b/services/inputflinger/tests/FakeEventHub.h @@ -55,7 +55,7 @@ class FakeEventHub : public EventHubInterface { KeyedVector<int32_t, int32_t> absoluteAxisValue; KeyedVector<int32_t, KeyInfo> keysByScanCode; KeyedVector<int32_t, KeyInfo> keysByUsageCode; - std::unordered_map<int32_t, int32_t> keyRemapping; + std::map<int32_t, int32_t> keyRemapping; KeyedVector<int32_t, bool> leds; // fake mapping which would normally come from keyCharacterMap std::unordered_map<int32_t, int32_t> keyCodeMapping; @@ -129,7 +129,7 @@ public: void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode, uint32_t flags); void addKeyCodeMapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode); - void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const; + void setKeyRemapping(int32_t deviceId, const std::map<int32_t, int32_t>& keyRemapping) const; void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition); void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType, diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index e1f844c571..f373cac085 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -256,6 +256,10 @@ void FakeInputReaderPolicy::notifyTouchpadHardwareState(const SelfContainedHardw mTouchpadHardwareStateNotified.notify_all(); } +void FakeInputReaderPolicy::notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) { + std::scoped_lock lock(mLock); +} + std::shared_ptr<KeyCharacterMap> FakeInputReaderPolicy::getKeyboardLayoutOverlay( const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) { return nullptr; diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h index 61bb9fcb25..3a2b4e9ed9 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -85,6 +85,7 @@ private: void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override; void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, int32_t deviceId) override; + void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) override; std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override; std::string getDeviceAlias(const InputDeviceIdentifier&) override; diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp index d0998ba851..887a939e09 100644 --- a/services/inputflinger/tests/FakePointerController.cpp +++ b/services/inputflinger/tests/FakePointerController.cpp @@ -148,12 +148,6 @@ bool FakePointerController::isPointerShown() { return mIsPointerShown; } -std::optional<FloatRect> FakePointerController::getBounds() const { - if (!mEnabled) return std::nullopt; - - return mHaveBounds ? std::make_optional<FloatRect>(mMinX, mMinY, mMaxX, mMaxY) : std::nullopt; -} - void FakePointerController::move(float deltaX, float deltaY) { if (!mEnabled) return; diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h index 2c76c6214c..9b773a7715 100644 --- a/services/inputflinger/tests/FakePointerController.h +++ b/services/inputflinger/tests/FakePointerController.h @@ -65,7 +65,6 @@ public: private: std::string dump() override { return ""; } - std::optional<FloatRect> getBounds() const override; void move(float deltaX, float deltaY) override; void unfade(Transition) override; void setPresentation(Presentation) override {} diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c2f174f6b4..f066b031f3 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -9091,6 +9091,7 @@ class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms; static constexpr std::chrono::nanoseconds KEY_REPEAT_DELAY = 40ms; + static constexpr bool KEY_REPEAT_ENABLED = true; std::shared_ptr<FakeApplicationHandle> mApp; sp<FakeWindowHandle> mWindow; @@ -9098,7 +9099,8 @@ protected: virtual void SetUp() override { InputDispatcherTest::SetUp(); - mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY); + mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY, + KEY_REPEAT_ENABLED); setUpWindow(); } @@ -9247,6 +9249,24 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectK expectKeyRepeatOnce(3); } +TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_NoRepeatWhenKeyRepeatDisabled) { + SCOPED_FLAG_OVERRIDE(keyboard_repeat_keys, true); + static constexpr std::chrono::milliseconds KEY_NO_REPEAT_ASSERTION_TIMEOUT = 100ms; + + mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY, + /*repeatKeyEnabled=*/false); + sendAndConsumeKeyDown(/*deviceId=*/1); + + ASSERT_GT(KEY_NO_REPEAT_ASSERTION_TIMEOUT, KEY_REPEAT_TIMEOUT) + << "Ensure the check for no key repeats extends beyond the repeat timeout duration."; + ASSERT_GT(KEY_NO_REPEAT_ASSERTION_TIMEOUT, KEY_REPEAT_DELAY) + << "Ensure the check for no key repeats extends beyond the repeat delay duration."; + + // No events should be returned if key repeat is turned off. + // Wait for KEY_NO_REPEAT_ASSERTION_TIMEOUT to return no events to ensure key repeat disabled. + mWindow->assertNoEvents(KEY_NO_REPEAT_ASSERTION_TIMEOUT); +} + /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 4a9e89319d..17c37d5a41 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -3330,11 +3330,11 @@ TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { TEST_F(KeyboardInputMapperTest, Process_KeyRemapping) { mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0); mFakeEventHub->addKey(EVENTHUB_ID, KEY_B, 0, AKEYCODE_B, 0); - mFakeEventHub->addKeyRemapping(EVENTHUB_ID, AKEYCODE_A, AKEYCODE_B); KeyboardInputMapper& mapper = constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD); + mFakeEventHub->setKeyRemapping(EVENTHUB_ID, {{AKEYCODE_A, AKEYCODE_B}}); // Key down by scan code. process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1); NotifyKeyArgs args; diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h index 5a3d79da5e..f41b39ac8e 100644 --- a/services/inputflinger/tests/InterfaceMocks.h +++ b/services/inputflinger/tests/InterfaceMocks.h @@ -97,7 +97,8 @@ public: MOCK_METHOD(bool, hasRelativeAxis, (int32_t deviceId, int axis), (const)); MOCK_METHOD(bool, hasInputProperty, (int32_t deviceId, int property), (const)); MOCK_METHOD(bool, hasMscEvent, (int32_t deviceId, int mscEvent), (const)); - MOCK_METHOD(void, addKeyRemapping, (int32_t deviceId, int fromKeyCode, int toKeyCode), (const)); + MOCK_METHOD(void, setKeyRemapping, + (int32_t deviceId, (const std::map<int32_t, int32_t>& keyRemapping)), (const)); MOCK_METHOD(status_t, mapKey, (int32_t deviceId, int scanCode, int usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags), @@ -247,8 +248,6 @@ public: MOCK_METHOD(int32_t, getMetaState, (), ()); MOCK_METHOD(void, updateMetaState, (int32_t keyCode), ()); - MOCK_METHOD(void, addKeyRemapping, (int32_t fromKeyCode, int32_t toKeyCode), ()); - MOCK_METHOD(void, setKeyboardType, (KeyboardType keyboardType), ()); MOCK_METHOD(void, bumpGeneration, (), ()); diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 18222ddb4b..411c7baf77 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -978,6 +978,36 @@ TEST_F(PointerChoreographerTest, WhenTouchDeviceIsResetClearsSpots) { assertPointerControllerRemoved(pc); } +/** + * When both "show touches" and "stylus hover icons" are enabled, if the app doesn't specify an + * icon for the hovering stylus, fall back to using the spot hover icon. + */ +TEST_F(PointerChoreographerTest, ShowTouchesOverridesUnspecifiedStylusIcon) { + mChoreographer.setShowTouchesEnabled(true); + mChoreographer.setStylusPointerIconEnabled(true); + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, + {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, + DISPLAY_ID)}}); + + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + auto pc = assertPointerControllerCreated(ControllerType::STYLUS); + + mChoreographer.setPointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED, DISPLAY_ID, DEVICE_ID); + pc->assertPointerIconSet(PointerIconStyle::TYPE_SPOT_HOVER); + + mChoreographer.setPointerIcon(PointerIconStyle::TYPE_ARROW, DISPLAY_ID, DEVICE_ID); + pc->assertPointerIconSet(PointerIconStyle::TYPE_ARROW); + + mChoreographer.setPointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED, DISPLAY_ID, DEVICE_ID); + pc->assertPointerIconSet(PointerIconStyle::TYPE_SPOT_HOVER); +} + using StylusFixtureParam = std::tuple</*name*/ std::string_view, /*source*/ uint32_t, ControllerType>; diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h index cfedc6eb1a..6fa3365faa 100644 --- a/services/inputflinger/tests/TestEventMatchers.h +++ b/services/inputflinger/tests/TestEventMatchers.h @@ -615,7 +615,12 @@ public: explicit WithPointerIdMatcher(size_t index, int32_t pointerId) : mIndex(index), mPointerId(pointerId) {} - bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream* os) const { + if (mIndex >= args.pointerCoords.size()) { + *os << "Pointer index " << mIndex << " is out of bounds"; + return false; + } + return args.pointerProperties[mIndex].id == mPointerId; } @@ -646,12 +651,51 @@ MATCHER_P2(WithCursorPosition, x, y, "InputEvent with specified cursor position" return (isnan(x) ? isnan(argX) : x == argX) && (isnan(y) ? isnan(argY) : y == argY); } -MATCHER_P2(WithRelativeMotion, x, y, "InputEvent with specified relative motion") { - const auto argX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); - const auto argY = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); - *result_listener << "expected relative motion (" << x << ", " << y << "), but got (" << argX - << ", " << argY << ")"; - return argX == x && argY == y; +/// Relative motion matcher +class WithRelativeMotionMatcher { +public: + using is_gtest_matcher = void; + explicit WithRelativeMotionMatcher(size_t pointerIndex, float relX, float relY) + : mPointerIndex(pointerIndex), mRelX(relX), mRelY(relY) {} + + bool MatchAndExplain(const NotifyMotionArgs& event, std::ostream* os) const { + if (mPointerIndex >= event.pointerCoords.size()) { + *os << "Pointer index " << mPointerIndex << " is out of bounds"; + return false; + } + + const PointerCoords& coords = event.pointerCoords[mPointerIndex]; + bool matches = mRelX == coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X) && + mRelY == coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); + if (!matches) { + *os << "expected relative motion (" << mRelX << ", " << mRelY << ") at pointer index " + << mPointerIndex << ", but got (" + << coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X) << ", " + << coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y) << ")"; + } + return matches; + } + + void DescribeTo(std::ostream* os) const { + *os << "with relative motion (" << mRelX << ", " << mRelY << ") at pointer index " + << mPointerIndex; + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong relative motion"; } + +private: + const size_t mPointerIndex; + const float mRelX; + const float mRelY; +}; + +inline WithRelativeMotionMatcher WithRelativeMotion(float relX, float relY) { + return WithRelativeMotionMatcher(0, relX, relY); +} + +inline WithRelativeMotionMatcher WithPointerRelativeMotion(size_t pointerIndex, float relX, + float relY) { + return WithRelativeMotionMatcher(pointerIndex, relX, relY); } MATCHER_P3(WithGestureOffset, dx, dy, epsilon, @@ -758,10 +802,14 @@ MATCHER_P(WithToolType, toolType, "InputEvent with specified tool type") { return argToolType == toolType; } -MATCHER_P2(WithPointerToolType, pointer, toolType, +MATCHER_P2(WithPointerToolType, pointerIndex, toolType, "InputEvent with specified tool type for pointer") { - const auto argToolType = arg.pointerProperties[pointer].toolType; - *result_listener << "expected pointer " << pointer << " to have tool type " + if (std::cmp_greater_equal(pointerIndex, arg.getPointerCount())) { + *result_listener << "Pointer index " << pointerIndex << " is out of bounds"; + return false; + } + const auto argToolType = arg.pointerProperties[pointerIndex].toolType; + *result_listener << "expected pointer " << pointerIndex << " to have tool type " << ftl::enum_string(toolType) << ", but got " << ftl::enum_string(argToolType); return argToolType == toolType; } diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp index 3e4a19becd..5442a65f2f 100644 --- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp @@ -155,10 +155,6 @@ public: return reader->getLightPlayerId(deviceId, lightId); } - void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const { - reader->addKeyRemapping(deviceId, fromKeyCode, toKeyCode); - } - int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const { return reader->getKeyCodeForKeyLocation(deviceId, locationKeyCode); } diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index ddc3310448..fa8270a3d9 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -202,7 +202,8 @@ public: int32_t getSwitchState(int32_t deviceId, int32_t sw) const override { return mFdp->ConsumeIntegral<int32_t>(); } - void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const override {} + void setKeyRemapping(int32_t deviceId, + const std::map<int32_t, int32_t>& keyRemapping) const override {} int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override { return mFdp->ConsumeIntegral<int32_t>(); } @@ -283,6 +284,7 @@ public: void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {} void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, int32_t deviceId) override {} + void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) override {} std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier& identifier, const std::optional<KeyboardLayoutInfo> layoutInfo) override { diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index f4b0265afb..7b2596adca 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -52,6 +52,7 @@ cc_library { "-Wall", "-Werror", "-Wextra", + "-Wthread-safety", "-fvisibility=hidden", ], diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp index f56642b77c..0d00642688 100644 --- a/services/sensorservice/SensorEventConnection.cpp +++ b/services/sensorservice/SensorEventConnection.cpp @@ -711,14 +711,17 @@ status_t SensorService::SensorEventConnection::enableDisable( if (err == OK && isSensorCapped) { if ((requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) || !isRateCappedBasedOnPermission()) { + Mutex::Autolock _l(mConnectionLock); mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs; } else { + Mutex::Autolock _l(mConnectionLock); mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS; } } } else { err = mService->disable(this, handle); + Mutex::Autolock _l(mConnectionLock); mMicSamplingPeriodBackup.erase(handle); } return err; @@ -750,8 +753,10 @@ status_t SensorService::SensorEventConnection::setEventRate(int handle, nsecs_t if (ret == OK && isSensorCapped) { if ((requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) || !isRateCappedBasedOnPermission()) { + Mutex::Autolock _l(mConnectionLock); mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs; } else { + Mutex::Autolock _l(mConnectionLock); mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS; } } diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h index 6a98a40686..bb8733dc3a 100644 --- a/services/sensorservice/SensorEventConnection.h +++ b/services/sensorservice/SensorEventConnection.h @@ -199,7 +199,8 @@ private: // valid mapping for sensors that require a permission in order to reduce the lookup time. std::unordered_map<int32_t, int32_t> mHandleToAppOp; // Mapping of sensor handles to its rate before being capped by the mic toggle. - std::unordered_map<int, nsecs_t> mMicSamplingPeriodBackup; + std::unordered_map<int, nsecs_t> mMicSamplingPeriodBackup + GUARDED_BY(mConnectionLock); userid_t mUserId; std::optional<bool> mIsRateCappedBasedOnPermission; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index bd093f52cf..d08e261e6c 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -305,7 +305,7 @@ DisplayConfiguration::Dpi HWComposer::correctedDpiIfneeded( // The logic here checks if hwc was able to provide some dpi, and if so if the dpi // disparity between the axes is more reasonable than a rough estimate, otherwise use // the estimated dpi as a corrected value. - if (estimatedDpi.x == -1 || estimatedDpi.x == -1) { + if (estimatedDpi.x == -1 || estimatedDpi.y == -1) { return dpi; } if (dpi.x == -1 || dpi.y == -1) { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index ac15b92175..ee605b7a3e 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -279,24 +279,6 @@ void updateVisibility(LayerSnapshot& snapshot, bool visible) { snapshot.getDebugString().c_str()); } -bool needsInputInfo(const LayerSnapshot& snapshot, const RequestedLayerState& requested) { - if (requested.potentialCursor) { - return false; - } - - if (snapshot.inputInfo.token != nullptr) { - return true; - } - - if (snapshot.hasBufferOrSidebandStream()) { - return true; - } - - return requested.windowInfoHandle && - requested.windowInfoHandle->getInfo()->inputConfig.test( - gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL); -} - void updateMetadata(LayerSnapshot& snapshot, const RequestedLayerState& requested, const LayerSnapshotBuilder::Args& args) { snapshot.metadata.clear(); @@ -1162,7 +1144,7 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, } updateVisibility(snapshot, snapshot.isVisible); - if (!needsInputInfo(snapshot, requested)) { + if (!requested.needsInputInfo()) { return; } @@ -1172,7 +1154,7 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, bool noValidDisplay = !displayInfoOpt.has_value(); auto displayInfo = displayInfoOpt.value_or(sDefaultInfo); - if (!requested.windowInfoHandle) { + if (!requested.hasInputInfo()) { snapshot.inputInfo.inputConfig = InputConfig::NO_INPUT_CHANNEL; } fillInputFrameInfo(snapshot.inputInfo, displayInfo.transform, snapshot); diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 17d2610d7a..5734ccf38f 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -62,6 +62,8 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) metadata.merge(args.metadata); changes |= RequestedLayerState::Changes::Metadata; handleAlive = true; + // TODO: b/305254099 remove once we don't pass invisible windows to input + windowInfoHandle = nullptr; if (parentId != UNASSIGNED_LAYER_ID) { canBeRoot = false; } @@ -553,6 +555,24 @@ bool RequestedLayerState::hasInputInfo() const { windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL); } +bool RequestedLayerState::needsInputInfo() const { + if (potentialCursor) { + return false; + } + + if ((sidebandStream != nullptr) || (externalTexture != nullptr)) { + return true; + } + + if (!windowInfoHandle) { + return false; + } + + const auto windowInfo = windowInfoHandle->getInfo(); + return windowInfo->token != nullptr || + windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL); +} + bool RequestedLayerState::hasBlur() const { return backgroundBlurRadius > 0 || blurRegions.size() > 0; } diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h index 48b9640486..1d96dff336 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -87,6 +87,7 @@ struct RequestedLayerState : layer_state_t { aidl::android::hardware::graphics::composer3::Composition getCompositionType() const; bool hasValidRelativeParent() const; bool hasInputInfo() const; + bool needsInputInfo() const; bool hasBlur() const; bool hasFrameUpdate() const; bool hasReadyFrame() const; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index be00079b9c..5e131548aa 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -38,7 +38,6 @@ #include <FrameTimeline/FrameTimeline.h> #include <scheduler/interface/ICompositor.h> -#include <algorithm> #include <cinttypes> #include <cstdint> #include <functional> @@ -46,16 +45,15 @@ #include <numeric> #include <common/FlagManager.h> -#include "../Layer.h" #include "EventThread.h" #include "FrameRateOverrideMappings.h" #include "FrontEnd/LayerHandle.h" +#include "Layer.h" #include "OneShotTimer.h" #include "RefreshRateStats.h" #include "SurfaceFlingerFactory.h" #include "SurfaceFlingerProperties.h" #include "TimeStats/TimeStats.h" -#include "VSyncTracker.h" #include "VsyncConfiguration.h" #include "VsyncController.h" #include "VsyncSchedule.h" @@ -361,10 +359,8 @@ void Scheduler::createEventThread(Cycle cycle, frametimeline::TokenManager* toke if (cycle == Cycle::Render) { mRenderEventThread = std::move(eventThread); - mRenderEventConnection = mRenderEventThread->createEventConnection(); } else { mLastCompositeEventThread = std::move(eventThread); - mLastCompositeEventConnection = mLastCompositeEventThread->createEventConnection(); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 1367ec385e..c88b563805 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -145,10 +145,6 @@ public: Cycle, EventRegistrationFlags eventRegistration = {}, const sp<IBinder>& layerHandle = nullptr) EXCLUDES(mChoreographerLock); - const sp<EventThreadConnection>& getEventConnection(Cycle cycle) const { - return cycle == Cycle::Render ? mRenderEventConnection : mLastCompositeEventConnection; - } - enum class Hotplug { Connected, Disconnected }; void dispatchHotplug(PhysicalDisplayId, Hotplug); @@ -467,10 +463,7 @@ private: void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock); std::unique_ptr<EventThread> mRenderEventThread; - sp<EventThreadConnection> mRenderEventConnection; - std::unique_ptr<EventThread> mLastCompositeEventThread; - sp<EventThreadConnection> mLastCompositeEventConnection; std::atomic<nsecs_t> mLastResyncTime = 0; diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp index fa377e9323..3c5f68c4c2 100644 --- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp @@ -21,7 +21,6 @@ #include "VsyncModulator.h" -#include <android-base/properties.h> #include <common/trace.h> #include <log/log.h> @@ -37,8 +36,7 @@ const std::chrono::nanoseconds VsyncModulator::MIN_EARLY_TRANSACTION_TIME = 1ms; VsyncModulator::VsyncModulator(const VsyncConfigSet& config, Now now) : mVsyncConfigSet(config), - mNow(now), - mTraceDetailedInfo(base::GetBoolProperty("debug.sf.vsync_trace_detailed_info", false)) {} + mNow(now) {} VsyncConfig VsyncModulator::setVsyncConfigSet(const VsyncConfigSet& config) { std::lock_guard<std::mutex> lock(mMutex); @@ -71,10 +69,6 @@ VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(Transactio break; } - if (mTraceDetailedInfo) { - SFTRACE_INT("mEarlyWakeup", static_cast<int>(mEarlyWakeupRequests.size())); - } - if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) { mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES; mEarlyTransactionStartTime = mNow(); @@ -167,15 +161,19 @@ VsyncConfig VsyncModulator::updateVsyncConfigLocked() { const VsyncConfig& offsets = getNextVsyncConfig(); mVsyncConfig = offsets; - if (mTraceDetailedInfo) { - const bool isEarly = &offsets == &mVsyncConfigSet.early; - const bool isEarlyGpu = &offsets == &mVsyncConfigSet.earlyGpu; - const bool isLate = &offsets == &mVsyncConfigSet.late; + // Trace config type + SFTRACE_INT("Vsync-Early", &mVsyncConfig == &mVsyncConfigSet.early); + SFTRACE_INT("Vsync-EarlyGpu", &mVsyncConfig == &mVsyncConfigSet.earlyGpu); + SFTRACE_INT("Vsync-Late", &mVsyncConfig == &mVsyncConfigSet.late); - SFTRACE_INT("Vsync-EarlyOffsetsOn", isEarly); - SFTRACE_INT("Vsync-EarlyGpuOffsetsOn", isEarlyGpu); - SFTRACE_INT("Vsync-LateOffsetsOn", isLate); - } + // Trace early vsync conditions + SFTRACE_INT("EarlyWakeupRequests", + static_cast<int>(mEarlyWakeupRequests.size())); + SFTRACE_INT("EarlyTransactionFrames", mEarlyTransactionFrames); + SFTRACE_INT("RefreshRateChangePending", mRefreshRateChangePending); + + // Trace early gpu conditions + SFTRACE_INT("EarlyGpuFrames", mEarlyGpuFrames); return offsets; } @@ -183,7 +181,6 @@ VsyncConfig VsyncModulator::updateVsyncConfigLocked() { void VsyncModulator::binderDied(const wp<IBinder>& who) { std::lock_guard<std::mutex> lock(mMutex); mEarlyWakeupRequests.erase(who); - static_cast<void>(updateVsyncConfigLocked()); } diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h index be0d3348b5..d0a793535c 100644 --- a/services/surfaceflinger/Scheduler/VsyncModulator.h +++ b/services/surfaceflinger/Scheduler/VsyncModulator.h @@ -105,7 +105,6 @@ private: std::atomic<TimePoint> mLastTransactionCommitTime = TimePoint(); const Now mNow; - const bool mTraceDetailedInfo; }; } // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c794a7ba43..65a0ed3065 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1003,6 +1003,8 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { // which we maintain for backwards compatibility. config.cacheUltraHDR = base::GetBoolProperty("ro.surface_flinger.prime_shader_cache.ultrahdr"s, false); + config.cacheEdgeExtension = + base::GetBoolProperty("debug.sf.edge_extension_shader"s, true); return getRenderEngine().primeCache(config); }); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index fa31643df1..9b10c94bcd 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -64,17 +64,6 @@ DisplayTransactionTest::~DisplayTransactionTest() { void DisplayTransactionTest::injectMockScheduler(PhysicalDisplayId displayId) { LOG_ALWAYS_FATAL_IF(mFlinger.scheduler()); - - EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*mEventThread, createEventConnection(_, _)) - .WillOnce(Return( - sp<EventThreadConnection>::make(mEventThread, mock::EventThread::kCallingUid))); - - EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*mSFEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp<EventThreadConnection>::make(mSFEventThread, - mock::EventThread::kCallingUid))); - mFlinger.setupScheduler(std::make_unique<mock::VsyncController>(), std::make_shared<mock::VSyncTracker>(), std::unique_ptr<EventThread>(mEventThread), diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp index b4efe0fe14..c7cc21ce07 100644 --- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp @@ -619,4 +619,14 @@ TEST_F(LayerLifecycleManagerTest, isSimpleBufferUpdate) { } } +TEST_F(LayerLifecycleManagerTest, testInputInfoOfRequestedLayerState) { + // By default the layer has no buffer, so it doesn't need an input info + EXPECT_FALSE(getRequestedLayerState(mLifecycleManager, 111)->needsInputInfo()); + + setBuffer(111); + mLifecycleManager.commitChanges(); + + EXPECT_TRUE(getRequestedLayerState(mLifecycleManager, 111)->needsInputInfo()); +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 90207232b0..75d2fa3c7f 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -1762,6 +1762,7 @@ TEST_F(LayerSnapshotTest, hideLayerWithNanMatrix) { UPDATE_AND_VERIFY(mSnapshotBuilder, {2}); EXPECT_TRUE(getSnapshot(1)->isHiddenByPolicy()); } + TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) { if (!com::android::graphics::libgui::flags::edge_extension_shader()) { GTEST_SKIP() << "Skipping test because edge_extension_shader is off"; @@ -1920,4 +1921,18 @@ TEST_F(LayerSnapshotTest, multipleEdgeExtensionIncreaseBoundSizeWithinCrop) { EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0); } +TEST_F(LayerSnapshotTest, shouldUpdateInputWhenNoInputInfo) { + // By default the layer has no buffer, so we don't expect it to have an input info + EXPECT_FALSE(getSnapshot(111)->hasInputInfo()); + + setBuffer(111); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + + EXPECT_TRUE(getSnapshot(111)->hasInputInfo()); + EXPECT_TRUE(getSnapshot(111)->inputInfo.inputConfig.test( + gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL)); + EXPECT_FALSE(getSnapshot(2)->hasInputInfo()); +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 45ca7e2f59..ac09cbcea6 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -124,7 +124,7 @@ SchedulerTest::SchedulerTest() { // createConnection call to scheduler makes a createEventConnection call to EventThread. Make // sure that call gets executed and returns an EventThread::Connection object. - EXPECT_CALL(*mEventThread, createEventConnection(_, _)) + EXPECT_CALL(*mEventThread, createEventConnection(_)) .WillRepeatedly(Return(mEventThreadConnection)); mScheduler->setEventThread(Cycle::Render, std::move(eventThread)); @@ -797,7 +797,7 @@ TEST_F(AttachedChoreographerTest, registerMultipleOnSameLayer) { const auto mockConnection1 = sp<MockEventThreadConnection>::make(mEventThread); const auto mockConnection2 = sp<MockEventThreadConnection>::make(mEventThread); - EXPECT_CALL(*mEventThread, createEventConnection(_, _)) + EXPECT_CALL(*mEventThread, createEventConnection(_)) .WillOnce(Return(mockConnection1)) .WillOnce(Return(mockConnection2)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 4b0a7c3a04..86996214b5 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -187,16 +187,6 @@ void DisplayModeSwitchingTest::setupScheduler( mAppEventThread = eventThread.get(); auto sfEventThread = std::make_unique<mock::EventThread>(); - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), - mock::EventThread::kCallingUid))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), - mock::EventThread::kCallingUid))); - auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_shared<mock::VSyncTracker>(); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index df16b2e058..9de3346fb0 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -74,10 +74,8 @@ public: void setEventThread(Cycle cycle, std::unique_ptr<EventThread> eventThreadPtr) { if (cycle == Cycle::Render) { mRenderEventThread = std::move(eventThreadPtr); - mRenderEventConnection = mRenderEventThread->createEventConnection(); } else { mLastCompositeEventThread = std::move(eventThreadPtr); - mLastCompositeEventConnection = mLastCompositeEventThread->createEventConnection(); } } @@ -133,7 +131,9 @@ public: using Scheduler::resyncAllToHardwareVsync; auto& mutableLayerHistory() { return mLayerHistory; } - auto& mutableAttachedChoreographers() { return mAttachedChoreographers; } + auto& mutableAttachedChoreographers() NO_THREAD_SAFETY_ANALYSIS { + return mAttachedChoreographers; + } size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size(); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 725354b845..9dae06aa1d 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -16,7 +16,6 @@ #pragma once -#include <algorithm> #include <chrono> #include <memory> #include <variant> @@ -44,7 +43,6 @@ #include "Layer.h" #include "NativeWindowSurface.h" #include "RenderArea.h" -#include "Scheduler/MessageQueue.h" #include "Scheduler/RefreshRateSelector.h" #include "SurfaceFlinger.h" #include "TestableScheduler.h" @@ -60,7 +58,6 @@ #include "Scheduler/VSyncTracker.h" #include "Scheduler/VsyncController.h" -#include "mock/MockVSyncDispatch.h" #include "mock/MockVSyncTracker.h" #include "mock/MockVsyncController.h" @@ -88,9 +85,7 @@ class Factory final : public surfaceflinger::Factory { public: ~Factory() = default; - std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { - return nullptr; - } + std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; } std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration( Fps /*currentRefreshRate*/) override { @@ -276,17 +271,6 @@ public: auto eventThread = makeMock<mock::EventThread>(options.useNiceMock); auto sfEventThread = makeMock<mock::EventThread>(options.useNiceMock); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(), - mock::EventThread::kCallingUid))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(), - mock::EventThread::kCallingUid))); - auto vsyncController = makeMock<mock::VsyncController>(options.useNiceMock); auto vsyncTracker = makeSharedMock<mock::VSyncTracker>(options.useNiceMock); @@ -502,7 +486,7 @@ public: } auto getDisplayNativePrimaries(const sp<IBinder>& displayToken, - ui::DisplayPrimaries &primaries) { + ui::DisplayPrimaries& primaries) { return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } @@ -675,8 +659,10 @@ public: * post-conditions. */ - const auto& displays() const { return mFlinger->mDisplays; } - const auto& physicalDisplays() const { return mFlinger->mPhysicalDisplays; } + const auto& displays() const NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mDisplays; } + const auto& physicalDisplays() const NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->mPhysicalDisplays; + } const auto& currentState() const { return mFlinger->mCurrentState; } const auto& drawingState() const { return mFlinger->mDrawingState; } const auto& transactionFlags() const { return mFlinger->mTransactionFlags; } @@ -689,13 +675,17 @@ public: auto& mutableDisplayModeController() { return mFlinger->mDisplayModeController; } auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } - auto& mutableDisplays() { return mFlinger->mDisplays; } - auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; } + auto& mutableDisplays() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mDisplays; } + auto& mutablePhysicalDisplays() NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->mPhysicalDisplays; + } auto& mutableDrawingState() { return mFlinger->mDrawingState; } auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; } auto& mutableVisibleRegionsDirty() { return mFlinger->mVisibleRegionsDirty; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } - auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } + auto& mutablePendingHotplugEvents() NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->mPendingHotplugEvents; + } auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; } @@ -703,7 +693,7 @@ public: auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; } auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; } - auto& mutableActiveDisplayId() { return mFlinger->mActiveDisplayId; } + auto& mutableActiveDisplayId() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mActiveDisplayId; } auto& mutablePreviouslyComposedLayers() { return mFlinger->mPreviouslyComposedLayers; } auto& mutableActiveDisplayRotationFlags() { diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 8dd1a34ec4..7398cbebe3 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -24,21 +24,11 @@ namespace android::mock { class EventThread : public android::EventThread { public: - static constexpr auto kCallingUid = static_cast<uid_t>(0); - EventThread(); ~EventThread() override; - // TODO(b/302035909): workaround otherwise gtest complains about - // error: no viable conversion from - // 'tuple<android::ftl::Flags<android::gui::ISurfaceComposer::EventRegistration> &&>' to 'const - // tuple<android::ftl::Flags<android::gui::ISurfaceComposer::EventRegistration>>' - sp<EventThreadConnection> createEventConnection(EventRegistrationFlags flags) const override { - return createEventConnection(false, flags); - } - MOCK_METHOD(sp<EventThreadConnection>, createEventConnection, (bool, EventRegistrationFlags), - (const)); - + MOCK_METHOD(sp<EventThreadConnection>, createEventConnection, (EventRegistrationFlags), + (const, override)); MOCK_METHOD(void, enableSyntheticVsync, (bool), (override)); MOCK_METHOD(void, onHotplugReceived, (PhysicalDisplayId, bool), (override)); MOCK_METHOD(void, onHotplugConnectionError, (int32_t), (override)); |