diff options
20 files changed, 440 insertions, 89 deletions
diff --git a/Android.bp b/Android.bp index 8c4dfbbea4..2520a71968 100644 --- a/Android.bp +++ b/Android.bp @@ -105,7 +105,13 @@ aidl_library { cc_library_headers { name: "libandroid_headers_private", + host_supported: true, export_include_dirs: ["include/private"], + target: { + windows: { + enabled: true, + }, + }, } filegroup { diff --git a/include/android/choreographer.h b/include/android/choreographer.h index f999708f04..d4f30efe3a 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -48,9 +48,19 @@ #ifndef ANDROID_CHOREOGRAPHER_H #define ANDROID_CHOREOGRAPHER_H +#include <stddef.h> #include <stdint.h> #include <sys/cdefs.h> +// This file may also be built on glibc or on Windows/MacOS libc's, so no-op +// and deprecated definitions are provided. +#if !defined(__INTRODUCED_IN) +#define __INTRODUCED_IN(__api_level) /* nothing */ +#endif +#if !defined(__DEPRECATED_IN) +#define __DEPRECATED_IN(__api_level) __attribute__((__deprecated__)) +#endif + __BEGIN_DECLS struct AChoreographer; diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index bf7a0ba5f0..3af9ec7481 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -258,11 +258,24 @@ status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parce } } +void ABBinder::addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& /* recipient */, + void* /* cookie */) { + LOG_ALWAYS_FATAL("Should not reach this. Can't linkToDeath local binders."); +} + ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder) : AIBinder(nullptr /*clazz*/), mRemote(binder) { LOG_ALWAYS_FATAL_IF(binder == nullptr, "binder == nullptr"); } -ABpBinder::~ABpBinder() {} + +ABpBinder::~ABpBinder() { + for (auto& recip : mDeathRecipients) { + sp<AIBinder_DeathRecipient> strongRecip = recip.recipient.promote(); + if (strongRecip) { + strongRecip->pruneThisTransferEntry(getBinder(), recip.cookie); + } + } +} sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) { if (binder == nullptr) { @@ -301,6 +314,11 @@ sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android:: return ret; } +void ABpBinder::addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient, + void* cookie) { + mDeathRecipients.emplace_back(recipient, cookie); +} + struct AIBinder_Weak { wp<AIBinder> binder; }; @@ -426,6 +444,17 @@ AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinde LOG_ALWAYS_FATAL_IF(onDied == nullptr, "onDied == nullptr"); } +void AIBinder_DeathRecipient::pruneThisTransferEntry(const sp<IBinder>& who, void* cookie) { + std::lock_guard<std::mutex> l(mDeathRecipientsMutex); + mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(), + [&](const sp<TransferDeathRecipient>& tdr) { + auto tdrWho = tdr->getWho(); + return tdrWho != nullptr && tdrWho.promote() == who && + cookie == tdr->getCookie(); + }), + mDeathRecipients.end()); +} + void AIBinder_DeathRecipient::pruneDeadTransferEntriesLocked() { mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(), [](const sp<TransferDeathRecipient>& tdr) { @@ -554,8 +583,11 @@ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* return STATUS_UNEXPECTED_NULL; } - // returns binder_status_t - return recipient->linkToDeath(binder->getBinder(), cookie); + binder_status_t ret = recipient->linkToDeath(binder->getBinder(), cookie); + if (ret == STATUS_OK) { + binder->addDeathRecipient(recipient, cookie); + } + return ret; } binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient, diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h index 9d5368f674..a2682d8c0c 100644 --- a/libs/binder/ndk/ibinder_internal.h +++ b/libs/binder/ndk/ibinder_internal.h @@ -51,6 +51,8 @@ struct AIBinder : public virtual ::android::RefBase { ::android::sp<::android::IBinder> binder = const_cast<AIBinder*>(this)->getBinder(); return binder->remoteBinder() != nullptr; } + virtual void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient, + void* cookie) = 0; private: // AIBinder instance is instance of this class for a local object. In order to transact on a @@ -78,6 +80,8 @@ struct ABBinder : public AIBinder, public ::android::BBinder { ::android::status_t dump(int fd, const ::android::Vector<::android::String16>& args) override; ::android::status_t onTransact(uint32_t code, const ::android::Parcel& data, ::android::Parcel* reply, binder_flags_t flags) override; + void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& /* recipient */, + void* /* cookie */) override; private: ABBinder(const AIBinder_Class* clazz, void* userData); @@ -106,12 +110,19 @@ struct ABpBinder : public AIBinder { bool isServiceFuzzing() const { return mServiceFuzzing; } void setServiceFuzzing() { mServiceFuzzing = true; } + void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient, + void* cookie) override; private: friend android::sp<ABpBinder>; explicit ABpBinder(const ::android::sp<::android::IBinder>& binder); ::android::sp<::android::IBinder> mRemote; bool mServiceFuzzing = false; + struct DeathRecipientInfo { + android::wp<AIBinder_DeathRecipient> recipient; + void* cookie; + }; + std::vector<DeathRecipientInfo> mDeathRecipients; }; struct AIBinder_Class { @@ -183,6 +194,7 @@ struct AIBinder_DeathRecipient : ::android::RefBase { binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie); binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie); void setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked); + void pruneThisTransferEntry(const ::android::sp<::android::IBinder>&, void* cookie); private: // When the user of this API deletes a Bp object but not the death recipient, the diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp index 3ee36cd8c3..ca927272f8 100644 --- a/libs/binder/ndk/tests/iface.cpp +++ b/libs/binder/ndk/tests/iface.cpp @@ -25,6 +25,7 @@ using ::android::wp; const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo"; const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die"; +const char* IFoo::kInstanceNameToDieFor2 = "libbinder_ndk-test-IFoo-to-die2"; const char* IFoo::kIFooDescriptor = "my-special-IFoo-class"; struct IFoo_Class_Data { diff --git a/libs/binder/ndk/tests/include/iface/iface.h b/libs/binder/ndk/tests/include/iface/iface.h index 0a562f085d..0cdd50b37a 100644 --- a/libs/binder/ndk/tests/include/iface/iface.h +++ b/libs/binder/ndk/tests/include/iface/iface.h @@ -27,6 +27,7 @@ class IFoo : public virtual ::android::RefBase { public: static const char* kSomeInstanceName; static const char* kInstanceNameToDieFor; + static const char* kInstanceNameToDieFor2; static const char* kIFooDescriptor; static AIBinder_Class* kClass; diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 966ec959b6..ce63b828cb 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -536,6 +536,7 @@ TEST(NdkBinder, DeathRecipient) { bool deathReceived = false; std::function<void(void)> onDeath = [&] { + std::unique_lock<std::mutex> lockDeath(deathMutex); std::cerr << "Binder died (as requested)." << std::endl; deathReceived = true; deathCv.notify_one(); @@ -547,6 +548,7 @@ TEST(NdkBinder, DeathRecipient) { bool wasDeathReceivedFirst = false; std::function<void(void)> onUnlink = [&] { + std::unique_lock<std::mutex> lockUnlink(unlinkMutex); std::cerr << "Binder unlinked (as requested)." << std::endl; wasDeathReceivedFirst = deathReceived; unlinkReceived = true; @@ -560,7 +562,6 @@ TEST(NdkBinder, DeathRecipient) { EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(cookie))); - // the binder driver should return this if the service dies during the transaction EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); foo = nullptr; @@ -579,6 +580,123 @@ TEST(NdkBinder, DeathRecipient) { binder = nullptr; } +TEST(NdkBinder, DeathRecipientDropBinderNoDeath) { + using namespace std::chrono_literals; + + std::mutex deathMutex; + std::condition_variable deathCv; + bool deathReceived = false; + + std::function<void(void)> onDeath = [&] { + std::unique_lock<std::mutex> lockDeath(deathMutex); + std::cerr << "Binder died (as requested)." << std::endl; + deathReceived = true; + deathCv.notify_one(); + }; + + std::mutex unlinkMutex; + std::condition_variable unlinkCv; + bool unlinkReceived = false; + bool wasDeathReceivedFirst = false; + + std::function<void(void)> onUnlink = [&] { + std::unique_lock<std::mutex> lockUnlink(unlinkMutex); + std::cerr << "Binder unlinked (as requested)." << std::endl; + wasDeathReceivedFirst = deathReceived; + unlinkReceived = true; + unlinkCv.notify_one(); + }; + + // keep the death recipient around + ndk::ScopedAIBinder_DeathRecipient recipient(AIBinder_DeathRecipient_new(LambdaOnDeath)); + AIBinder_DeathRecipient_setOnUnlinked(recipient.get(), LambdaOnUnlink); + + { + AIBinder* binder; + sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor2, &binder); + ASSERT_NE(nullptr, foo.get()); + ASSERT_NE(nullptr, binder); + + DeathRecipientCookie* cookie = new DeathRecipientCookie{&onDeath, &onUnlink}; + + EXPECT_EQ(STATUS_OK, + AIBinder_linkToDeath(binder, recipient.get(), static_cast<void*>(cookie))); + // let the sp<IFoo> and AIBinder fall out of scope + AIBinder_decStrong(binder); + binder = nullptr; + } + + { + std::unique_lock<std::mutex> lockDeath(deathMutex); + EXPECT_FALSE(deathCv.wait_for(lockDeath, 100ms, [&] { return deathReceived; })); + EXPECT_FALSE(deathReceived); + } + + { + std::unique_lock<std::mutex> lockUnlink(unlinkMutex); + EXPECT_TRUE(deathCv.wait_for(lockUnlink, 1s, [&] { return unlinkReceived; })); + EXPECT_TRUE(unlinkReceived); + EXPECT_FALSE(wasDeathReceivedFirst); + } +} + +TEST(NdkBinder, DeathRecipientDropBinderOnDied) { + using namespace std::chrono_literals; + + std::mutex deathMutex; + std::condition_variable deathCv; + bool deathReceived = false; + + sp<IFoo> foo; + AIBinder* binder; + std::function<void(void)> onDeath = [&] { + std::unique_lock<std::mutex> lockDeath(deathMutex); + std::cerr << "Binder died (as requested)." << std::endl; + deathReceived = true; + AIBinder_decStrong(binder); + binder = nullptr; + deathCv.notify_one(); + }; + + std::mutex unlinkMutex; + std::condition_variable unlinkCv; + bool unlinkReceived = false; + bool wasDeathReceivedFirst = false; + + std::function<void(void)> onUnlink = [&] { + std::unique_lock<std::mutex> lockUnlink(unlinkMutex); + std::cerr << "Binder unlinked (as requested)." << std::endl; + wasDeathReceivedFirst = deathReceived; + unlinkReceived = true; + unlinkCv.notify_one(); + }; + + ndk::ScopedAIBinder_DeathRecipient recipient(AIBinder_DeathRecipient_new(LambdaOnDeath)); + AIBinder_DeathRecipient_setOnUnlinked(recipient.get(), LambdaOnUnlink); + + foo = IFoo::getService(IFoo::kInstanceNameToDieFor2, &binder); + ASSERT_NE(nullptr, foo.get()); + ASSERT_NE(nullptr, binder); + + DeathRecipientCookie* cookie = new DeathRecipientCookie{&onDeath, &onUnlink}; + EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient.get(), static_cast<void*>(cookie))); + + EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); + + { + std::unique_lock<std::mutex> lockDeath(deathMutex); + EXPECT_TRUE(deathCv.wait_for(lockDeath, 1s, [&] { return deathReceived; })); + EXPECT_TRUE(deathReceived); + } + + { + std::unique_lock<std::mutex> lockUnlink(unlinkMutex); + EXPECT_TRUE(deathCv.wait_for(lockUnlink, 100ms, [&] { return unlinkReceived; })); + EXPECT_TRUE(unlinkReceived); + EXPECT_TRUE(wasDeathReceivedFirst); + } +} + TEST(NdkBinder, RetrieveNonNdkService) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -958,6 +1076,10 @@ int main(int argc, char* argv[]) { } if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); + return manualThreadPoolService(IFoo::kInstanceNameToDieFor2); + } + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); return manualPollingService(IFoo::kSomeInstanceName); } if (fork() == 0) { diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 5ac965f566..32b2b68b4d 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -5,6 +5,7 @@ package { // to get the below license kinds: // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["frameworks_native_license"], + default_team: "trendy_team_android_core_graphics_stack", } cc_test { diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 5af48550c6..bdec5c33cd 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -119,3 +119,10 @@ flag { description: "Controls the API to provide InputDevice view behavior." bug: "246946631" } + +flag { + name: "enable_touchpad_fling_stop" + namespace: "input" + description: "Enable fling scrolling to be stopped by putting a finger on the touchpad again" + bug: "281106755" +} diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h index bcfae10201..48fb02f69d 100644 --- a/libs/nativewindow/include/vndk/hardware_buffer.h +++ b/libs/nativewindow/include/vndk/hardware_buffer.h @@ -107,7 +107,7 @@ enum { }; /** - * Additional options for AHardwareBuffer_allocate2. These correspond to + * Additional options for AHardwareBuffer_allocateWithOptions. These correspond to * android.hardware.graphics.common.ExtendableType */ typedef struct { diff --git a/libs/vibrator/ExternalVibration.cpp b/libs/vibrator/ExternalVibration.cpp index 80e911c65d..c97e496083 100644 --- a/libs/vibrator/ExternalVibration.cpp +++ b/libs/vibrator/ExternalVibration.cpp @@ -17,7 +17,7 @@ #include <vibrator/ExternalVibration.h> #include <vibrator/ExternalVibrationUtils.h> -#include <android/os/IExternalVibratorService.h> +#include <android/os/ExternalVibrationScale.h> #include <binder/Parcel.h> #include <log/log.h> #include <utils/Errors.h> @@ -65,24 +65,36 @@ inline bool ExternalVibration::operator==(const ExternalVibration& rhs) const { return mToken == rhs.mToken; } -os::HapticScale ExternalVibration::externalVibrationScaleToHapticScale(int externalVibrationScale) { - switch (externalVibrationScale) { - case IExternalVibratorService::SCALE_MUTE: - return os::HapticScale::MUTE; - case IExternalVibratorService::SCALE_VERY_LOW: - return os::HapticScale::VERY_LOW; - case IExternalVibratorService::SCALE_LOW: - return os::HapticScale::LOW; - case IExternalVibratorService::SCALE_NONE: - return os::HapticScale::NONE; - case IExternalVibratorService::SCALE_HIGH: - return os::HapticScale::HIGH; - case IExternalVibratorService::SCALE_VERY_HIGH: - return os::HapticScale::VERY_HIGH; +os::HapticScale ExternalVibration::externalVibrationScaleToHapticScale( + os::ExternalVibrationScale externalVibrationScale) { + os::HapticLevel scaleLevel = os::HapticLevel::NONE; + + switch (externalVibrationScale.scaleLevel) { + case os::ExternalVibrationScale::ScaleLevel::SCALE_MUTE: + scaleLevel = os::HapticLevel::MUTE; + break; + case os::ExternalVibrationScale::ScaleLevel::SCALE_VERY_LOW: + scaleLevel = os::HapticLevel::VERY_LOW; + break; + case os::ExternalVibrationScale::ScaleLevel::SCALE_LOW: + scaleLevel = os::HapticLevel::LOW; + break; + case os::ExternalVibrationScale::ScaleLevel::SCALE_NONE: + scaleLevel = os::HapticLevel::NONE; + break; + case os::ExternalVibrationScale::ScaleLevel::SCALE_HIGH: + scaleLevel = os::HapticLevel::HIGH; + break; + case os::ExternalVibrationScale::ScaleLevel::SCALE_VERY_HIGH: + scaleLevel = os::HapticLevel::VERY_HIGH; + break; default: - ALOGE("Unknown ExternalVibrationScale %d, not applying scaling", externalVibrationScale); - return os::HapticScale::NONE; - } + ALOGE("Unknown ExternalVibrationScale %d, not applying scaling", + externalVibrationScale.scaleLevel); + } + + return {/*level=*/scaleLevel, /*adaptiveScaleFactor=*/ + externalVibrationScale.adaptiveHapticsScale}; } } // namespace os diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp index 980b08ba36..761ac1bf3b 100644 --- a/libs/vibrator/ExternalVibrationUtils.cpp +++ b/libs/vibrator/ExternalVibrationUtils.cpp @@ -26,30 +26,30 @@ static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f; static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f; static constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f; -float getHapticScaleGamma(HapticScale scale) { - switch (scale) { - case HapticScale::VERY_LOW: +float getHapticScaleGamma(HapticLevel level) { + switch (level) { + case HapticLevel::VERY_LOW: return 2.0f; - case HapticScale::LOW: + case HapticLevel::LOW: return 1.5f; - case HapticScale::HIGH: + case HapticLevel::HIGH: return 0.5f; - case HapticScale::VERY_HIGH: + case HapticLevel::VERY_HIGH: return 0.25f; default: return 1.0f; } } -float getHapticMaxAmplitudeRatio(HapticScale scale) { - switch (scale) { - case HapticScale::VERY_LOW: +float getHapticMaxAmplitudeRatio(HapticLevel level) { + switch (level) { + case HapticLevel::VERY_LOW: return HAPTIC_SCALE_VERY_LOW_RATIO; - case HapticScale::LOW: + case HapticLevel::LOW: return HAPTIC_SCALE_LOW_RATIO; - case HapticScale::NONE: - case HapticScale::HIGH: - case HapticScale::VERY_HIGH: + case HapticLevel::NONE: + case HapticLevel::HIGH: + case HapticLevel::VERY_HIGH: return 1.0f; default: return 0.0f; @@ -57,19 +57,28 @@ float getHapticMaxAmplitudeRatio(HapticScale scale) { } void applyHapticScale(float* buffer, size_t length, HapticScale scale) { - if (scale == HapticScale::MUTE) { + if (scale.isScaleMute()) { memset(buffer, 0, length * sizeof(float)); return; } - if (scale == HapticScale::NONE) { + if (scale.isScaleNone()) { return; } - float gamma = getHapticScaleGamma(scale); - float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale); + HapticLevel hapticLevel = scale.getLevel(); + float adaptiveScaleFactor = scale.getAdaptiveScaleFactor(); + float gamma = getHapticScaleGamma(hapticLevel); + float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(hapticLevel); + for (size_t i = 0; i < length; i++) { - float sign = buffer[i] >= 0 ? 1.0 : -1.0; - buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma) - * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign; + if (hapticLevel != HapticLevel::NONE) { + float sign = buffer[i] >= 0 ? 1.0 : -1.0; + buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma) + * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign; + } + + if (adaptiveScaleFactor != 1.0f) { + buffer[i] *= adaptiveScaleFactor; + } } } @@ -89,13 +98,13 @@ void clipHapticData(float* buffer, size_t length, float limit) { } // namespace bool isValidHapticScale(HapticScale scale) { - switch (scale) { - case HapticScale::MUTE: - case HapticScale::VERY_LOW: - case HapticScale::LOW: - case HapticScale::NONE: - case HapticScale::HIGH: - case HapticScale::VERY_HIGH: + switch (scale.getLevel()) { + case HapticLevel::MUTE: + case HapticLevel::VERY_LOW: + case HapticLevel::LOW: + case HapticLevel::NONE: + case HapticLevel::HIGH: + case HapticLevel::VERY_HIGH: return true; } return false; diff --git a/libs/vibrator/include/vibrator/ExternalVibration.h b/libs/vibrator/include/vibrator/ExternalVibration.h index 00cd3cd256..ac2767e17e 100644 --- a/libs/vibrator/include/vibrator/ExternalVibration.h +++ b/libs/vibrator/include/vibrator/ExternalVibration.h @@ -24,6 +24,7 @@ #include <system/audio.h> #include <utils/RefBase.h> #include <vibrator/ExternalVibrationUtils.h> +#include <android/os/ExternalVibrationScale.h> namespace android { namespace os { @@ -45,10 +46,11 @@ public : audio_attributes_t getAudioAttributes() const { return mAttrs; } sp<IExternalVibrationController> getController() { return mController; } - /* Converts the scale from non-public ExternalVibrationService into the HapticScale + /* Converts the scale from non-public ExternalVibrationService into the HapticScaleLevel * used by the utils. */ - static os::HapticScale externalVibrationScaleToHapticScale(int externalVibrationScale); + static os::HapticScale externalVibrationScaleToHapticScale( + os::ExternalVibrationScale externalVibrationScale); private: int32_t mUid; diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h index ca219d3cbf..d9a2b81ddf 100644 --- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h +++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h @@ -19,7 +19,7 @@ namespace android::os { -enum class HapticScale { +enum class HapticLevel { MUTE = -100, VERY_LOW = -2, LOW = -1, @@ -28,10 +28,41 @@ enum class HapticScale { VERY_HIGH = 2, }; +class HapticScale { +private: +HapticLevel mLevel = HapticLevel::NONE; +float mAdaptiveScaleFactor = 1.0f; + +public: +constexpr HapticScale(HapticLevel level, float adaptiveScaleFactor) + : mLevel(level), mAdaptiveScaleFactor(adaptiveScaleFactor) {} +constexpr HapticScale(HapticLevel level) : mLevel(level) {} +constexpr HapticScale() {} + +HapticLevel getLevel() const { return mLevel; } +float getAdaptiveScaleFactor() const { return mAdaptiveScaleFactor; } + +bool operator==(const HapticScale& other) const { + return mLevel == other.mLevel && mAdaptiveScaleFactor == other.mAdaptiveScaleFactor; +} + +bool isScaleNone() const { + return mLevel == HapticLevel::NONE && mAdaptiveScaleFactor == 1.0f; +} + +bool isScaleMute() const { + return mLevel == HapticLevel::MUTE; +} + +static HapticScale mute() { + return {/*level=*/os::HapticLevel::MUTE}; +} +}; + bool isValidHapticScale(HapticScale scale); -/* Scales the haptic data in given buffer using the selected HapticScale and ensuring no absolute - * value will be larger than the absolute of given limit. +/* Scales the haptic data in given buffer using the selected HapticScaleLevel and ensuring no + * absolute value will be larger than the absolute of given limit. * The limit will be ignored if it is NaN or zero. */ void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit); diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp index 19788cee40..797ebcc8be 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -67,7 +67,8 @@ GestureConverter::GestureConverter(InputReaderContext& readerContext, : mDeviceId(deviceId), mReaderContext(readerContext), mPointerController(readerContext.getPointerController(deviceId)), - mEnablePointerChoreographer(input_flags::enable_pointer_choreographer()) { + mEnablePointerChoreographer(input_flags::enable_pointer_choreographer()), + mEnableFlingStop(input_flags::enable_touchpad_fling_stop()) { deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mXAxisInfo); deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mYAxisInfo); } @@ -400,20 +401,55 @@ std::list<NotifyArgs> GestureConverter::handleFling(nsecs_t when, nsecs_t readTi // ensure consistency between touchscreen and touchpad flings), so we're just using // the "start fling" gestures as a marker for the end of a two-finger scroll // gesture. + mFlingMayBeInProgress = true; return endScroll(when, readTime); } break; case GESTURES_FLING_TAP_DOWN: if (mCurrentClassification == MotionClassification::NONE) { - // Use the tap down state of a fling gesture as an indicator that a contact - // has been initiated with the touchpad. We treat this as a move event with zero - // magnitude, which will also result in the pointer icon being updated. - // TODO(b/282023644): Add a signal in libgestures for when a stable contact has been - // initiated with a touchpad. - return handleMove(when, readTime, gestureStartTime, - Gesture(kGestureMove, gesture.start_time, gesture.end_time, - /*dx=*/0.f, - /*dy=*/0.f)); + if (mEnableFlingStop && mFlingMayBeInProgress) { + // The user has just touched the pad again after ending a two-finger scroll + // motion, which might have started a fling. We want to stop the fling, but + // unfortunately there's currently no API for doing so. Instead, send and + // immediately cancel a fake finger to cause the scrolling to stop and hopefully + // avoid side effects (e.g. activation of UI elements). + // TODO(b/326056750): add an API for fling stops. + mFlingMayBeInProgress = false; + const auto [xCursorPosition, yCursorPosition] = mEnablePointerChoreographer + ? FloatPoint{0, 0} + : mPointerController->getPosition(); + PointerCoords coords; + coords.clear(); + coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0); + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0); + + std::list<NotifyArgs> out; + mDownTime = when; + out += exitHover(when, readTime, xCursorPosition, yCursorPosition); + // TODO(b/281106755): add a MotionClassification value for fling stops. + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN, + /*actionButton=*/0, /*buttonState=*/0, + /*pointerCount=*/1, &coords, xCursorPosition, + yCursorPosition)); + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_CANCEL, + /*actionButton=*/0, /*buttonState=*/0, + /*pointerCount=*/1, &coords, xCursorPosition, + yCursorPosition)); + out += enterHover(when, readTime, xCursorPosition, yCursorPosition); + return out; + } else { + // Use the tap down state of a fling gesture as an indicator that a contact + // has been initiated with the touchpad. We treat this as a move event with zero + // magnitude, which will also result in the pointer icon being updated. + // TODO(b/282023644): Add a signal in libgestures for when a stable contact has + // been initiated with a touchpad. + return handleMove(when, readTime, gestureStartTime, + Gesture(kGestureMove, gesture.start_time, gesture.end_time, + /*dx=*/0.f, + /*dy=*/0.f)); + } } break; default: diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h index 07cc56c618..ffab03967d 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -106,6 +106,7 @@ private: InputReaderContext& mReaderContext; std::shared_ptr<PointerControllerInterface> mPointerController; const bool mEnablePointerChoreographer; + const bool mEnableFlingStop; std::optional<int32_t> mDisplayId; FloatRect mBoundsInLogicalDisplay{}; @@ -120,6 +121,9 @@ private: // Whether we are currently in a hover state (i.e. a HOVER_ENTER event has been sent without a // matching HOVER_EXIT). bool mIsHovering = false; + // Whether we've received a "fling start" gesture (i.e. the end of a scroll) but no "fling tap + // down" gesture to match it yet. + bool mFlingMayBeInProgress = false; MotionClassification mCurrentClassification = MotionClassification::NONE; // Only used when mCurrentClassification is MULTI_FINGER_SWIPE. diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index dd88165561..ca9ef8e0ef 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -1167,6 +1167,38 @@ TEST_F(GestureConverterTest, FlingTapDown) { ASSERT_TRUE(mFakePointerController->isPointerShown()); } +TEST_F(GestureConverterTest, FlingTapDownAfterScrollStopsFling) { + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + input_flags::enable_touchpad_fling_stop(true); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); + + Gesture scrollGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, scrollGesture); + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, + GESTURES_FLING_START); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); + + Gesture tapDownGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /*vx=*/0.f, /*vy=*/0.f, GESTURES_FLING_TAP_DOWN); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapDownGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_DOWN)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), + WithMotionClassification(MotionClassification::NONE))))); + ASSERT_THAT(args, + Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); +} + TEST_F(GestureConverterTest, Tap) { // Tap should produce button press/release events InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); @@ -2556,6 +2588,38 @@ TEST_F(GestureConverterTestWithChoreographer, FlingTapDown) { WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); } +TEST_F(GestureConverterTestWithChoreographer, FlingTapDownAfterScrollStopsFling) { + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + input_flags::enable_touchpad_fling_stop(true); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); + + Gesture scrollGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, scrollGesture); + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, + GESTURES_FLING_START); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); + + Gesture tapDownGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /*vx=*/0.f, /*vy=*/0.f, GESTURES_FLING_TAP_DOWN); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapDownGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_DOWN)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), + WithMotionClassification(MotionClassification::NONE))))); + ASSERT_THAT(args, + Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); +} + TEST_F(GestureConverterTestWithChoreographer, Tap) { // Tap should produce button press/release events InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); diff --git a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp index 759485ffce..61ab47a75a 100644 --- a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp +++ b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp @@ -70,12 +70,14 @@ static void runBenchmark(benchmark::State& state, microseconds delay, R (IPower: if (hal == nullptr) { ALOGV("Power HAL not available, skipping test..."); + state.SkipWithMessage("Power HAL unavailable"); return; } ndk::ScopedAStatus ret = (*hal.*fn)(std::forward<Args1>(args1)...); if (ret.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { ALOGV("Power HAL does not support this operation, skipping test..."); + state.SkipWithMessage("operation unsupported"); return; } @@ -97,6 +99,7 @@ static void runSessionBenchmark(benchmark::State& state, R (IPowerHintSession::* if (hal == nullptr) { ALOGV("Power HAL not available, skipping test..."); + state.SkipWithMessage("Power HAL unavailable"); return; } @@ -109,12 +112,14 @@ static void runSessionBenchmark(benchmark::State& state, R (IPowerHintSession::* if (session == nullptr) { ALOGV("Power HAL doesn't support session, skipping test..."); + state.SkipWithMessage("operation unsupported"); return; } ndk::ScopedAStatus ret = (*session.*fn)(std::forward<Args1>(args1)...); if (ret.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { ALOGV("Power HAL does not support this operation, skipping test..."); + state.SkipWithMessage("operation unsupported"); return; } @@ -163,6 +168,7 @@ static void BM_PowerHalAidlBenchmarks_createHintSession(benchmark::State& state) if (hal == nullptr) { ALOGV("Power HAL not available, skipping test..."); + state.SkipWithMessage("Power HAL unavailable"); return; } @@ -170,6 +176,7 @@ static void BM_PowerHalAidlBenchmarks_createHintSession(benchmark::State& state) hal->createHintSession(tgid, uid, threadIds, durationNanos, &appSession); if (ret.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { ALOGV("Power HAL does not support this operation, skipping test..."); + state.SkipWithMessage("operation unsupported"); return; } diff --git a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp index 111b5d70bc..bcb376b799 100644 --- a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp +++ b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp @@ -50,6 +50,7 @@ static void runBenchmark(benchmark::State& state, microseconds delay, Return<R> if (hal == nullptr) { ALOGV("Power HAL HIDL not available, skipping test..."); + state.SkipWithMessage("Power HAL unavailable"); return; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index edba50bde6..e44f841a25 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -233,31 +233,25 @@ bool validateCompositionDataspace(Dataspace dataspace) { } std::chrono::milliseconds getIdleTimerTimeout(DisplayId displayId) { - const auto displayIdleTimerMsKey = [displayId] { - std::stringstream ss; - ss << "debug.sf.set_idle_timer_ms_" << displayId.value; - return ss.str(); - }(); - - const int32_t displayIdleTimerMs = base::GetIntProperty(displayIdleTimerMsKey, 0); - if (displayIdleTimerMs > 0) { + if (const int32_t displayIdleTimerMs = + base::GetIntProperty("debug.sf.set_idle_timer_ms_"s + + std::to_string(displayId.value), + 0); + displayIdleTimerMs > 0) { return std::chrono::milliseconds(displayIdleTimerMs); } - const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms", 0); + const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms"s, 0); const int32_t millis = setIdleTimerMs ? setIdleTimerMs : sysprop::set_idle_timer_ms(0); return std::chrono::milliseconds(millis); } bool getKernelIdleTimerSyspropConfig(DisplayId displayId) { - const auto displaySupportKernelIdleTimerKey = [displayId] { - std::stringstream ss; - ss << "debug.sf.support_kernel_idle_timer_" << displayId.value; - return ss.str(); - }(); + const bool displaySupportKernelIdleTimer = + base::GetBoolProperty("debug.sf.support_kernel_idle_timer_"s + + std::to_string(displayId.value), + false); - const auto displaySupportKernelIdleTimer = - base::GetBoolProperty(displaySupportKernelIdleTimerKey, false); return displaySupportKernelIdleTimer || sysprop::support_kernel_idle_timer(false); } @@ -467,11 +461,10 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI wideColorGamutCompositionPixelFormat = static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888)); - mLayerCachingEnabled = [] { - const bool enable = - android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); - return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable); - }(); + mLayerCachingEnabled = + base::GetBoolProperty("debug.sf.enable_layer_caching"s, + sysprop::SurfaceFlingerProperties::enable_layer_caching() + .value_or(false)); useContextPriority = use_context_priority(true); @@ -3571,10 +3564,10 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( const auto enableFrameRateOverride = sysprop::enable_frame_rate_override(true) ? Config::FrameRateOverride::Enabled : Config::FrameRateOverride::Disabled; - Config config = + const Config config = {.enableFrameRateOverride = enableFrameRateOverride, .frameRateMultipleThreshold = - base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0), + base::GetIntProperty("debug.sf.frame_rate_multiple_threshold"s, 0), .idleTimerTimeout = idleTimerTimeoutMs, .kernelIdleTimerController = kernelIdleTimerController}; @@ -7691,7 +7684,7 @@ status_t SurfaceFlinger::setSchedFifo(bool enabled) { status_t SurfaceFlinger::setSchedAttr(bool enabled) { static const unsigned int kUclampMin = - base::GetUintProperty<unsigned int>("ro.surface_flinger.uclamp.min", 0U); + base::GetUintProperty<unsigned int>("ro.surface_flinger.uclamp.min"s, 0U); if (!kUclampMin) { // uclamp.min set to 0 (default), skip setting |