Merge "Refactor of screenshot code on main thread." into main
diff --git a/Android.bp b/Android.bp
index 8c4dfbb..2520a71 100644
--- a/Android.bp
+++ b/Android.bp
@@ -105,7 +105,13 @@
cc_library_headers {
name: "libandroid_headers_private",
+ host_supported: true,
export_include_dirs: ["include/private"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
}
filegroup {
diff --git a/data/etc/android.software.contextualsearch.xml b/data/etc/android.software.contextualsearch.xml
new file mode 100644
index 0000000..4564ac8
--- /dev/null
+++ b/data/etc/android.software.contextualsearch.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<!-- Feature for devices supporting contextual search helper. -->
+<permissions>
+ <feature name="android.software.contextualsearch" />
+</permissions>
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index f999708..d4f30ef 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 3af9ec7..bf7a0ba 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -258,24 +258,11 @@
}
}
-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() {
- for (auto& recip : mDeathRecipients) {
- sp<AIBinder_DeathRecipient> strongRecip = recip.recipient.promote();
- if (strongRecip) {
- strongRecip->pruneThisTransferEntry(getBinder(), recip.cookie);
- }
- }
-}
+ABpBinder::~ABpBinder() {}
sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) {
if (binder == nullptr) {
@@ -314,11 +301,6 @@
return ret;
}
-void ABpBinder::addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient,
- void* cookie) {
- mDeathRecipients.emplace_back(recipient, cookie);
-}
-
struct AIBinder_Weak {
wp<AIBinder> binder;
};
@@ -444,17 +426,6 @@
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) {
@@ -583,11 +554,8 @@
return STATUS_UNEXPECTED_NULL;
}
- binder_status_t ret = recipient->linkToDeath(binder->getBinder(), cookie);
- if (ret == STATUS_OK) {
- binder->addDeathRecipient(recipient, cookie);
- }
- return ret;
+ // returns binder_status_t
+ return recipient->linkToDeath(binder->getBinder(), cookie);
}
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 a2682d8..9d5368f 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -51,8 +51,6 @@
::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
@@ -80,8 +78,6 @@
::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);
@@ -110,19 +106,12 @@
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 {
@@ -194,7 +183,6 @@
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 ca92727..3ee36cd 100644
--- a/libs/binder/ndk/tests/iface.cpp
+++ b/libs/binder/ndk/tests/iface.cpp
@@ -25,7 +25,6 @@
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 0cdd50b..0a562f0 100644
--- a/libs/binder/ndk/tests/include/iface/iface.h
+++ b/libs/binder/ndk/tests/include/iface/iface.h
@@ -27,7 +27,6 @@
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 ce63b82..966ec95 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -536,7 +536,6 @@
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();
@@ -548,7 +547,6 @@
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;
@@ -562,6 +560,7 @@
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;
@@ -580,123 +579,6 @@
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"
@@ -1076,10 +958,6 @@
}
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 5ac965f..32b2b68 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -5,6 +5,7 @@
// 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/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp
deleted file mode 100644
index 35dd9ec..0000000
--- a/libs/gui/fuzzer/Android.bp
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2021 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.
- */
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // 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_defaults {
- name: "libgui_fuzzer_defaults",
- defaults: ["android.hardware.power-ndk_shared"],
- static_libs: [
- "android.hidl.token@1.0-utils",
- "libbinder_random_parcel",
- "libgui_aidl_static",
- "libgui_window_info_static",
- "libpdx",
- "libgmock",
- "libgui_mocks",
- "libgmock_ndk",
- "libgmock_main",
- "libgtest_ndk_c++",
- "libgmock_main_ndk",
- "librenderengine_mocks",
- "perfetto_trace_protos",
- "libcompositionengine_mocks",
- "perfetto_trace_protos",
- ],
- shared_libs: [
- "android.hardware.configstore@1.0",
- "android.hardware.configstore-utils",
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.bufferqueue@2.0",
- "android.hidl.token@1.0",
- "libSurfaceFlingerProp",
- "libgui",
- "libbase",
- "liblog",
- "libEGL",
- "libGLESv2",
- "libbinder",
- "libcutils",
- "libhidlbase",
- "libinput",
- "libui",
- "libutils",
- "libnativewindow",
- "libvndksupport",
- ],
- header_libs: [
- "libdvr_headers",
- "libui_fuzzableDataspaces_headers",
- ],
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- componentid: 155276,
- hotlists: [
- "4593311",
- ],
- description: "The fuzzer targets the APIs of libgui library",
- vector: "local_no_privileges_required",
- service_privilege: "privileged",
- users: "multi_user",
- fuzzed_code_usage: "shipped",
- },
-}
-
-cc_fuzz {
- name: "libgui_surfaceComposer_fuzzer",
- srcs: [
- "libgui_surfaceComposer_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- "service_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_surfaceComposerClient_fuzzer",
- srcs: [
- "libgui_surfaceComposerClient_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- "service_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_parcelable_fuzzer",
- srcs: [
- "libgui_parcelable_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_bufferQueue_fuzzer",
- srcs: [
- "libgui_bufferQueue_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_consumer_fuzzer",
- srcs: [
- "libgui_consumer_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- ],
-}
-
-cc_fuzz {
- name: "libgui_displayEvent_fuzzer",
- srcs: [
- "libgui_displayEvent_fuzzer.cpp",
- ],
- defaults: [
- "libgui_fuzzer_defaults",
- ],
-}
diff --git a/libs/gui/fuzzer/README.md b/libs/gui/fuzzer/README.md
deleted file mode 100644
index 96e27c9..0000000
--- a/libs/gui/fuzzer/README.md
+++ /dev/null
@@ -1,219 +0,0 @@
-# Fuzzers for Libgui
-
-## Table of contents
-+ [libgui_surfaceComposer_fuzzer](#SurfaceComposer)
-+ [libgui_surfaceComposerClient_fuzzer](#SurfaceComposerClient)
-+ [libgui_parcelable_fuzzer](#Libgui_Parcelable)
-+ [libgui_bufferQueue_fuzzer](#BufferQueue)
-+ [libgui_consumer_fuzzer](#Libgui_Consumer)
-+ [libgui_displayEvent_fuzzer](#LibGui_DisplayEvent)
-
-# <a name="libgui_surfaceComposer_fuzzer"></a> Fuzzer for SurfaceComposer
-
-SurfaceComposer supports the following parameters:
-1. SurfaceWidth (parameter name:`width`)
-2. SurfaceHeight (parameter name:`height`)
-3. TransactionStateFlags (parameter name:`flags`)
-4. TransformHint (parameter name:`outTransformHint`)
-5. SurfacePixelFormat (parameter name:`format`)
-6. LayerId (parameter name:`outLayerId`)
-7. SurfaceComposerTags (parameter name:`surfaceTag`)
-8. PowerBoostID (parameter name:`boostId`)
-9. VsyncSource (parameter name:`vsyncSource`)
-10. EventRegistrationFlags (parameter name:`eventRegistration`)
-11. FrameRateCompatibility (parameter name:`frameRateCompatibility`)
-12. ChangeFrameRateStrategy (parameter name:`changeFrameRateStrategy`)
-13. HdrTypes (parameter name:`hdrTypes`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`surfaceTag` | 0.`BnSurfaceComposer::BOOT_FINISHED`, 1.`BnSurfaceComposer::CREATE_CONNECTION`, 2.`BnSurfaceComposer::GET_STATIC_DISPLAY_INFO`, 3.`BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION`, 4.`BnSurfaceComposer::CREATE_DISPLAY`, 5.`BnSurfaceComposer::DESTROY_DISPLAY`, 6.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN`, 7.`BnSurfaceComposer::SET_TRANSACTION_STATE`, 8.`BnSurfaceComposer::AUTHENTICATE_SURFACE`, 9.`BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS`, 10.`BnSurfaceComposer::GET_DISPLAY_STATE`, 11.`BnSurfaceComposer::CAPTURE_DISPLAY`, 12.`BnSurfaceComposer::CAPTURE_LAYERS`, 13.`BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS`, 14.`BnSurfaceComposer::GET_ANIMATION_FRAME_STATS`, 15.`BnSurfaceComposer::SET_POWER_MODE`, 16.`BnSurfaceComposer::GET_DISPLAY_STATS`, 17.`BnSurfaceComposer::SET_ACTIVE_COLOR_MODE`, 18.`BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS`, 19.`BnSurfaceComposer::INJECT_VSYNC`, 20.`BnSurfaceComposer::GET_LAYER_DEBUG_INFO`, 21.`BnSurfaceComposer::GET_COMPOSITION_PREFERENCE`, 22.`BnSurfaceComposer::GET_COLOR_MANAGEMENT`, 23.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES`, 24.`BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED`, 25.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE`, 26.`BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT`, 27.`BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY`, 28.`BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES`, 29.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS`, 30.`BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER`, 31.`BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER`, 32.`BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS`, 33.`BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS`, 34.`BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT`, 35.`BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS`, 36.`BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID`, 37.`BnSurfaceComposer::NOTIFY_POWER_BOOST`, 38.`BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS`, 39.`BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE`, 40.`BnSurfaceComposer::SET_GAME_CONTENT_TYPE`, 41.`BnSurfaceComposer::SET_FRAME_RATE`, 42.`BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN`, 43.`BnSurfaceComposer::SET_FRAME_TIMELINE_INFO`, 44.`BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER`, 45.`BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY`, 46.`BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT`, 47.`BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO`, 48.`BnSurfaceComposer::ADD_FPS_LISTENER`, 49.`BnSurfaceComposer::REMOVE_FPS_LISTENER`, 50.`BnSurfaceComposer::OVERRIDE_HDR_TYPES`, 51.`BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER`, 52.`BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER`, 53.`BnSurfaceComposer::ON_PULL_ATOM`, 54.`BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER`, 55.`BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER` | Value obtained from FuzzedDataProvider|
-|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider|
-|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider|
-|`eventRegistration`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride` |Value obtained from FuzzedDataProvider|
-|`frameRateCompatibility`| 0.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT`, 1.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE` |Value obtained from FuzzedDataProvider|
-|`changeFrameRateStrategy`| 0.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS`, 1.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS` |Value obtained from FuzzedDataProvider|
-|`hdrTypes`| 0.`ui::Hdr::DOLBY_VISION`, 1.`ui::Hdr::HDR10`, 2.`ui::Hdr::HLG`, 3.`ui::Hdr::HDR10_PLUS` |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_surfaceComposer_fuzzer
-```
-2. Run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_surfaceComposer_fuzzer/libgui_surfaceComposer_fuzzer
-```
-
-# <a name="libgui_surfaceComposerClient_fuzzer"></a> Fuzzer for SurfaceComposerClient
-
-SurfaceComposerClient supports the following data sources:
-1. SurfaceWidth (parameter name:`width`)
-2. SurfaceHeight (parameter name:`height`)
-3. TransactionStateFlags (parameter name:`flags`)
-4. TransformHint (parameter name:`outTransformHint`)
-5. SurfacePixelFormat (parameter name:`format`)
-6. LayerId (parameter name:`outLayerId`)
-7. SurfaceComposerClientTags (parameter name:`surfaceTag`)
-8. DefaultMode (parameter name:`defaultMode`)
-9. PrimaryRefreshRateMin (parameter name:`primaryRefreshRateMin`)
-10. PrimaryRefreshRateMax (parameter name:`primaryRefreshRateMax`)
-11. AppRefreshRateMin (parameter name:`appRefreshRateMin`)
-12. AppRefreshRateMax (parameter name:`appRefreshRateMax`)
-13. DisplayPowerMode (parameter name:`mode`)
-14. CacheId (parameter name:`cacheId`)
-15. DisplayBrightness (parameter name:`brightness`)
-16. PowerBoostID (parameter name:`boostId`)
-17. AtomId (parameter name:`atomId`)
-18. ComponentMask (parameter name:`componentMask`)
-19. MaxFrames (parameter name:`maxFrames`)
-20. TaskId (parameter name:`taskId`)
-21. Alpha (parameter name:`aplha`)
-22. CornerRadius (parameter name:`cornerRadius`)
-23. BackgroundBlurRadius (parameter name:`backgroundBlurRadius`)
-24. Half3Color (parameter name:`color`)
-25. LayerStack (parameter name:`layerStack`)
-26. Dataspace (parameter name:`dataspace`)
-27. Api (parameter name:`api`)
-28. Priority (parameter name:`priority`)
-29. TouchableRegionPointX (parameter name:`pointX`)
-30. TouchableRegionPointY (parameter name:`pointY`)
-31. ColorMode (parameter name:`colorMode`)
-32. WindowInfoFlags (parameter name:`flags`)
-33. WindowInfoTransformOrientation (parameter name:`transform`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`surfaceTag`| 0.`Tag::CREATE_SURFACE`, 1.`Tag::CREATE_WITH_SURFACE_PARENT`, 2.`Tag::CLEAR_LAYER_FRAME_STATS`, 3.`Tag::GET_LAYER_FRAME_STATS`, 4.`Tag::MIRROR_SURFACE`, 5.`Tag::LAST` |Value obtained from FuzzedDataProvider|
-|`mode`| 0.`gui::TouchOcclusionMode::BLOCK_UNTRUSTED`, 1.`gui::TouchOcclusionMode::USE_OPACITY`, 2.`gui::TouchOcclusionMode::ALLOW` |Value obtained from FuzzedDataProvider|
-|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider|
-|`colorMode`|0.`ui::ColorMode::NATIVE`, 1.`ui::ColorMode::STANDARD_BT601_625`, 2.`ui::ColorMode::STANDARD_BT601_625_UNADJUSTED`, 3.`ui::ColorMode::STANDARD_BT601_525`, 4.`ui::ColorMode::STANDARD_BT601_525_UNADJUSTED`, 5.`ui::ColorMode::STANDARD_BT709`, 6.`ui::ColorMode::DCI_P3`, 7.`ui::ColorMode::SRGB`, 8.`ui::ColorMode::ADOBE_RGB`, 9.`ui::ColorMode::DISPLAY_P3`, 10.`ui::ColorMode::BT2020`, 11.`ui::ColorMode::BT2100_PQ`, 12.`ui::ColorMode::BT2100_HLG`, 13.`ui::ColorMode::DISPLAY_BT2020` |Value obtained from FuzzedDataProvider|
-|`flags`|0 .`gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON`, 1.`gui::WindowInfo::Flag::DIM_BEHIND`, 2.`gui::WindowInfo::Flag::BLUR_BEHIND`, 3.`gui::WindowInfo::Flag::NOT_FOCUSABLE`, 4.`gui::WindowInfo::Flag::NOT_TOUCHABLE`, 5.`gui::WindowInfo::Flag::NOT_TOUCH_MODAL`, 6.`gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING`, 7.`gui::WindowInfo::Flag::KEEP_SCREEN_ON`, 8.`gui::WindowInfo::Flag::LAYOUT_IN_SCREEN`, 9.`gui::WindowInfo::Flag::LAYOUT_NO_LIMITS`, 10.`gui::WindowInfo::Flag::FULLSCREEN`, 11.`gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN`, 12.`gui::WindowInfo::Flag::DITHER`, 13.`gui::WindowInfo::Flag::SECURE`, 14.`gui::WindowInfo::Flag::SCALED`, 15.`gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES`, 16.`gui::WindowInfo::Flag::LAYOUT_INSET_DECOR`, 17.`gui::WindowInfo::Flag::ALT_FOCUSABLE_IM`, 18.`gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH`, 19.`gui::WindowInfo::Flag::SHOW_WHEN_LOCKED`, 20.`gui::WindowInfo::Flag::SHOW_WALLPAPER`, 21.`gui::WindowInfo::Flag::TURN_SCREEN_ON`, 22.`gui::WindowInfo::Flag::DISMISS_KEYGUARD`, 23.`gui::WindowInfo::Flag::SPLIT_TOUCH`, 24.`gui::WindowInfo::Flag::HARDWARE_ACCELERATED`, 25.`gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN`, 26.`gui::WindowInfo::Flag::TRANSLUCENT_STATUS`, 27.`gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION`, 28.`gui::WindowInfo::Flag::LOCAL_FOCUS_MODE`, 29.`gui::WindowInfo::Flag::SLIPPERY`, 30.`gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR`, 31.`gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS`, |Value obtained from FuzzedDataProvider|
-|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
-|`transform`| 0.`ui::Transform::ROT_0`, 1.`ui::Transform::FLIP_H`, 2.`ui::Transform::FLIP_V`, 3.`ui::Transform::ROT_90`, 4.`ui::Transform::ROT_180`, 5.`ui::Transform::ROT_270` |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_surfaceComposerClient_fuzzer
-```
-2. To run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_surfaceComposerClient_fuzzer/libgui_surfaceComposerClient_fuzzer
-```
-
-# <a name="libgui_parcelable_fuzzer"></a> Fuzzer for Libgui_Parcelable
-
-Libgui_Parcelable supports the following parameters:
-1. LayerMetadataKey (parameter name:`key`)
-2. Dataspace (parameter name:`mDataspace`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`key`| 0.`view::LayerMetadataKey::METADATA_OWNER_UID`, 1.`view::LayerMetadataKey::METADATA_WINDOW_TYPE`, 2.`view::LayerMetadataKey::METADATA_TASK_ID`, 3.`view::LayerMetadataKey::METADATA_MOUSE_CURSOR`, 4.`view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID`, 5.`view::LayerMetadataKey::METADATA_OWNER_PID`, 6.`view::LayerMetadataKey::METADATA_DEQUEUE_TIME`, 7.`view::LayerMetadataKey::METADATA_GAME_MODE`, |Value obtained from FuzzedDataProvider|
-|`mDataSpace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_fuzzer
-```
-2. Run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_fuzzer/libgui_fuzzer
-```
-
-# <a name="libgui_bufferQueue_fuzzer"></a> Fuzzer for BufferQueue
-
-BufferQueue supports the following parameters:
-1. SurfaceWidth (parameter name:`width`)
-2. SurfaceHeight (parameter name:`height`)
-3. TransactionStateFlags (parameter name:`flags`)
-4. TransformHint (parameter name:`outTransformHint`)
-5. SurfacePixelFormat (parameter name:`format`)
-6. LayerId (parameter name:`layerId`)
-7. BufferId (parameter name:`bufferId`)
-8. FrameNumber (parameter name:`frameNumber`)
-9. FrameRate (parameter name:`frameRate`)
-10. Compatability (parameter name:`compatability`)
-11. LatchTime (parameter name:`latchTime`)
-12. AcquireTime (parameter name:`acquireTime`)
-13. RefreshTime (parameter name:`refreshTime`)
-14. DequeueTime (parameter name:`dequeueTime`)
-15. Slot (parameter name:`slot`)
-16. MaxBuffers (parameter name:`maxBuffers`)
-17. GenerationNumber (parameter name:`generationNumber`)
-18. Api (parameter name:`api`)
-19. Usage (parameter name:`usage`)
-20. MaxFrameNumber (parameter name:`maxFrameNumber`)
-21. BufferCount (parameter name:`bufferCount`)
-22. MaxAcquredBufferCount (parameter name:`maxAcquredBufferCount`)
-23. Status (parameter name:`status`)
-24. ApiConnection (parameter name:`apiConnection`)
-25. Dataspace (parameter name:`dataspace`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`status`| 0.`OK`, 1.`NO_MEMORY`, 2.`NO_INIT`, 3.`BAD_VALUE`, 4.`DEAD_OBJECT`, 5.`INVALID_OPERATION`, 6.`TIMED_OUT`, 7.`WOULD_BLOCK`, 8.`UNKNOWN_ERROR`, 9.`ALREADY_EXISTS`, |Value obtained from FuzzedDataProvider|
-|`apiConnection`| 0.`BufferQueueCore::CURRENTLY_CONNECTED_API`, 1.`BufferQueueCore::NO_CONNECTED_API`, 2.`NATIVE_WINDOW_API_EGL`, 3.`NATIVE_WINDOW_API_CPU`, 4.`NATIVE_WINDOW_API_MEDIA`, 5.`NATIVE_WINDOW_API_CAMERA`, |Value obtained from FuzzedDataProvider|
-|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_bufferQueue_fuzzer
-```
-2. To run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_bufferQueue_fuzzer/libgui_bufferQueue_fuzzer
-```
-
-# <a name="libgui_consumer_fuzzer"></a> Fuzzer for Libgui_Consumer
-
-Libgui_Consumer supports the following parameters:
-1. GraphicWidth (parameter name:`graphicWidth`)
-2. GraphicHeight (parameter name:`graphicHeight`)
-4. TransformHint (parameter name:`outTransformHint`)
-5. GraphicPixelFormat (parameter name:`format`)
-6. Usage (parameter name:`usage`)
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_consumer_fuzzer
-```
-2. Run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_consumer_fuzzer/libgui_consumer_fuzzer
-```
-
-# <a name="libgui_displayEvent_fuzzer"></a> Fuzzer for LibGui_DisplayEvent
-
-LibGui_DisplayEvent supports the following parameters:
-1. DisplayEventType (parameter name:`type`)
-2. Events (parameter name:`events`)
-3. VsyncSource (parameter name:`vsyncSource`)
-4. EventRegistrationFlags (parameter name:`flags`)
-
-| Parameter| Valid Values| Configured Value|
-|------------- |-------------| ----- |
-|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider|
-|`flags`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride`, |Value obtained from FuzzedDataProvider|
-|`type`| 0.`DisplayEventReceiver::DISPLAY_EVENT_NULL`, 1.`DisplayEventReceiver::DISPLAY_EVENT_VSYNC`, 2.`DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG`, 3.`DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE`, 4.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE`, 5.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH`, |Value obtained from FuzzedDataProvider|
-|`events`| 0.`Looper::EVENT_INPUT`, 1.`Looper::EVENT_OUTPUT`, 2.`Looper::EVENT_ERROR`, 3.`Looper::EVENT_HANGUP`, 4.`Looper::EVENT_INVALID`, |Value obtained from FuzzedDataProvider|
-
-#### Steps to run
-1. Build the fuzzer
-```
- $ mm -j$(nproc) libgui_displayEvent_fuzzer
-```
-2. Run on device
-```
- $ adb sync data
- $ adb shell /data/fuzz/arm64/libgui_displayEvent_fuzzer/libgui_displayEvent_fuzzer
-```
diff --git a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
deleted file mode 100644
index 2e270b7..0000000
--- a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright 2022 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 <android-base/stringprintf.h>
-#include <gui/BufferQueueConsumer.h>
-#include <gui/BufferQueueCore.h>
-#include <gui/BufferQueueProducer.h>
-#include <gui/bufferqueue/2.0/types.h>
-#include <system/window.h>
-
-#include <libgui_fuzzer_utils.h>
-
-using namespace android;
-using namespace hardware::graphics::bufferqueue;
-using namespace V1_0::utils;
-using namespace V2_0::utils;
-
-constexpr int32_t kMaxBytes = 256;
-
-constexpr int32_t kError[] = {
- OK, NO_MEMORY, NO_INIT, BAD_VALUE, DEAD_OBJECT, INVALID_OPERATION,
- TIMED_OUT, WOULD_BLOCK, UNKNOWN_ERROR, ALREADY_EXISTS,
-};
-
-constexpr int32_t kAPIConnection[] = {
- BufferQueueCore::CURRENTLY_CONNECTED_API,
- BufferQueueCore::NO_CONNECTED_API,
- NATIVE_WINDOW_API_EGL,
- NATIVE_WINDOW_API_CPU,
- NATIVE_WINDOW_API_MEDIA,
- NATIVE_WINDOW_API_CAMERA,
-};
-
-class BufferQueueFuzzer {
-public:
- BufferQueueFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- void invokeTypes();
- void invokeH2BGraphicBufferV1();
- void invokeH2BGraphicBufferV2();
- void invokeBufferQueueConsumer();
- void invokeBufferQueueProducer();
- void invokeBlastBufferQueue();
- void invokeQuery(sp<BufferQueueProducer>);
- void invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer>);
- void invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer>);
- void invokeAcquireBuffer(sp<BufferQueueConsumer>);
- void invokeOccupancyTracker(sp<BufferQueueConsumer>);
- sp<SurfaceControl> makeSurfaceControl();
- sp<BLASTBufferQueue> makeBLASTBufferQueue(sp<SurfaceControl>);
-
- FuzzedDataProvider mFdp;
-};
-
-class ManageResourceHandle {
-public:
- ManageResourceHandle(FuzzedDataProvider* fdp) {
- mNativeHandle = native_handle_create(0 /*numFds*/, 1 /*numInts*/);
- mShouldOwn = fdp->ConsumeBool();
- mStream = NativeHandle::create(mNativeHandle, mShouldOwn);
- }
- ~ManageResourceHandle() {
- if (!mShouldOwn) {
- native_handle_close(mNativeHandle);
- native_handle_delete(mNativeHandle);
- }
- }
- sp<NativeHandle> getStream() { return mStream; }
-
-private:
- bool mShouldOwn;
- sp<NativeHandle> mStream;
- native_handle_t* mNativeHandle;
-};
-
-sp<SurfaceControl> BufferQueueFuzzer::makeSurfaceControl() {
- sp<IBinder> handle;
- const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
- sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
- sp<BnGraphicBufferProducer> producer;
- uint32_t layerId = mFdp.ConsumeIntegral<uint32_t>();
- std::string layerName = base::StringPrintf("#%d", layerId);
- return sp<SurfaceControl>::make(client, handle, layerId, layerName,
- mFdp.ConsumeIntegral<int32_t>(),
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>(),
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>());
-}
-
-sp<BLASTBufferQueue> BufferQueueFuzzer::makeBLASTBufferQueue(sp<SurfaceControl> surface) {
- return sp<BLASTBufferQueue>::make(mFdp.ConsumeRandomLengthString(kMaxBytes), surface,
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>());
-}
-
-void BufferQueueFuzzer::invokeBlastBufferQueue() {
- sp<SurfaceControl> surface = makeSurfaceControl();
- sp<BLASTBufferQueue> queue = makeBLASTBufferQueue(surface);
-
- BufferItem item;
- queue->onFrameAvailable(item);
- queue->onFrameReplaced(item);
- uint64_t bufferId = mFdp.ConsumeIntegral<uint64_t>();
- queue->onFrameDequeued(bufferId);
- queue->onFrameCancelled(bufferId);
-
- SurfaceComposerClient::Transaction next;
- uint64_t frameNumber = mFdp.ConsumeIntegral<uint64_t>();
- queue->mergeWithNextTransaction(&next, frameNumber);
- queue->applyPendingTransactions(frameNumber);
-
- queue->update(surface, mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>());
- queue->setFrameRate(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeIntegral<int8_t>(),
- mFdp.ConsumeBool() /*shouldBeSeamless*/);
- FrameTimelineInfo info;
- queue->setFrameTimelineInfo(mFdp.ConsumeIntegral<uint64_t>(), info);
-
- ManageResourceHandle handle(&mFdp);
- queue->setSidebandStream(handle.getStream());
-
- queue->getLastTransformHint();
- queue->getLastAcquiredFrameNum();
-
- CompositorTiming compTiming;
- sp<Fence> previousFence = new Fence(memfd_create("pfd", MFD_ALLOW_SEALING));
- sp<Fence> gpuFence = new Fence(memfd_create("gfd", MFD_ALLOW_SEALING));
- FrameEventHistoryStats frameStats(frameNumber, mFdp.ConsumeIntegral<uint64_t>(), gpuFence,
- compTiming, mFdp.ConsumeIntegral<int64_t>(),
- mFdp.ConsumeIntegral<int64_t>());
- std::vector<SurfaceControlStats> stats;
- sp<Fence> presentFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
- SurfaceControlStats controlStats(surface, mFdp.ConsumeIntegral<int64_t>(),
- mFdp.ConsumeIntegral<int64_t>(), presentFence, previousFence,
- mFdp.ConsumeIntegral<uint32_t>(), frameStats,
- mFdp.ConsumeIntegral<uint32_t>());
- stats.push_back(controlStats);
-}
-
-void BufferQueueFuzzer::invokeQuery(sp<BufferQueueProducer> producer) {
- int32_t value;
- producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
-}
-
-void BufferQueueFuzzer::invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer> producer) {
- int32_t value;
- producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
-}
-
-void BufferQueueFuzzer::invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer> producer) {
- int32_t value;
- producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
-}
-
-void BufferQueueFuzzer::invokeBufferQueueProducer() {
- sp<BufferQueueCore> core(new BufferQueueCore());
- sp<BufferQueueProducer> producer(new BufferQueueProducer(core));
- const sp<android::IProducerListener> listener;
- android::IGraphicBufferProducer::QueueBufferOutput output;
- uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
- producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
-
- sp<GraphicBuffer> buffer;
- int32_t slot = mFdp.ConsumeIntegral<int32_t>();
- uint32_t maxBuffers = mFdp.ConsumeIntegral<uint32_t>();
- producer->requestBuffer(slot, &buffer);
- producer->setMaxDequeuedBufferCount(maxBuffers);
- producer->setAsyncMode(mFdp.ConsumeBool() /*async*/);
-
- android::IGraphicBufferProducer::QueueBufferInput input;
- producer->attachBuffer(&slot, buffer);
- producer->queueBuffer(slot, input, &output);
-
- int32_t format = mFdp.ConsumeIntegral<int32_t>();
- uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
- uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
- uint64_t outBufferAge;
- FrameEventHistoryDelta outTimestamps;
- sp<android::Fence> fence;
- producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
- &outTimestamps);
- producer->detachBuffer(slot);
- producer->detachNextBuffer(&buffer, &fence);
- producer->cancelBuffer(slot, fence);
-
- invokeQuery(producer);
-
- ManageResourceHandle handle(&mFdp);
- producer->setSidebandStream(handle.getStream());
-
- producer->allocateBuffers(width, height, format, usage);
- producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
- producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
- producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
- producer->setLegacyBufferDrop(mFdp.ConsumeBool() /*drop*/);
- producer->setAutoPrerotation(mFdp.ConsumeBool() /*autoPrerotation*/);
-
- producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
- producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
- producer->disconnect(api);
-}
-
-void BufferQueueFuzzer::invokeAcquireBuffer(sp<BufferQueueConsumer> consumer) {
- BufferItem item;
- consumer->acquireBuffer(&item, mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint64_t>());
-}
-
-void BufferQueueFuzzer::invokeOccupancyTracker(sp<BufferQueueConsumer> consumer) {
- String8 outResult;
- String8 prefix((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
- consumer->dumpState(prefix, &outResult);
-
- std::vector<OccupancyTracker::Segment> outHistory;
- consumer->getOccupancyHistory(mFdp.ConsumeBool() /*forceFlush*/, &outHistory);
-}
-
-void BufferQueueFuzzer::invokeBufferQueueConsumer() {
- sp<BufferQueueCore> core(new BufferQueueCore());
- sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
- sp<android::IConsumerListener> listener;
- consumer->consumerConnect(listener, mFdp.ConsumeBool() /*controlledByApp*/);
- invokeAcquireBuffer(consumer);
-
- int32_t slot = mFdp.ConsumeIntegral<int32_t>();
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint64_t>());
- consumer->attachBuffer(&slot, buffer);
- consumer->detachBuffer(slot);
-
- consumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>());
- consumer->setMaxBufferCount(mFdp.ConsumeIntegral<int32_t>());
- consumer->setMaxAcquiredBufferCount(mFdp.ConsumeIntegral<int32_t>());
-
- String8 name((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
- consumer->setConsumerName(name);
- consumer->setDefaultBufferFormat(mFdp.ConsumeIntegral<int32_t>());
- android_dataspace dataspace =
- static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces));
- consumer->setDefaultBufferDataSpace(dataspace);
-
- consumer->setTransformHint(mFdp.ConsumeIntegral<uint32_t>());
- consumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>());
- consumer->setConsumerIsProtected(mFdp.ConsumeBool() /*isProtected*/);
- invokeOccupancyTracker(consumer);
-
- sp<Fence> releaseFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
- consumer->releaseBuffer(mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint64_t>(),
- EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
- consumer->consumerDisconnect();
-}
-
-void BufferQueueFuzzer::invokeTypes() {
- HStatus hStatus;
- int32_t status = mFdp.PickValueInArray(kError);
- bool bufferNeedsReallocation = mFdp.ConsumeBool();
- bool releaseAllBuffers = mFdp.ConsumeBool();
- b2h(status, &hStatus, &bufferNeedsReallocation, &releaseAllBuffers);
- h2b(hStatus, &status);
-
- HConnectionType type;
- int32_t apiConnection = mFdp.PickValueInArray(kAPIConnection);
- b2h(apiConnection, &type);
- h2b(type, &apiConnection);
-}
-
-void BufferQueueFuzzer::invokeH2BGraphicBufferV1() {
- sp<V1_0::utils::H2BGraphicBufferProducer> producer(
- new V1_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV1()));
- const sp<android::IProducerListener> listener;
- android::IGraphicBufferProducer::QueueBufferOutput output;
- uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
- producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
-
- sp<GraphicBuffer> buffer;
- int32_t slot = mFdp.ConsumeIntegral<int32_t>();
- producer->requestBuffer(slot, &buffer);
- producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<int32_t>());
- producer->setAsyncMode(mFdp.ConsumeBool());
-
- android::IGraphicBufferProducer::QueueBufferInput input;
- input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING));
- producer->attachBuffer(&slot, buffer);
- producer->queueBuffer(slot, input, &output);
-
- int32_t format = mFdp.ConsumeIntegral<int32_t>();
- uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
- uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
- uint64_t outBufferAge;
- FrameEventHistoryDelta outTimestamps;
- sp<android::Fence> fence;
- producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
- &outTimestamps);
- producer->detachBuffer(slot);
- producer->cancelBuffer(slot, fence);
-
- invokeQuery(producer);
-
- ManageResourceHandle handle(&mFdp);
- producer->setSidebandStream(handle.getStream());
-
- producer->allocateBuffers(width, height, format, usage);
- producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
- producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
- producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
-
- producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
- producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
- producer->disconnect(api);
-}
-
-void BufferQueueFuzzer::invokeH2BGraphicBufferV2() {
- sp<V2_0::utils::H2BGraphicBufferProducer> producer(
- new V2_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV2()));
- const sp<android::IProducerListener> listener;
- android::IGraphicBufferProducer::QueueBufferOutput output;
- uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
- producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
-
- sp<GraphicBuffer> buffer;
- int32_t slot = mFdp.ConsumeIntegral<int32_t>();
- producer->requestBuffer(slot, &buffer);
- producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<uint32_t>());
- producer->setAsyncMode(mFdp.ConsumeBool());
-
- android::IGraphicBufferProducer::QueueBufferInput input;
- input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING));
- producer->attachBuffer(&slot, buffer);
- producer->queueBuffer(slot, input, &output);
-
- int32_t format = mFdp.ConsumeIntegral<int32_t>();
- uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
- uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
- uint64_t outBufferAge;
- FrameEventHistoryDelta outTimestamps;
- sp<android::Fence> fence;
- producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
- &outTimestamps);
- producer->detachBuffer(slot);
- producer->cancelBuffer(slot, fence);
-
- invokeQuery(producer);
-
- ManageResourceHandle handle(&mFdp);
- producer->setSidebandStream(handle.getStream());
-
- producer->allocateBuffers(width, height, format, usage);
- producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
- producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
- producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
-
- producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
- producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
- producer->disconnect(api);
-}
-
-void BufferQueueFuzzer::process() {
- invokeBlastBufferQueue();
- invokeH2BGraphicBufferV1();
- invokeH2BGraphicBufferV2();
- invokeTypes();
- invokeBufferQueueConsumer();
- invokeBufferQueueProducer();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- BufferQueueFuzzer bufferQueueFuzzer(data, size);
- bufferQueueFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp b/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp
deleted file mode 100644
index 24a046d..0000000
--- a/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2022 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 <gui/BufferQueueConsumer.h>
-#include <gui/BufferQueueCore.h>
-#include <gui/BufferQueueProducer.h>
-#include <gui/GLConsumer.h>
-#include <libgui_fuzzer_utils.h>
-
-using namespace android;
-
-constexpr int32_t kMinBuffer = 0;
-constexpr int32_t kMaxBuffer = 100000;
-
-class ConsumerFuzzer {
-public:
- ConsumerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- FuzzedDataProvider mFdp;
-};
-
-void ConsumerFuzzer::process() {
- sp<BufferQueueCore> core(new BufferQueueCore());
- sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
-
- uint64_t maxBuffers = mFdp.ConsumeIntegralInRange<uint64_t>(kMinBuffer, kMaxBuffer);
- sp<CpuConsumer> cpu(
- new CpuConsumer(consumer, maxBuffers, mFdp.ConsumeBool() /*controlledByApp*/));
- CpuConsumer::LockedBuffer lockBuffer;
- cpu->lockNextBuffer(&lockBuffer);
- cpu->unlockBuffer(lockBuffer);
- cpu->abandon();
-
- uint32_t tex = mFdp.ConsumeIntegral<uint32_t>();
- sp<GLConsumer> glComsumer(new GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL,
- mFdp.ConsumeBool() /*useFenceSync*/,
- mFdp.ConsumeBool() /*isControlledByApp*/));
- sp<Fence> releaseFence = new Fence(memfd_create("rfd", MFD_ALLOW_SEALING));
- glComsumer->setReleaseFence(releaseFence);
- glComsumer->updateTexImage();
- glComsumer->releaseTexImage();
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint64_t>());
- float mtx[16];
- glComsumer->getTransformMatrix(mtx);
- glComsumer->computeTransformMatrix(mtx, buffer, getRect(&mFdp),
- mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeBool() /*filtering*/);
- glComsumer->scaleDownCrop(getRect(&mFdp), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>());
-
- glComsumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>());
- glComsumer->setFilteringEnabled(mFdp.ConsumeBool() /*enabled*/);
-
- glComsumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>());
- glComsumer->attachToContext(tex);
- glComsumer->abandon();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- ConsumerFuzzer consumerFuzzer(data, size);
- consumerFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
deleted file mode 100644
index 0d2a52b..0000000
--- a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2022 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 <android/gui/ISurfaceComposer.h>
-
-#include <libgui_fuzzer_utils.h>
-
-using namespace android;
-
-constexpr gui::ISurfaceComposer::VsyncSource kVsyncSource[] = {
- gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
- gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger,
-};
-
-constexpr gui::ISurfaceComposer::EventRegistration kEventRegistration[] = {
- gui::ISurfaceComposer::EventRegistration::modeChanged,
- gui::ISurfaceComposer::EventRegistration::frameRateOverride,
-};
-
-constexpr uint32_t kDisplayEvent[] = {
- DisplayEventReceiver::DISPLAY_EVENT_NULL,
- DisplayEventReceiver::DISPLAY_EVENT_VSYNC,
- DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
- DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE,
- DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
- DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
-};
-
-constexpr int32_t kEvents[] = {
- Looper::EVENT_INPUT, Looper::EVENT_OUTPUT, Looper::EVENT_ERROR,
- Looper::EVENT_HANGUP, Looper::EVENT_INVALID,
-};
-
-DisplayEventReceiver::Event buildDisplayEvent(FuzzedDataProvider* fdp, uint32_t type,
- DisplayEventReceiver::Event event) {
- switch (type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: {
- event.vsync.count = fdp->ConsumeIntegral<uint32_t>();
- event.vsync.vsyncData.frameInterval = fdp->ConsumeIntegral<uint64_t>();
- event.vsync.vsyncData.preferredFrameTimelineIndex = fdp->ConsumeIntegral<uint32_t>();
- for (size_t idx = 0; idx < gui::VsyncEventData::kFrameTimelinesCapacity; ++idx) {
- event.vsync.vsyncData.frameTimelines[idx].vsyncId = fdp->ConsumeIntegral<int64_t>();
- event.vsync.vsyncData.frameTimelines[idx].deadlineTimestamp =
- fdp->ConsumeIntegral<uint64_t>();
- event.vsync.vsyncData.frameTimelines[idx].expectedPresentationTime =
- fdp->ConsumeIntegral<uint64_t>();
- }
- break;
-
- }
- case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: {
- event.hotplug =
- DisplayEventReceiver::Event::Hotplug{fdp->ConsumeBool() /*connected*/,
- fdp->ConsumeIntegral<
- int32_t>() /*connectionError*/};
- break;
- }
- case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
- event.modeChange =
- DisplayEventReceiver::Event::ModeChange{fdp->ConsumeIntegral<int32_t>(),
- fdp->ConsumeIntegral<int64_t>()};
- break;
- }
- case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
- case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH: {
- event.frameRateOverride =
- DisplayEventReceiver::Event::FrameRateOverride{fdp->ConsumeIntegral<uint32_t>(),
- fdp->ConsumeFloatingPoint<
- float>()};
- break;
- }
- }
- return event;
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider fdp(data, size);
- sp<Looper> looper;
- sp<FakeDisplayEventDispatcher> dispatcher(
- new FakeDisplayEventDispatcher(looper, fdp.PickValueInArray(kVsyncSource),
- fdp.PickValueInArray(kEventRegistration)));
-
- dispatcher->initialize();
- DisplayEventReceiver::Event event;
- uint32_t type = fdp.PickValueInArray(kDisplayEvent);
- PhysicalDisplayId displayId;
- event.header =
- DisplayEventReceiver::Event::Header{type, displayId, fdp.ConsumeIntegral<int64_t>()};
- event = buildDisplayEvent(&fdp, type, event);
-
- dispatcher->injectEvent(event);
- dispatcher->handleEvent(0, fdp.PickValueInArray(kEvents), nullptr);
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
deleted file mode 100644
index 2bdbd43..0000000
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright 2021 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 <android/gui/BnRegionSamplingListener.h>
-#include <android/gui/BnSurfaceComposer.h>
-#include <android/gui/BnSurfaceComposerClient.h>
-#include <android/gui/IDisplayEventConnection.h>
-#include <android/gui/ISurfaceComposerClient.h>
-#include <fuzzer/FuzzedDataProvider.h>
-#include <gmock/gmock.h>
-#include <gui/BLASTBufferQueue.h>
-#include <gui/DisplayEventDispatcher.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/LayerState.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
-#include <ui/fuzzer/FuzzableDataspaces.h>
-
-namespace android {
-
-constexpr uint32_t kOrientation[] = {
- ui::Transform::ROT_0, ui::Transform::FLIP_H, ui::Transform::FLIP_V,
- ui::Transform::ROT_90, ui::Transform::ROT_180, ui::Transform::ROT_270,
-};
-
-Rect getRect(FuzzedDataProvider* fdp) {
- const int32_t left = fdp->ConsumeIntegral<int32_t>();
- const int32_t top = fdp->ConsumeIntegral<int32_t>();
- const int32_t right = fdp->ConsumeIntegral<int32_t>();
- const int32_t bottom = fdp->ConsumeIntegral<int32_t>();
- return Rect(left, top, right, bottom);
-}
-
-gui::DisplayBrightness getBrightness(FuzzedDataProvider* fdp) {
- static constexpr float kMinBrightness = 0;
- static constexpr float kMaxBrightness = 1;
- gui::DisplayBrightness brightness;
- brightness.sdrWhitePoint =
- fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
- brightness.sdrWhitePointNits =
- fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
- brightness.displayBrightness =
- fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
- brightness.displayBrightnessNits =
- fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
- return brightness;
-}
-
-class FakeBnSurfaceComposer : public gui::BnSurfaceComposer {
-public:
- MOCK_METHOD(binder::Status, bootFinished, (), (override));
- MOCK_METHOD(binder::Status, createDisplayEventConnection,
- (gui::ISurfaceComposer::VsyncSource, gui::ISurfaceComposer::EventRegistration,
- const sp<IBinder>& /*layerHandle*/, sp<gui::IDisplayEventConnection>*),
- (override));
- MOCK_METHOD(binder::Status, createConnection, (sp<gui::ISurfaceComposerClient>*), (override));
- MOCK_METHOD(binder::Status, createDisplay, (const std::string&, bool, float, sp<IBinder>*),
- (override));
- MOCK_METHOD(binder::Status, destroyDisplay, (const sp<IBinder>&), (override));
- MOCK_METHOD(binder::Status, getPhysicalDisplayIds, (std::vector<int64_t>*), (override));
- MOCK_METHOD(binder::Status, getPhysicalDisplayToken, (int64_t, sp<IBinder>*), (override));
- MOCK_METHOD(binder::Status, setPowerMode, (const sp<IBinder>&, int), (override));
- MOCK_METHOD(binder::Status, getSupportedFrameTimestamps, (std::vector<FrameEvent>*),
- (override));
- MOCK_METHOD(binder::Status, getDisplayStats, (const sp<IBinder>&, gui::DisplayStatInfo*),
- (override));
- MOCK_METHOD(binder::Status, getDisplayState, (const sp<IBinder>&, gui::DisplayState*),
- (override));
- MOCK_METHOD(binder::Status, getStaticDisplayInfo, (int64_t, gui::StaticDisplayInfo*),
- (override));
- MOCK_METHOD(binder::Status, getDynamicDisplayInfoFromId, (int64_t, gui::DynamicDisplayInfo*),
- (override));
- MOCK_METHOD(binder::Status, getDynamicDisplayInfoFromToken,
- (const sp<IBinder>&, gui::DynamicDisplayInfo*), (override));
- MOCK_METHOD(binder::Status, getDisplayNativePrimaries,
- (const sp<IBinder>&, gui::DisplayPrimaries*), (override));
- MOCK_METHOD(binder::Status, setActiveColorMode, (const sp<IBinder>&, int), (override));
- MOCK_METHOD(binder::Status, setBootDisplayMode, (const sp<IBinder>&, int), (override));
- MOCK_METHOD(binder::Status, clearBootDisplayMode, (const sp<IBinder>&), (override));
- MOCK_METHOD(binder::Status, getBootDisplayModeSupport, (bool*), (override));
- MOCK_METHOD(binder::Status, getHdrConversionCapabilities,
- (std::vector<gui::HdrConversionCapability>*), (override));
- MOCK_METHOD(binder::Status, setHdrConversionStrategy,
- (const gui::HdrConversionStrategy&, int32_t*), (override));
- MOCK_METHOD(binder::Status, getHdrOutputConversionSupport, (bool*), (override));
- MOCK_METHOD(binder::Status, setAutoLowLatencyMode, (const sp<IBinder>&, bool), (override));
- MOCK_METHOD(binder::Status, setGameContentType, (const sp<IBinder>&, bool), (override));
- MOCK_METHOD(binder::Status, captureDisplay,
- (const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&), (override));
- MOCK_METHOD(binder::Status, captureDisplayById,
- (int64_t, const gui::CaptureArgs&, const sp<IScreenCaptureListener>&), (override));
- MOCK_METHOD(binder::Status, captureLayers,
- (const LayerCaptureArgs&, const sp<IScreenCaptureListener>&), (override));
- MOCK_METHOD(binder::Status, captureLayersSync,
- (const LayerCaptureArgs&, gui::ScreenCaptureResults*), (override));
- MOCK_METHOD(binder::Status, clearAnimationFrameStats, (), (override));
- MOCK_METHOD(binder::Status, getAnimationFrameStats, (gui::FrameStats*), (override));
- MOCK_METHOD(binder::Status, overrideHdrTypes, (const sp<IBinder>&, const std::vector<int32_t>&),
- (override));
- MOCK_METHOD(binder::Status, onPullAtom, (int32_t, gui::PullAtomData*), (override));
- MOCK_METHOD(binder::Status, getLayerDebugInfo, (std::vector<gui::LayerDebugInfo>*), (override));
- MOCK_METHOD(binder::Status, getCompositionPreference, (gui::CompositionPreference*),
- (override));
- MOCK_METHOD(binder::Status, getDisplayedContentSamplingAttributes,
- (const sp<IBinder>&, gui::ContentSamplingAttributes*), (override));
- MOCK_METHOD(binder::Status, setDisplayContentSamplingEnabled,
- (const sp<IBinder>&, bool, int8_t, int64_t), (override));
- MOCK_METHOD(binder::Status, getDisplayedContentSample,
- (const sp<IBinder>&, int64_t, int64_t, gui::DisplayedFrameStats*), (override));
- MOCK_METHOD(binder::Status, getProtectedContentSupport, (bool*), (override));
- MOCK_METHOD(binder::Status, isWideColorDisplay, (const sp<IBinder>&, bool*), (override));
- MOCK_METHOD(binder::Status, addRegionSamplingListener,
- (const gui::ARect&, const sp<IBinder>&, const sp<gui::IRegionSamplingListener>&),
- (override));
- MOCK_METHOD(binder::Status, removeRegionSamplingListener,
- (const sp<gui::IRegionSamplingListener>&), (override));
- MOCK_METHOD(binder::Status, addFpsListener, (int32_t, const sp<gui::IFpsListener>&),
- (override));
- MOCK_METHOD(binder::Status, removeFpsListener, (const sp<gui::IFpsListener>&), (override));
- MOCK_METHOD(binder::Status, addTunnelModeEnabledListener,
- (const sp<gui::ITunnelModeEnabledListener>&), (override));
- MOCK_METHOD(binder::Status, removeTunnelModeEnabledListener,
- (const sp<gui::ITunnelModeEnabledListener>&), (override));
- MOCK_METHOD(binder::Status, setDesiredDisplayModeSpecs,
- (const sp<IBinder>&, const gui::DisplayModeSpecs&), (override));
- MOCK_METHOD(binder::Status, getDesiredDisplayModeSpecs,
- (const sp<IBinder>&, gui::DisplayModeSpecs*), (override));
- MOCK_METHOD(binder::Status, getDisplayBrightnessSupport, (const sp<IBinder>&, bool*),
- (override));
- MOCK_METHOD(binder::Status, setDisplayBrightness,
- (const sp<IBinder>&, const gui::DisplayBrightness&), (override));
- MOCK_METHOD(binder::Status, addHdrLayerInfoListener,
- (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override));
- MOCK_METHOD(binder::Status, removeHdrLayerInfoListener,
- (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override));
- MOCK_METHOD(binder::Status, notifyPowerBoost, (int), (override));
- MOCK_METHOD(binder::Status, setGlobalShadowSettings,
- (const gui::Color&, const gui::Color&, float, float, float), (override));
- MOCK_METHOD(binder::Status, getDisplayDecorationSupport,
- (const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override));
- MOCK_METHOD(binder::Status, setGameModeFrameRateOverride, (int32_t, float), (override));
- MOCK_METHOD(binder::Status, setGameDefaultFrameRateOverride, (int32_t, float), (override));
- MOCK_METHOD(binder::Status, enableRefreshRateOverlay, (bool), (override));
- MOCK_METHOD(binder::Status, setDebugFlash, (int), (override));
- MOCK_METHOD(binder::Status, scheduleComposite, (), (override));
- MOCK_METHOD(binder::Status, scheduleCommit, (), (override));
- MOCK_METHOD(binder::Status, forceClientComposition, (bool), (override));
- MOCK_METHOD(binder::Status, updateSmallAreaDetection,
- (const std::vector<int32_t>&, const std::vector<float>&), (override));
- MOCK_METHOD(binder::Status, setSmallAreaDetectionThreshold, (int32_t, float), (override));
- MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override));
- MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override));
- MOCK_METHOD(binder::Status, addWindowInfosListener,
- (const sp<gui::IWindowInfosListener>&, gui::WindowInfosListenerInfo*), (override));
- MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
- (override));
- MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override));
- MOCK_METHOD(binder::Status, getStalledTransactionInfo,
- (int32_t, std::optional<gui::StalledTransactionInfo>*), (override));
- MOCK_METHOD(binder::Status, getSchedulingPolicy, (gui::SchedulingPolicy*), (override));
-};
-
-class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient {
-public:
- MOCK_METHOD(binder::Status, createSurface,
- (const std::string& name, int32_t flags, const sp<IBinder>& parent,
- const gui::LayerMetadata& metadata, gui::CreateSurfaceResult* outResult),
- (override));
-
- MOCK_METHOD(binder::Status, clearLayerFrameStats, (const sp<IBinder>& handle), (override));
-
- MOCK_METHOD(binder::Status, getLayerFrameStats,
- (const sp<IBinder>& handle, gui::FrameStats* outStats), (override));
-
- MOCK_METHOD(binder::Status, mirrorSurface,
- (const sp<IBinder>& mirrorFromHandle, gui::CreateSurfaceResult* outResult),
- (override));
-
- MOCK_METHOD(binder::Status, mirrorDisplay,
- (int64_t displayId, gui::CreateSurfaceResult* outResult), (override));
-
- MOCK_METHOD(binder::Status, getSchedulingPolicy, (gui::SchedulingPolicy*), (override));
-};
-
-class FakeDisplayEventDispatcher : public DisplayEventDispatcher {
-public:
- FakeDisplayEventDispatcher(const sp<Looper>& looper,
- gui::ISurfaceComposer::VsyncSource vsyncSource,
- gui::ISurfaceComposer::EventRegistration eventRegistration)
- : DisplayEventDispatcher(looper, vsyncSource, eventRegistration){};
-
- MOCK_METHOD4(dispatchVsync, void(nsecs_t, PhysicalDisplayId, uint32_t, VsyncEventData));
- MOCK_METHOD3(dispatchHotplug, void(nsecs_t, PhysicalDisplayId, bool));
- MOCK_METHOD2(dispatchHotplugConnectionError, void(nsecs_t, int32_t));
- MOCK_METHOD4(dispatchModeChanged, void(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t));
- MOCK_METHOD2(dispatchNullEvent, void(nsecs_t, PhysicalDisplayId));
- MOCK_METHOD3(dispatchFrameRateOverrides,
- void(nsecs_t, PhysicalDisplayId, std::vector<FrameRateOverride>));
- MOCK_METHOD3(dispatchHdcpLevelsChanged, void(PhysicalDisplayId, int32_t, int32_t));
-};
-
-} // namespace android
-
-namespace android::hardware {
-
-namespace graphics::bufferqueue::V1_0::utils {
-
-class FakeGraphicBufferProducerV1 : public HGraphicBufferProducer {
-public:
- FakeGraphicBufferProducerV1() {
- ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return 0; });
- ON_CALL(*this, setAsyncMode).WillByDefault([]() { return 0; });
- ON_CALL(*this, detachBuffer).WillByDefault([]() { return 0; });
- ON_CALL(*this, cancelBuffer).WillByDefault([]() { return 0; });
- ON_CALL(*this, disconnect).WillByDefault([]() { return 0; });
- ON_CALL(*this, setSidebandStream).WillByDefault([]() { return 0; });
- ON_CALL(*this, allowAllocation).WillByDefault([]() { return 0; });
- ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return 0; });
- ON_CALL(*this, setSharedBufferMode).WillByDefault([]() { return 0; });
- ON_CALL(*this, setAutoRefresh).WillByDefault([]() { return 0; });
- ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return 0; });
- ON_CALL(*this, setLegacyBufferDrop).WillByDefault([]() { return 0; });
- };
- MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb));
- MOCK_METHOD1(setMaxDequeuedBufferCount, Return<int32_t>(int32_t));
- MOCK_METHOD1(setAsyncMode, Return<int32_t>(bool));
- MOCK_METHOD6(dequeueBuffer,
- Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t,
- bool, dequeueBuffer_cb));
- MOCK_METHOD1(detachBuffer, Return<int32_t>(int));
- MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb));
- MOCK_METHOD2(attachBuffer, Return<void>(const media::V1_0::AnwBuffer&, attachBuffer_cb));
- MOCK_METHOD3(
- queueBuffer,
- Return<void>(
- int,
- const graphics::bufferqueue::V1_0::IGraphicBufferProducer::QueueBufferInput&,
- queueBuffer_cb));
- MOCK_METHOD2(cancelBuffer, Return<int32_t>(int, const hidl_handle&));
- MOCK_METHOD2(query, Return<void>(int32_t, query_cb));
- MOCK_METHOD4(connect,
- Return<void>(const sp<graphics::bufferqueue::V1_0::IProducerListener>&, int32_t,
- bool, connect_cb));
- MOCK_METHOD2(disconnect,
- Return<int32_t>(
- int, graphics::bufferqueue::V1_0::IGraphicBufferProducer::DisconnectMode));
- MOCK_METHOD1(setSidebandStream, Return<int32_t>(const hidl_handle&));
- MOCK_METHOD4(allocateBuffers,
- Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t));
- MOCK_METHOD1(allowAllocation, Return<int32_t>(bool));
- MOCK_METHOD1(setGenerationNumber, Return<int32_t>(uint32_t));
- MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb));
- MOCK_METHOD1(setSharedBufferMode, Return<int32_t>(bool));
- MOCK_METHOD1(setAutoRefresh, Return<int32_t>(bool));
- MOCK_METHOD1(setDequeueTimeout, Return<int32_t>(nsecs_t));
- MOCK_METHOD1(setLegacyBufferDrop, Return<int32_t>(bool));
- MOCK_METHOD1(getLastQueuedBuffer, Return<void>(getLastQueuedBuffer_cb));
- MOCK_METHOD1(getFrameTimestamps, Return<void>(getFrameTimestamps_cb));
- MOCK_METHOD1(getUniqueId, Return<void>(getUniqueId_cb));
-};
-
-}; // namespace graphics::bufferqueue::V1_0::utils
-
-namespace graphics::bufferqueue::V2_0::utils {
-
-class FakeGraphicBufferProducerV2 : public HGraphicBufferProducer {
-public:
- FakeGraphicBufferProducerV2() {
- ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, setAsyncMode).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, detachBuffer).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, cancelBuffer).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, disconnect).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, allocateBuffers).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, allowAllocation).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return Status::OK; });
- ON_CALL(*this, getUniqueId).WillByDefault([]() { return 0; });
- };
- MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb));
- MOCK_METHOD1(setMaxDequeuedBufferCount, Return<graphics::bufferqueue::V2_0::Status>(int));
- MOCK_METHOD1(setAsyncMode, Return<graphics::bufferqueue::V2_0::Status>(bool));
- MOCK_METHOD2(
- dequeueBuffer,
- Return<void>(
- const graphics::bufferqueue::V2_0::IGraphicBufferProducer::DequeueBufferInput&,
- dequeueBuffer_cb));
- MOCK_METHOD1(detachBuffer, Return<graphics::bufferqueue::V2_0::Status>(int));
- MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb));
- MOCK_METHOD3(attachBuffer,
- Return<void>(const graphics::common::V1_2::HardwareBuffer&, uint32_t,
- attachBuffer_cb));
- MOCK_METHOD3(
- queueBuffer,
- Return<void>(
- int,
- const graphics::bufferqueue::V2_0::IGraphicBufferProducer::QueueBufferInput&,
- queueBuffer_cb));
- MOCK_METHOD2(cancelBuffer,
- Return<graphics::bufferqueue::V2_0::Status>(int, const hidl_handle&));
- MOCK_METHOD2(query, Return<void>(int32_t, query_cb));
- MOCK_METHOD4(connect,
- Return<void>(const sp<graphics::bufferqueue::V2_0::IProducerListener>&,
- graphics::bufferqueue::V2_0::ConnectionType, bool, connect_cb));
- MOCK_METHOD1(disconnect,
- Return<graphics::bufferqueue::V2_0::Status>(
- graphics::bufferqueue::V2_0::ConnectionType));
- MOCK_METHOD4(allocateBuffers,
- Return<graphics::bufferqueue::V2_0::Status>(uint32_t, uint32_t, uint32_t,
- uint64_t));
- MOCK_METHOD1(allowAllocation, Return<graphics::bufferqueue::V2_0::Status>(bool));
- MOCK_METHOD1(setGenerationNumber, Return<graphics::bufferqueue::V2_0::Status>(uint32_t));
- MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb));
- MOCK_METHOD1(setDequeueTimeout, Return<graphics::bufferqueue::V2_0::Status>(int64_t));
- MOCK_METHOD0(getUniqueId, Return<uint64_t>());
-};
-
-}; // namespace graphics::bufferqueue::V2_0::utils
-}; // namespace android::hardware
diff --git a/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp b/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp
deleted file mode 100644
index 9f0f6ca..0000000
--- a/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2022 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 <gui/BufferQueueConsumer.h>
-#include <gui/BufferQueueCore.h>
-#include <gui/BufferQueueProducer.h>
-#include <gui/LayerMetadata.h>
-#include <gui/OccupancyTracker.h>
-#include <gui/StreamSplitter.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceControl.h>
-#include <gui/view/Surface.h>
-#include <libgui_fuzzer_utils.h>
-#include "android/view/LayerMetadataKey.h"
-
-using namespace android;
-
-constexpr int32_t kMaxBytes = 256;
-constexpr int32_t kMatrixSize = 4;
-constexpr int32_t kLayerMetadataKeyCount = 8;
-
-constexpr uint32_t kMetadataKey[] = {
- (uint32_t)view::LayerMetadataKey::METADATA_OWNER_UID,
- (uint32_t)view::LayerMetadataKey::METADATA_WINDOW_TYPE,
- (uint32_t)view::LayerMetadataKey::METADATA_TASK_ID,
- (uint32_t)view::LayerMetadataKey::METADATA_MOUSE_CURSOR,
- (uint32_t)view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID,
- (uint32_t)view::LayerMetadataKey::METADATA_OWNER_PID,
- (uint32_t)view::LayerMetadataKey::METADATA_DEQUEUE_TIME,
- (uint32_t)view::LayerMetadataKey::METADATA_GAME_MODE,
-};
-
-class ParcelableFuzzer {
-public:
- ParcelableFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- void invokeStreamSplitter();
- void invokeOccupancyTracker();
- void invokeLayerDebugInfo();
- void invokeLayerMetadata();
- void invokeViewSurface();
-
- FuzzedDataProvider mFdp;
-};
-
-void ParcelableFuzzer::invokeViewSurface() {
- view::Surface surface;
- surface.name = String16((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
- Parcel parcel;
- surface.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- surface.readFromParcel(&parcel);
- bool nameAlreadyWritten = mFdp.ConsumeBool();
- surface.writeToParcel(&parcel, nameAlreadyWritten);
- parcel.setDataPosition(0);
- surface.readFromParcel(&parcel, mFdp.ConsumeBool());
-}
-
-void ParcelableFuzzer::invokeLayerMetadata() {
- std::unordered_map<uint32_t, std::vector<uint8_t>> map;
- for (size_t idx = 0; idx < kLayerMetadataKeyCount; ++idx) {
- std::vector<uint8_t> data;
- for (size_t idx1 = 0; idx1 < mFdp.ConsumeIntegral<uint32_t>(); ++idx1) {
- data.push_back(mFdp.ConsumeIntegral<uint8_t>());
- }
- map[kMetadataKey[idx]] = data;
- }
- LayerMetadata metadata(map);
- uint32_t key = mFdp.PickValueInArray(kMetadataKey);
- metadata.setInt32(key, mFdp.ConsumeIntegral<int32_t>());
- metadata.itemToString(key, (mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
-
- Parcel parcel;
- metadata.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- metadata.readFromParcel(&parcel);
-}
-
-void ParcelableFuzzer::invokeLayerDebugInfo() {
- gui::LayerDebugInfo info;
- info.mName = mFdp.ConsumeRandomLengthString(kMaxBytes);
- info.mParentName = mFdp.ConsumeRandomLengthString(kMaxBytes);
- info.mType = mFdp.ConsumeRandomLengthString(kMaxBytes);
- info.mLayerStack = mFdp.ConsumeIntegral<uint32_t>();
- info.mX = mFdp.ConsumeFloatingPoint<float>();
- info.mY = mFdp.ConsumeFloatingPoint<float>();
- info.mZ = mFdp.ConsumeIntegral<uint32_t>();
- info.mWidth = mFdp.ConsumeIntegral<int32_t>();
- info.mHeight = mFdp.ConsumeIntegral<int32_t>();
- info.mActiveBufferWidth = mFdp.ConsumeIntegral<int32_t>();
- info.mActiveBufferHeight = mFdp.ConsumeIntegral<int32_t>();
- info.mActiveBufferStride = mFdp.ConsumeIntegral<int32_t>();
- info.mActiveBufferFormat = mFdp.ConsumeIntegral<int32_t>();
- info.mNumQueuedFrames = mFdp.ConsumeIntegral<int32_t>();
-
- info.mFlags = mFdp.ConsumeIntegral<uint32_t>();
- info.mPixelFormat = mFdp.ConsumeIntegral<int32_t>();
- info.mTransparentRegion = Region(getRect(&mFdp));
- info.mVisibleRegion = Region(getRect(&mFdp));
- info.mSurfaceDamageRegion = Region(getRect(&mFdp));
- info.mCrop = getRect(&mFdp);
- info.mDataSpace = static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces));
- info.mColor = half4(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
- mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>());
- for (size_t idx = 0; idx < kMatrixSize; ++idx) {
- info.mMatrix[idx / 2][idx % 2] = mFdp.ConsumeFloatingPoint<float>();
- }
- info.mIsOpaque = mFdp.ConsumeBool();
- info.mContentDirty = mFdp.ConsumeBool();
- info.mStretchEffect.width = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.height = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.vectorX = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.vectorY = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.maxAmountX = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.maxAmountY = mFdp.ConsumeFloatingPoint<float>();
- info.mStretchEffect.mappedChildBounds =
- FloatRect(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
- mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>());
-
- Parcel parcel;
- info.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- info.readFromParcel(&parcel);
-}
-
-void ParcelableFuzzer::invokeOccupancyTracker() {
- nsecs_t totalTime = mFdp.ConsumeIntegral<uint32_t>();
- size_t numFrames = mFdp.ConsumeIntegral<size_t>();
- float occupancyAverage = mFdp.ConsumeFloatingPoint<float>();
- OccupancyTracker::Segment segment(totalTime, numFrames, occupancyAverage,
- mFdp.ConsumeBool() /*usedThirdBuffer*/);
- Parcel parcel;
- segment.writeToParcel(&parcel);
- parcel.setDataPosition(0);
- segment.readFromParcel(&parcel);
-}
-
-void ParcelableFuzzer::invokeStreamSplitter() {
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- sp<StreamSplitter> splitter;
- StreamSplitter::createSplitter(consumer, &splitter);
- splitter->addOutput(producer);
- std::string name = mFdp.ConsumeRandomLengthString(kMaxBytes);
- splitter->setName(String8(name.c_str()));
-}
-
-void ParcelableFuzzer::process() {
- invokeStreamSplitter();
- invokeOccupancyTracker();
- invokeLayerDebugInfo();
- invokeLayerMetadata();
- invokeViewSurface();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- ParcelableFuzzer libGuiFuzzer(data, size);
- libGuiFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
deleted file mode 100644
index 4daa3be..0000000
--- a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright 2022 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 <aidl/android/hardware/power/Boost.h>
-#include <fuzzbinder/libbinder_driver.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-#include <libgui_fuzzer_utils.h>
-#include "android-base/stringprintf.h"
-
-using namespace android;
-
-constexpr int32_t kRandomStringMaxBytes = 256;
-
-constexpr ui::ColorMode kColormodes[] = {ui::ColorMode::NATIVE,
- ui::ColorMode::STANDARD_BT601_625,
- ui::ColorMode::STANDARD_BT601_625_UNADJUSTED,
- ui::ColorMode::STANDARD_BT601_525,
- ui::ColorMode::STANDARD_BT601_525_UNADJUSTED,
- ui::ColorMode::STANDARD_BT709,
- ui::ColorMode::DCI_P3,
- ui::ColorMode::SRGB,
- ui::ColorMode::ADOBE_RGB,
- ui::ColorMode::DISPLAY_P3,
- ui::ColorMode::BT2020,
- ui::ColorMode::BT2100_PQ,
- ui::ColorMode::BT2100_HLG,
- ui::ColorMode::DISPLAY_BT2020};
-
-constexpr aidl::android::hardware::power::Boost kBoost[] = {
- aidl::android::hardware::power::Boost::INTERACTION,
- aidl::android::hardware::power::Boost::DISPLAY_UPDATE_IMMINENT,
- aidl::android::hardware::power::Boost::ML_ACC,
- aidl::android::hardware::power::Boost::AUDIO_LAUNCH,
- aidl::android::hardware::power::Boost::CAMERA_LAUNCH,
- aidl::android::hardware::power::Boost::CAMERA_SHOT,
-};
-
-constexpr gui::TouchOcclusionMode kMode[] = {
- gui::TouchOcclusionMode::BLOCK_UNTRUSTED,
- gui::TouchOcclusionMode::USE_OPACITY,
- gui::TouchOcclusionMode::ALLOW,
-};
-
-constexpr gui::WindowInfo::Flag kFlags[] = {
- gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON,
- gui::WindowInfo::Flag::DIM_BEHIND,
- gui::WindowInfo::Flag::BLUR_BEHIND,
- gui::WindowInfo::Flag::NOT_FOCUSABLE,
- gui::WindowInfo::Flag::NOT_TOUCHABLE,
- gui::WindowInfo::Flag::NOT_TOUCH_MODAL,
- gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING,
- gui::WindowInfo::Flag::KEEP_SCREEN_ON,
- gui::WindowInfo::Flag::LAYOUT_IN_SCREEN,
- gui::WindowInfo::Flag::LAYOUT_NO_LIMITS,
- gui::WindowInfo::Flag::FULLSCREEN,
- gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN,
- gui::WindowInfo::Flag::DITHER,
- gui::WindowInfo::Flag::SECURE,
- gui::WindowInfo::Flag::SCALED,
- gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES,
- gui::WindowInfo::Flag::LAYOUT_INSET_DECOR,
- gui::WindowInfo::Flag::ALT_FOCUSABLE_IM,
- gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH,
- gui::WindowInfo::Flag::SHOW_WHEN_LOCKED,
- gui::WindowInfo::Flag::SHOW_WALLPAPER,
- gui::WindowInfo::Flag::TURN_SCREEN_ON,
- gui::WindowInfo::Flag::DISMISS_KEYGUARD,
- gui::WindowInfo::Flag::SPLIT_TOUCH,
- gui::WindowInfo::Flag::HARDWARE_ACCELERATED,
- gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN,
- gui::WindowInfo::Flag::TRANSLUCENT_STATUS,
- gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION,
- gui::WindowInfo::Flag::LOCAL_FOCUS_MODE,
- gui::WindowInfo::Flag::SLIPPERY,
- gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR,
- gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS,
-};
-
-constexpr gui::WindowInfo::Type kType[] = {
- gui::WindowInfo::Type::UNKNOWN,
- gui::WindowInfo::Type::FIRST_APPLICATION_WINDOW,
- gui::WindowInfo::Type::BASE_APPLICATION,
- gui::WindowInfo::Type::APPLICATION,
- gui::WindowInfo::Type::APPLICATION_STARTING,
- gui::WindowInfo::Type::LAST_APPLICATION_WINDOW,
- gui::WindowInfo::Type::FIRST_SUB_WINDOW,
- gui::WindowInfo::Type::APPLICATION_PANEL,
- gui::WindowInfo::Type::APPLICATION_MEDIA,
- gui::WindowInfo::Type::APPLICATION_SUB_PANEL,
- gui::WindowInfo::Type::APPLICATION_ATTACHED_DIALOG,
- gui::WindowInfo::Type::APPLICATION_MEDIA_OVERLAY,
-};
-
-constexpr gui::WindowInfo::InputConfig kFeatures[] = {
- gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL,
- gui::WindowInfo::InputConfig::DISABLE_USER_ACTIVITY,
- gui::WindowInfo::InputConfig::DROP_INPUT,
- gui::WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED,
- gui::WindowInfo::InputConfig::SPY,
- gui::WindowInfo::InputConfig::INTERCEPTS_STYLUS,
-};
-
-class SurfaceComposerClientFuzzer {
-public:
- SurfaceComposerClientFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- void invokeSurfaceComposerClient();
- void invokeSurfaceComposerClientBinder();
- void invokeSurfaceComposerTransaction();
- void getWindowInfo(gui::WindowInfo*);
- sp<SurfaceControl> makeSurfaceControl();
- BlurRegion getBlurRegion();
- void fuzzOnPullAtom();
- gui::DisplayModeSpecs getDisplayModeSpecs();
-
- FuzzedDataProvider mFdp;
-};
-
-gui::DisplayModeSpecs SurfaceComposerClientFuzzer::getDisplayModeSpecs() {
- const auto getRefreshRateRange = [&] {
- gui::DisplayModeSpecs::RefreshRateRanges::RefreshRateRange range;
- range.min = mFdp.ConsumeFloatingPoint<float>();
- range.max = mFdp.ConsumeFloatingPoint<float>();
- return range;
- };
-
- const auto getRefreshRateRanges = [&] {
- gui::DisplayModeSpecs::RefreshRateRanges ranges;
- ranges.physical = getRefreshRateRange();
- ranges.render = getRefreshRateRange();
- return ranges;
- };
-
- String8 displayName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
- sp<IBinder> displayToken =
- SurfaceComposerClient::createDisplay(displayName, mFdp.ConsumeBool() /*secure*/);
- gui::DisplayModeSpecs specs;
- specs.defaultMode = mFdp.ConsumeIntegral<int32_t>();
- specs.allowGroupSwitching = mFdp.ConsumeBool();
- specs.primaryRanges = getRefreshRateRanges();
- specs.appRequestRanges = getRefreshRateRanges();
- return specs;
-}
-
-BlurRegion SurfaceComposerClientFuzzer::getBlurRegion() {
- int32_t left = mFdp.ConsumeIntegral<int32_t>();
- int32_t right = mFdp.ConsumeIntegral<int32_t>();
- int32_t top = mFdp.ConsumeIntegral<int32_t>();
- int32_t bottom = mFdp.ConsumeIntegral<int32_t>();
- uint32_t blurRadius = mFdp.ConsumeIntegral<uint32_t>();
- float alpha = mFdp.ConsumeFloatingPoint<float>();
- float cornerRadiusTL = mFdp.ConsumeFloatingPoint<float>();
- float cornerRadiusTR = mFdp.ConsumeFloatingPoint<float>();
- float cornerRadiusBL = mFdp.ConsumeFloatingPoint<float>();
- float cornerRadiusBR = mFdp.ConsumeFloatingPoint<float>();
- return BlurRegion{blurRadius, cornerRadiusTL, cornerRadiusTR, cornerRadiusBL,
- cornerRadiusBR, alpha, left, top,
- right, bottom};
-}
-
-void SurfaceComposerClientFuzzer::getWindowInfo(gui::WindowInfo* windowInfo) {
- windowInfo->id = mFdp.ConsumeIntegral<int32_t>();
- windowInfo->name = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
- windowInfo->layoutParamsFlags = mFdp.PickValueInArray(kFlags);
- windowInfo->layoutParamsType = mFdp.PickValueInArray(kType);
- windowInfo->frame = Rect(mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<int32_t>(),
- mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<int32_t>());
- windowInfo->surfaceInset = mFdp.ConsumeIntegral<int32_t>();
- windowInfo->alpha = mFdp.ConsumeFloatingPointInRange<float>(0, 1);
- ui::Transform transform(mFdp.PickValueInArray(kOrientation));
- windowInfo->transform = transform;
- windowInfo->touchableRegion = Region(getRect(&mFdp));
- windowInfo->replaceTouchableRegionWithCrop = mFdp.ConsumeBool();
- windowInfo->touchOcclusionMode = mFdp.PickValueInArray(kMode);
- windowInfo->ownerPid = gui::Pid{mFdp.ConsumeIntegral<pid_t>()};
- windowInfo->ownerUid = gui::Uid{mFdp.ConsumeIntegral<uid_t>()};
- windowInfo->packageName = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
- windowInfo->inputConfig = mFdp.PickValueInArray(kFeatures);
-}
-
-sp<SurfaceControl> SurfaceComposerClientFuzzer::makeSurfaceControl() {
- sp<IBinder> handle;
- const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
- sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
- sp<BnGraphicBufferProducer> producer;
- uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t transformHint = mFdp.ConsumeIntegral<uint32_t>();
- uint32_t flags = mFdp.ConsumeIntegral<uint32_t>();
- int32_t format = mFdp.ConsumeIntegral<int32_t>();
- int32_t layerId = mFdp.ConsumeIntegral<int32_t>();
- std::string layerName = base::StringPrintf("#%d", layerId);
- return new SurfaceControl(client, handle, layerId, layerName, width, height, format,
- transformHint, flags);
-}
-
-void SurfaceComposerClientFuzzer::invokeSurfaceComposerTransaction() {
- sp<SurfaceControl> surface = makeSurfaceControl();
-
- SurfaceComposerClient::Transaction transaction;
- int32_t layer = mFdp.ConsumeIntegral<int32_t>();
- transaction.setLayer(surface, layer);
-
- sp<SurfaceControl> relativeSurface = makeSurfaceControl();
- transaction.setRelativeLayer(surface, relativeSurface, layer);
-
- Region transparentRegion(getRect(&mFdp));
- transaction.setTransparentRegionHint(surface, transparentRegion);
- transaction.setAlpha(surface, mFdp.ConsumeFloatingPoint<float>());
-
- transaction.setCornerRadius(surface, mFdp.ConsumeFloatingPoint<float>());
- transaction.setBackgroundBlurRadius(surface, mFdp.ConsumeFloatingPoint<float>());
- std::vector<BlurRegion> regions;
- uint32_t vectorSize = mFdp.ConsumeIntegralInRange<uint32_t>(0, 100);
- regions.resize(vectorSize);
- for (size_t idx = 0; idx < vectorSize; ++idx) {
- regions.push_back(getBlurRegion());
- }
- transaction.setBlurRegions(surface, regions);
-
- transaction.setLayerStack(surface, {mFdp.ConsumeIntegral<uint32_t>()});
- half3 color = {mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
- mFdp.ConsumeIntegral<uint32_t>()};
- transaction.setColor(surface, color);
- transaction.setBackgroundColor(surface, color, mFdp.ConsumeFloatingPoint<float>(),
- mFdp.PickValueInArray(kDataspaces));
-
- transaction.setApi(surface, mFdp.ConsumeIntegral<int32_t>());
- transaction.setFrameRateSelectionPriority(surface, mFdp.ConsumeIntegral<int32_t>());
- transaction.setColorSpaceAgnostic(surface, mFdp.ConsumeBool() /*agnostic*/);
-
- gui::WindowInfo windowInfo;
- getWindowInfo(&windowInfo);
- transaction.setInputWindowInfo(surface, windowInfo);
- Parcel windowParcel;
- windowInfo.writeToParcel(&windowParcel);
- windowParcel.setDataPosition(0);
- windowInfo.readFromParcel(&windowParcel);
-
- windowInfo.addTouchableRegion(getRect(&mFdp));
- int32_t pointX = mFdp.ConsumeIntegral<int32_t>();
- int32_t pointY = mFdp.ConsumeIntegral<int32_t>();
- windowInfo.touchableRegionContainsPoint(pointX, pointY);
- windowInfo.frameContainsPoint(pointX, pointY);
-
- Parcel transactionParcel;
- transaction.writeToParcel(&transactionParcel);
- transactionParcel.setDataPosition(0);
- transaction.readFromParcel(&transactionParcel);
- SurfaceComposerClient::Transaction::createFromParcel(&transactionParcel);
-}
-
-void SurfaceComposerClientFuzzer::fuzzOnPullAtom() {
- std::string outData;
- bool success;
- SurfaceComposerClient::onPullAtom(mFdp.ConsumeIntegral<int32_t>(), &outData, &success);
-}
-
-void SurfaceComposerClientFuzzer::invokeSurfaceComposerClient() {
- String8 displayName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
- sp<IBinder> displayToken =
- SurfaceComposerClient::createDisplay(displayName, mFdp.ConsumeBool() /*secure*/);
- SurfaceComposerClient::setDesiredDisplayModeSpecs(displayToken, getDisplayModeSpecs());
-
- ui::ColorMode colorMode = mFdp.PickValueInArray(kColormodes);
- SurfaceComposerClient::setActiveColorMode(displayToken, colorMode);
- SurfaceComposerClient::setAutoLowLatencyMode(displayToken, mFdp.ConsumeBool() /*on*/);
- SurfaceComposerClient::setGameContentType(displayToken, mFdp.ConsumeBool() /*on*/);
- SurfaceComposerClient::setDisplayPowerMode(displayToken, mFdp.ConsumeIntegral<int32_t>());
- SurfaceComposerClient::doUncacheBufferTransaction(mFdp.ConsumeIntegral<uint64_t>());
-
- SurfaceComposerClient::setDisplayBrightness(displayToken, getBrightness(&mFdp));
- aidl::android::hardware::power::Boost boostId = mFdp.PickValueInArray(kBoost);
- SurfaceComposerClient::notifyPowerBoost((int32_t)boostId);
-
- String8 surfaceName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
- sp<BBinder> handle(new BBinder());
- sp<BnGraphicBufferProducer> producer;
- sp<Surface> surfaceParent(
- new Surface(producer, mFdp.ConsumeBool() /*controlledByApp*/, handle));
-
- fuzzOnPullAtom();
- SurfaceComposerClient::setDisplayContentSamplingEnabled(displayToken,
- mFdp.ConsumeBool() /*enable*/,
- mFdp.ConsumeIntegral<uint8_t>(),
- mFdp.ConsumeIntegral<uint64_t>());
-
- sp<IBinder> stopLayerHandle;
- sp<gui::IRegionSamplingListener> listener = sp<gui::IRegionSamplingListenerDefault>::make();
- sp<gui::IRegionSamplingListenerDelegator> sampleListener =
- new gui::IRegionSamplingListenerDelegator(listener);
- SurfaceComposerClient::addRegionSamplingListener(getRect(&mFdp), stopLayerHandle,
- sampleListener);
- sp<gui::IFpsListenerDefault> fpsListener;
- SurfaceComposerClient::addFpsListener(mFdp.ConsumeIntegral<int32_t>(), fpsListener);
-}
-
-void SurfaceComposerClientFuzzer::invokeSurfaceComposerClientBinder() {
- sp<FakeBnSurfaceComposerClient> client(new FakeBnSurfaceComposerClient());
- fuzzService(client.get(), std::move(mFdp));
-}
-
-void SurfaceComposerClientFuzzer::process() {
- invokeSurfaceComposerClient();
- invokeSurfaceComposerTransaction();
- invokeSurfaceComposerClientBinder();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- SurfaceComposerClientFuzzer surfaceComposerClientFuzzer(data, size);
- surfaceComposerClientFuzzer.process();
- return 0;
-}
diff --git a/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp
deleted file mode 100644
index 6d5427b..0000000
--- a/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2021 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 <fuzzbinder/libbinder_driver.h>
-#include <fuzzer/FuzzedDataProvider.h>
-#include <libgui_fuzzer_utils.h>
-
-using namespace android;
-
-class SurfaceComposerFuzzer {
-public:
- SurfaceComposerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- FuzzedDataProvider mFdp;
-};
-
-void SurfaceComposerFuzzer::process() {
- sp<FakeBnSurfaceComposer> composer(new FakeBnSurfaceComposer());
- fuzzService(composer.get(), std::move(mFdp));
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- SurfaceComposerFuzzer surfaceComposerFuzzer(data, size);
- surfaceComposerFuzzer.process();
- return 0;
-}
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index d4dbc45..c348833 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -20,12 +20,14 @@
#include <unistd.h>
#include <ctype.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <ftl/enum.h>
#include <gui/constants.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
+using android::base::GetProperty;
using android::base::StringPrintf;
namespace android {
@@ -96,21 +98,22 @@
// Treblized input device config files will be located /product/usr, /system_ext/usr,
// /odm/usr or /vendor/usr.
- // These files may also be in the com.android.input.config APEX.
- const char* rootsForPartition[]{
- "/product",
- "/system_ext",
- "/odm",
- "/vendor",
- "/apex/com.android.input.config/etc",
- getenv("ANDROID_ROOT"),
+ std::vector<std::string> pathPrefixes{
+ "/product/usr/",
+ "/system_ext/usr/",
+ "/odm/usr/",
+ "/vendor/usr/",
};
- for (size_t i = 0; i < size(rootsForPartition); i++) {
- if (rootsForPartition[i] == nullptr) {
- continue;
- }
- path = rootsForPartition[i];
- path += "/usr/";
+ // These files may also be in the APEX pointed by input_device.config_file.apex sysprop.
+ if (auto apex = GetProperty("input_device.config_file.apex", ""); !apex.empty()) {
+ pathPrefixes.push_back("/apex/" + apex + "/etc/usr/");
+ }
+ // ANDROID_ROOT may not be set on host
+ if (auto android_root = getenv("ANDROID_ROOT"); android_root != nullptr) {
+ pathPrefixes.push_back(std::string(android_root) + "/usr/");
+ }
+ for (const auto& prefix : pathPrefixes) {
+ path = prefix;
appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
ALOGD("Probing for system provided input device configuration file: path='%s'",
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 5af4855..bdec5c3 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -119,3 +119,10 @@
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/vibrator/ExternalVibration.cpp b/libs/vibrator/ExternalVibration.cpp
index 80e911c..c97e496 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 @@
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 980b08b..761ac1b 100644
--- a/libs/vibrator/ExternalVibrationUtils.cpp
+++ b/libs/vibrator/ExternalVibrationUtils.cpp
@@ -26,30 +26,30 @@
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 @@
}
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 @@
} // 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 00cd3cd..ac2767e 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 @@
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 ca219d3..d9a2b81 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 @@
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/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 71afbcc..8858f0c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -54,6 +54,7 @@
#include "InputDispatcher.h"
#include "trace/InputTracer.h"
#include "trace/InputTracingPerfettoBackend.h"
+#include "trace/ThreadedBackend.h"
#define INDENT " "
#define INDENT2 " "
@@ -86,6 +87,15 @@
return input_flags::enable_input_event_tracing() && isUserdebugOrEng;
}
+// Create the input tracing backend that writes to perfetto from a single thread.
+std::unique_ptr<trace::InputTracingBackendInterface> createInputTracingBackendIfEnabled() {
+ if (!isInputTracingEnabled()) {
+ return nullptr;
+ }
+ return std::make_unique<trace::impl::ThreadedBackend<trace::impl::PerfettoBackend>>(
+ trace::impl::PerfettoBackend());
+}
+
template <class Entry>
void ensureEventTraced(const Entry& entry) {
if (!entry.traceTracker) {
@@ -832,9 +842,7 @@
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy)
- : InputDispatcher(policy,
- isInputTracingEnabled() ? std::make_unique<trace::impl::PerfettoBackend>()
- : nullptr) {}
+ : InputDispatcher(policy, createInputTracingBackendIfEnabled()) {}
InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,
std::unique_ptr<trace::InputTracingBackendInterface> traceBackend)
@@ -1312,6 +1320,7 @@
ALOGD("Received a new pointer down event, stop waiting for events to process and "
"just send the pending key event to the currently focused window.");
mKeyIsWaitingForEventsTimeout = now();
+ needWake = true;
}
break;
}
diff --git a/services/inputflinger/dispatcher/trace/InputTracer.cpp b/services/inputflinger/dispatcher/trace/InputTracer.cpp
index 8a855c2..be09013 100644
--- a/services/inputflinger/dispatcher/trace/InputTracer.cpp
+++ b/services/inputflinger/dispatcher/trace/InputTracer.cpp
@@ -19,12 +19,17 @@
#include "InputTracer.h"
#include <android-base/logging.h>
-#include <utils/AndroidThreads.h>
namespace android::inputdispatcher::trace::impl {
namespace {
+// Helper to std::visit with lambdas.
+template <typename... V>
+struct Visitor : V... {
+ using V::operator()...;
+};
+
TracedEvent createTracedEvent(const MotionEntry& e) {
return TracedMotionEvent{e.id,
e.eventTime,
@@ -59,19 +64,9 @@
// --- InputTracer ---
InputTracer::InputTracer(std::unique_ptr<InputTracingBackendInterface> backend)
- : mTracerThread(&InputTracer::threadLoop, this), mBackend(std::move(backend)) {}
-
-InputTracer::~InputTracer() {
- {
- std::scoped_lock lock(mLock);
- mThreadExit = true;
- }
- mThreadWakeCondition.notify_all();
- mTracerThread.join();
-}
+ : mBackend(std::move(backend)) {}
std::unique_ptr<EventTrackerInterface> InputTracer::traceInboundEvent(const EventEntry& entry) {
- std::scoped_lock lock(mLock);
TracedEvent traced;
if (entry.type == EventEntry::Type::MOTION) {
@@ -89,7 +84,6 @@
void InputTracer::dispatchToTargetHint(const EventTrackerInterface& cookie,
const InputTarget& target) {
- std::scoped_lock lock(mLock);
auto& cookieState = getState(cookie);
if (!cookieState) {
LOG(FATAL) << "dispatchToTargetHint() should not be called after eventProcessingComplete()";
@@ -98,127 +92,72 @@
}
void InputTracer::eventProcessingComplete(const EventTrackerInterface& cookie) {
- {
- std::scoped_lock lock(mLock);
- auto& cookieState = getState(cookie);
- if (!cookieState) {
- LOG(FATAL) << "Traced event was already logged. "
- "eventProcessingComplete() was likely called more than once.";
- }
- mTraceQueue.emplace_back(std::move(*cookieState));
- cookieState.reset();
- } // release lock
+ auto& cookieState = getState(cookie);
+ if (!cookieState) {
+ LOG(FATAL) << "Traced event was already logged. "
+ "eventProcessingComplete() was likely called more than once.";
+ }
- mThreadWakeCondition.notify_all();
+ std::visit(Visitor{[&](const TracedMotionEvent& e) { mBackend->traceMotionEvent(e); },
+ [&](const TracedKeyEvent& e) { mBackend->traceKeyEvent(e); }},
+ cookieState->event);
+ cookieState.reset();
}
void InputTracer::traceEventDispatch(const DispatchEntry& dispatchEntry,
const EventTrackerInterface* cookie) {
- {
- std::scoped_lock lock(mLock);
- const EventEntry& entry = *dispatchEntry.eventEntry;
+ const EventEntry& entry = *dispatchEntry.eventEntry;
- TracedEvent traced;
- if (entry.type == EventEntry::Type::MOTION) {
- const auto& motion = static_cast<const MotionEntry&>(entry);
- traced = createTracedEvent(motion);
- } else if (entry.type == EventEntry::Type::KEY) {
- const auto& key = static_cast<const KeyEntry&>(entry);
- traced = createTracedEvent(key);
- } else {
- LOG(FATAL) << "Cannot trace EventEntry of type: " << ftl::enum_string(entry.type);
- }
+ TracedEvent traced;
+ if (entry.type == EventEntry::Type::MOTION) {
+ const auto& motion = static_cast<const MotionEntry&>(entry);
+ traced = createTracedEvent(motion);
+ } else if (entry.type == EventEntry::Type::KEY) {
+ const auto& key = static_cast<const KeyEntry&>(entry);
+ traced = createTracedEvent(key);
+ } else {
+ LOG(FATAL) << "Cannot trace EventEntry of type: " << ftl::enum_string(entry.type);
+ }
- if (!cookie) {
- // This event was not tracked as an inbound event, so trace it now.
- mTraceQueue.emplace_back(traced);
- }
+ if (!cookie) {
+ // This event was not tracked as an inbound event, so trace it now.
+ std::visit(Visitor{[&](const TracedMotionEvent& e) { mBackend->traceMotionEvent(e); },
+ [&](const TracedKeyEvent& e) { mBackend->traceKeyEvent(e); }},
+ traced);
+ }
- // The vsyncId only has meaning if the event is targeting a window.
- const int32_t windowId = dispatchEntry.windowId.value_or(0);
- const int32_t vsyncId = dispatchEntry.windowId.has_value() ? dispatchEntry.vsyncId : 0;
+ // The vsyncId only has meaning if the event is targeting a window.
+ const int32_t windowId = dispatchEntry.windowId.value_or(0);
+ const int32_t vsyncId = dispatchEntry.windowId.has_value() ? dispatchEntry.vsyncId : 0;
- mDispatchTraceQueue.emplace_back(std::move(traced), dispatchEntry.deliveryTime,
- dispatchEntry.resolvedFlags, dispatchEntry.targetUid,
- vsyncId, windowId, dispatchEntry.transform,
- dispatchEntry.rawTransform);
- } // release lock
-
- mThreadWakeCondition.notify_all();
+ mBackend->traceWindowDispatch({std::move(traced), dispatchEntry.deliveryTime,
+ dispatchEntry.resolvedFlags, dispatchEntry.targetUid, vsyncId,
+ windowId, dispatchEntry.transform, dispatchEntry.rawTransform,
+ /*hmac=*/{}});
}
std::optional<InputTracer::EventState>& InputTracer::getState(const EventTrackerInterface& cookie) {
- return static_cast<const EventTrackerImpl&>(cookie).mLockedState;
-}
-
-void InputTracer::threadLoop() {
- androidSetThreadName("InputTracer");
-
- std::vector<const EventState> eventsToTrace;
- std::vector<const WindowDispatchArgs> dispatchEventsToTrace;
-
- while (true) {
- { // acquire lock
- std::unique_lock lock(mLock);
- base::ScopedLockAssertion assumeLocked(mLock);
-
- // Wait until we need to process more events or exit.
- mThreadWakeCondition.wait(lock, [&]() REQUIRES(mLock) {
- return mThreadExit || !mTraceQueue.empty() || !mDispatchTraceQueue.empty();
- });
- if (mThreadExit) {
- return;
- }
-
- mTraceQueue.swap(eventsToTrace);
- mDispatchTraceQueue.swap(dispatchEventsToTrace);
- } // release lock
-
- // Trace the events into the backend without holding the lock to reduce the amount of
- // work performed in the critical section.
- writeEventsToBackend(eventsToTrace, dispatchEventsToTrace);
- eventsToTrace.clear();
- dispatchEventsToTrace.clear();
- }
-}
-
-void InputTracer::writeEventsToBackend(
- const std::vector<const EventState>& events,
- const std::vector<const WindowDispatchArgs>& dispatchEvents) {
- for (const auto& event : events) {
- if (auto* motion = std::get_if<TracedMotionEvent>(&event.event); motion != nullptr) {
- mBackend->traceMotionEvent(*motion);
- } else {
- mBackend->traceKeyEvent(std::get<TracedKeyEvent>(event.event));
- }
- }
-
- for (const auto& dispatchArgs : dispatchEvents) {
- mBackend->traceWindowDispatch(dispatchArgs);
- }
+ return static_cast<const EventTrackerImpl&>(cookie).mState;
}
// --- InputTracer::EventTrackerImpl ---
InputTracer::EventTrackerImpl::EventTrackerImpl(InputTracer& tracer, TracedEvent&& event)
- : mTracer(tracer), mLockedState(event) {}
+ : mTracer(tracer), mState(event) {}
InputTracer::EventTrackerImpl::~EventTrackerImpl() {
- {
- std::scoped_lock lock(mTracer.mLock);
- if (!mLockedState) {
- // This event has already been written to the trace as expected.
- return;
- }
- // We're still holding on to the state, which means it hasn't yet been written to the trace.
- // Write it to the trace now.
- // TODO(b/210460522): Determine why/where the event is being destroyed before
- // eventProcessingComplete() is called.
- mTracer.mTraceQueue.emplace_back(std::move(*mLockedState));
- mLockedState.reset();
- } // release lock
-
- mTracer.mThreadWakeCondition.notify_all();
+ if (!mState) {
+ // This event has already been written to the trace as expected.
+ return;
+ }
+ // We're still holding on to the state, which means it hasn't yet been written to the trace.
+ // Write it to the trace now.
+ // TODO(b/210460522): Determine why/where the event is being destroyed before
+ // eventProcessingComplete() is called.
+ std::visit(Visitor{[&](const TracedMotionEvent& e) { mTracer.mBackend->traceMotionEvent(e); },
+ [&](const TracedKeyEvent& e) { mTracer.mBackend->traceKeyEvent(e); }},
+ mState->event);
+ mState.reset();
}
} // namespace android::inputdispatcher::trace::impl
diff --git a/services/inputflinger/dispatcher/trace/InputTracer.h b/services/inputflinger/dispatcher/trace/InputTracer.h
index 9fe395d..c8b25c9 100644
--- a/services/inputflinger/dispatcher/trace/InputTracer.h
+++ b/services/inputflinger/dispatcher/trace/InputTracer.h
@@ -18,14 +18,7 @@
#include "InputTracerInterface.h"
-#include <android-base/thread_annotations.h>
-#include <gui/WindowInfo.h>
-
#include <memory>
-#include <mutex>
-#include <thread>
-#include <unordered_set>
-#include <vector>
#include "../Entry.h"
#include "InputTracingBackendInterface.h"
@@ -35,17 +28,16 @@
/**
* The tracer implementation for InputDispatcher.
*
- * InputTracer is thread-safe, so it can be called from any thread. Upon construction, InputTracer
- * will start its own thread that it uses for write events into the tracing backend. That is the
- * one and only thread that will interact with the tracing backend, since the Perfetto backend
- * uses thread-local storage.
+ * InputTracer's responsibility is to keep track of events as they are processed by InputDispatcher,
+ * and to write the events to the tracing backend when enough information is collected. InputTracer
+ * is not thread-safe.
*
* See the documentation in InputTracerInterface for the API surface.
*/
class InputTracer : public InputTracerInterface {
public:
explicit InputTracer(std::unique_ptr<InputTracingBackendInterface>);
- ~InputTracer() override;
+ ~InputTracer() = default;
InputTracer(const InputTracer&) = delete;
InputTracer& operator=(const InputTracer&) = delete;
@@ -55,10 +47,6 @@
void traceEventDispatch(const DispatchEntry&, const EventTrackerInterface*) override;
private:
- std::mutex mLock;
- std::thread mTracerThread;
- bool mThreadExit GUARDED_BY(mLock){false};
- std::condition_variable mThreadWakeCondition;
std::unique_ptr<InputTracingBackendInterface> mBackend;
// The state of a tracked event.
@@ -67,14 +55,12 @@
// TODO(b/210460522): Add additional args for tracking event sensitivity and
// dispatch target UIDs.
};
- std::vector<const EventState> mTraceQueue GUARDED_BY(mLock);
- using WindowDispatchArgs = InputTracingBackendInterface::WindowDispatchArgs;
- std::vector<const WindowDispatchArgs> mDispatchTraceQueue GUARDED_BY(mLock);
- // Provides thread-safe access to the state from an event tracker cookie.
- std::optional<EventState>& getState(const EventTrackerInterface&) REQUIRES(mLock);
+ // Get the event state associated with a tracking cookie.
+ std::optional<EventState>& getState(const EventTrackerInterface&);
- // Implementation of the event tracker cookie.
+ // Implementation of the event tracker cookie. The cookie holds the event state directly for
+ // convenience to avoid the overhead of tracking the state separately in InputTracer.
class EventTrackerImpl : public EventTrackerInterface {
public:
explicit EventTrackerImpl(InputTracer&, TracedEvent&& entry);
@@ -84,16 +70,10 @@
InputTracer& mTracer;
// This event tracker cookie will only hold the state as long as it has not been written
// to the trace. The state is released when the event is written to the trace.
- mutable std::optional<EventState> mLockedState;
+ mutable std::optional<EventState> mState;
- // Only allow InputTracer access to the locked state through getTrackerState() to ensure
- // that the InputTracer lock is held when this is accessed.
friend std::optional<EventState>& InputTracer::getState(const EventTrackerInterface&);
};
-
- void threadLoop();
- void writeEventsToBackend(const std::vector<const EventState>& events,
- const std::vector<const WindowDispatchArgs>& dispatchEvents);
};
} // namespace android::inputdispatcher::trace::impl
diff --git a/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h b/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h
index bc47817..b0eadfe 100644
--- a/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h
+++ b/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h
@@ -82,10 +82,10 @@
virtual ~InputTracingBackendInterface() = default;
/** Trace a KeyEvent. */
- virtual void traceKeyEvent(const TracedKeyEvent&) const = 0;
+ virtual void traceKeyEvent(const TracedKeyEvent&) = 0;
/** Trace a MotionEvent. */
- virtual void traceMotionEvent(const TracedMotionEvent&) const = 0;
+ virtual void traceMotionEvent(const TracedMotionEvent&) = 0;
/** Trace an event being sent to a window. */
struct WindowDispatchArgs {
@@ -99,7 +99,7 @@
ui::Transform rawTransform;
std::array<uint8_t, 32> hmac;
};
- virtual void traceWindowDispatch(const WindowDispatchArgs&) const = 0;
+ virtual void traceWindowDispatch(const WindowDispatchArgs&) = 0;
};
} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp b/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp
index 4442ad8..46ad9e1 100644
--- a/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp
+++ b/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp
@@ -63,7 +63,7 @@
});
}
-void PerfettoBackend::traceMotionEvent(const TracedMotionEvent& event) const {
+void PerfettoBackend::traceMotionEvent(const TracedMotionEvent& event) {
InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
auto tracePacket = ctx.NewTracePacket();
auto* inputEvent = tracePacket->set_android_input_event();
@@ -72,7 +72,7 @@
});
}
-void PerfettoBackend::traceKeyEvent(const TracedKeyEvent& event) const {
+void PerfettoBackend::traceKeyEvent(const TracedKeyEvent& event) {
InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
auto tracePacket = ctx.NewTracePacket();
auto* inputEvent = tracePacket->set_android_input_event();
@@ -81,7 +81,7 @@
});
}
-void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs) const {
+void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs) {
InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
auto tracePacket = ctx.NewTracePacket();
auto* inputEventProto = tracePacket->set_android_input_event();
diff --git a/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.h b/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.h
index 2777cfe..fefcfb3 100644
--- a/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.h
+++ b/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.h
@@ -48,9 +48,9 @@
PerfettoBackend();
~PerfettoBackend() override = default;
- void traceKeyEvent(const TracedKeyEvent&) const override;
- void traceMotionEvent(const TracedMotionEvent&) const override;
- void traceWindowDispatch(const WindowDispatchArgs&) const override;
+ void traceKeyEvent(const TracedKeyEvent&) override;
+ void traceMotionEvent(const TracedMotionEvent&) override;
+ void traceWindowDispatch(const WindowDispatchArgs&) override;
class InputEventDataSource : public perfetto::DataSource<InputEventDataSource> {
public:
diff --git a/services/inputflinger/dispatcher/trace/ThreadedBackend.cpp b/services/inputflinger/dispatcher/trace/ThreadedBackend.cpp
new file mode 100644
index 0000000..25bc227
--- /dev/null
+++ b/services/inputflinger/dispatcher/trace/ThreadedBackend.cpp
@@ -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.
+ */
+
+#define LOG_TAG "InputTracer"
+
+#include "ThreadedBackend.h"
+
+#include "InputTracingPerfettoBackend.h"
+
+#include <android-base/logging.h>
+
+namespace android::inputdispatcher::trace::impl {
+
+namespace {
+
+// Helper to std::visit with lambdas.
+template <typename... V>
+struct Visitor : V... {
+ using V::operator()...;
+};
+
+} // namespace
+
+// --- ThreadedBackend ---
+
+template <typename Backend>
+ThreadedBackend<Backend>::ThreadedBackend(Backend&& innerBackend)
+ : mTracerThread(
+ "InputTracer", [this]() { threadLoop(); },
+ [this]() { mThreadWakeCondition.notify_all(); }),
+ mBackend(std::move(innerBackend)) {}
+
+template <typename Backend>
+ThreadedBackend<Backend>::~ThreadedBackend() {
+ {
+ std::scoped_lock lock(mLock);
+ mThreadExit = true;
+ }
+ mThreadWakeCondition.notify_all();
+}
+
+template <typename Backend>
+void ThreadedBackend<Backend>::traceMotionEvent(const TracedMotionEvent& event) {
+ std::scoped_lock lock(mLock);
+ mQueue.emplace_back(event);
+ mThreadWakeCondition.notify_all();
+}
+
+template <typename Backend>
+void ThreadedBackend<Backend>::traceKeyEvent(const TracedKeyEvent& event) {
+ std::scoped_lock lock(mLock);
+ mQueue.emplace_back(event);
+ mThreadWakeCondition.notify_all();
+}
+
+template <typename Backend>
+void ThreadedBackend<Backend>::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs) {
+ std::scoped_lock lock(mLock);
+ mQueue.emplace_back(dispatchArgs);
+ mThreadWakeCondition.notify_all();
+}
+
+template <typename Backend>
+void ThreadedBackend<Backend>::threadLoop() {
+ std::vector<TraceEntry> entries;
+
+ { // acquire lock
+ std::unique_lock lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+
+ // Wait until we need to process more events or exit.
+ mThreadWakeCondition.wait(lock,
+ [&]() REQUIRES(mLock) { return mThreadExit || !mQueue.empty(); });
+ if (mThreadExit) {
+ return;
+ }
+
+ mQueue.swap(entries);
+ } // release lock
+
+ // Trace the events into the backend without holding the lock to reduce the amount of
+ // work performed in the critical section.
+ for (const auto& entry : entries) {
+ std::visit(Visitor{[&](const TracedMotionEvent& e) { mBackend.traceMotionEvent(e); },
+ [&](const TracedKeyEvent& e) { mBackend.traceKeyEvent(e); },
+ [&](const WindowDispatchArgs& args) {
+ mBackend.traceWindowDispatch(args);
+ }},
+ entry);
+ }
+ entries.clear();
+}
+
+// Explicit template instantiation for the PerfettoBackend.
+template class ThreadedBackend<PerfettoBackend>;
+
+} // namespace android::inputdispatcher::trace::impl
diff --git a/services/inputflinger/dispatcher/trace/ThreadedBackend.h b/services/inputflinger/dispatcher/trace/ThreadedBackend.h
new file mode 100644
index 0000000..5776cf9
--- /dev/null
+++ b/services/inputflinger/dispatcher/trace/ThreadedBackend.h
@@ -0,0 +1,59 @@
+/*
+ * 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 "InputThread.h"
+#include "InputTracingPerfettoBackend.h"
+
+#include <android-base/thread_annotations.h>
+#include <mutex>
+#include <variant>
+#include <vector>
+
+namespace android::inputdispatcher::trace::impl {
+
+/**
+ * A wrapper around an InputTracingBackend implementation that writes to the inner tracing backend
+ * from a single new thread that it creates. The new tracing thread is started when the
+ * ThreadedBackend is created, and is stopped when it is destroyed. The ThreadedBackend is
+ * thread-safe.
+ */
+template <typename Backend>
+class ThreadedBackend : public InputTracingBackendInterface {
+public:
+ ThreadedBackend(Backend&& innerBackend);
+ ~ThreadedBackend() override;
+
+ void traceKeyEvent(const TracedKeyEvent&) override;
+ void traceMotionEvent(const TracedMotionEvent&) override;
+ void traceWindowDispatch(const WindowDispatchArgs&) override;
+
+private:
+ std::mutex mLock;
+ InputThread mTracerThread;
+ bool mThreadExit GUARDED_BY(mLock){false};
+ std::condition_variable mThreadWakeCondition;
+ Backend mBackend;
+ using TraceEntry = std::variant<TracedKeyEvent, TracedMotionEvent, WindowDispatchArgs>;
+ std::vector<TraceEntry> mQueue GUARDED_BY(mLock);
+
+ using WindowDispatchArgs = InputTracingBackendInterface::WindowDispatchArgs;
+
+ void threadLoop();
+};
+
+} // namespace android::inputdispatcher::trace::impl
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 19788ce..764bb56 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -67,7 +67,7 @@
: mDeviceId(deviceId),
mReaderContext(readerContext),
mPointerController(readerContext.getPointerController(deviceId)),
- 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);
}
@@ -174,8 +174,7 @@
const Gesture& gesture) {
float deltaX = gesture.details.move.dx;
float deltaY = gesture.details.move.dy;
- const auto [oldXCursorPosition, oldYCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [oldXCursorPosition, oldYCursorPosition] = mPointerController->getPosition();
if (ENABLE_TOUCHPAD_PALM_REJECTION_V2) {
bool wasHoverCancelled = mIsHoverCancelled;
// Gesture will be cancelled if it started before the user started typing and
@@ -213,8 +212,7 @@
if (!down) {
out += enterHover(when, readTime, oldXCursorPosition, oldYCursorPosition);
}
- const auto [newXCursorPosition, newYCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [newXCursorPosition, newYCursorPosition] = mPointerController->getPosition();
PointerCoords coords;
coords.clear();
@@ -238,8 +236,7 @@
mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- const auto [xCursorPosition, yCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
PointerCoords coords;
coords.clear();
@@ -319,8 +316,7 @@
std::list<NotifyArgs> GestureConverter::releaseAllButtons(nsecs_t when, nsecs_t readTime) {
std::list<NotifyArgs> out;
- const auto [xCursorPosition, yCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
PointerCoords coords;
coords.clear();
@@ -355,8 +351,7 @@
const Gesture& gesture) {
std::list<NotifyArgs> out;
PointerCoords& coords = mFakeFingerCoords[0];
- const auto [xCursorPosition, yCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
if (mCurrentClassification != MotionClassification::TWO_FINGER_SWIPE) {
out += exitHover(when, readTime, xCursorPosition, yCursorPosition);
@@ -400,20 +395,54 @@
// 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] =
+ 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:
@@ -425,8 +454,7 @@
std::list<NotifyArgs> GestureConverter::endScroll(nsecs_t when, nsecs_t readTime) {
std::list<NotifyArgs> out;
- const auto [xCursorPosition, yCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE, 0);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, 0);
NotifyMotionArgs args =
@@ -446,8 +474,7 @@
float dx, float dy) {
std::list<NotifyArgs> out = {};
- const auto [xCursorPosition, yCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) {
// If the user changes the number of fingers mid-way through a swipe (e.g. they start with
// three and then put a fourth finger down), the gesture library will treat it as two
@@ -511,8 +538,7 @@
if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) {
return out;
}
- const auto [xCursorPosition, yCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET, 0);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, 0);
@@ -535,8 +561,7 @@
[[nodiscard]] std::list<NotifyArgs> GestureConverter::handlePinch(nsecs_t when, nsecs_t readTime,
const Gesture& gesture) {
- const auto [xCursorPosition, yCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
// Pinch gesture phases are reported a little differently from others, in that the same details
// struct is used for all phases of the gesture, just with different zoom_state values. When
@@ -594,8 +619,7 @@
std::list<NotifyArgs> GestureConverter::endPinch(nsecs_t when, nsecs_t readTime) {
std::list<NotifyArgs> out;
- const auto [xCursorPosition, yCursorPosition] =
- mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
+ const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, 1.0);
out.push_back(makeMotionArgs(when, readTime,
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index 07cc56c..c8f437e 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -105,7 +105,7 @@
const int32_t mDeviceId;
InputReaderContext& mReaderContext;
std::shared_ptr<PointerControllerInterface> mPointerController;
- const bool mEnablePointerChoreographer;
+ const bool mEnableFlingStop;
std::optional<int32_t> mDisplayId;
FloatRect mBoundsInLogicalDisplay{};
@@ -120,6 +120,9 @@
// 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/rust/slow_keys_filter.rs b/services/inputflinger/rust/slow_keys_filter.rs
index 01165b5..09fbf40 100644
--- a/services/inputflinger/rust/slow_keys_filter.rs
+++ b/services/inputflinger/rust/slow_keys_filter.rs
@@ -28,6 +28,9 @@
use std::collections::HashSet;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
+// Policy flags from Input.h
+const POLICY_FLAG_DISABLE_KEY_REPEAT: i32 = 0x08000000;
+
#[derive(Debug)]
struct OngoingKeyDown {
scancode: i32,
@@ -129,6 +132,12 @@
let mut pending_event = *event;
pending_event.downTime += slow_filter.slow_key_threshold_ns;
pending_event.eventTime = pending_event.downTime;
+ // Currently a slow keys user ends up repeating the presses key quite often
+ // since default repeat thresholds are very low, so blocking repeat for events
+ // when slow keys is enabled.
+ // TODO(b/322327461): Allow key repeat with slow keys, once repeat key rate and
+ // thresholds can be modified in the settings.
+ pending_event.policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
slow_filter.pending_down_events.push(pending_event);
}
KeyEventAction::UP => {
@@ -200,7 +209,7 @@
mod tests {
use crate::input_filter::{test_callbacks::TestCallbacks, test_filter::TestFilter, Filter};
use crate::input_filter_thread::test_thread::TestThread;
- use crate::slow_keys_filter::SlowKeysFilter;
+ use crate::slow_keys_filter::{SlowKeysFilter, POLICY_FLAG_DISABLE_KEY_REPEAT};
use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
@@ -285,6 +294,7 @@
action: KeyEventAction::DOWN,
downTime: 100,
eventTime: 100,
+ policyFlags: POLICY_FLAG_DISABLE_KEY_REPEAT,
..BASE_KEY_EVENT
}
);
diff --git a/services/inputflinger/tests/FakeInputTracingBackend.cpp b/services/inputflinger/tests/FakeInputTracingBackend.cpp
index b7af356..4655ee8 100644
--- a/services/inputflinger/tests/FakeInputTracingBackend.cpp
+++ b/services/inputflinger/tests/FakeInputTracingBackend.cpp
@@ -163,7 +163,7 @@
// --- FakeInputTracingBackend ---
-void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) const {
+void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) {
{
std::scoped_lock lock(mTrace->mLock);
mTrace->mTracedEvents.emplace(event.id, event);
@@ -171,7 +171,7 @@
mTrace->mEventTracedCondition.notify_all();
}
-void FakeInputTracingBackend::traceMotionEvent(const trace::TracedMotionEvent& event) const {
+void FakeInputTracingBackend::traceMotionEvent(const trace::TracedMotionEvent& event) {
{
std::scoped_lock lock(mTrace->mLock);
mTrace->mTracedEvents.emplace(event.id, event);
@@ -179,7 +179,7 @@
mTrace->mEventTracedCondition.notify_all();
}
-void FakeInputTracingBackend::traceWindowDispatch(const WindowDispatchArgs& args) const {
+void FakeInputTracingBackend::traceWindowDispatch(const WindowDispatchArgs& args) {
{
std::scoped_lock lock(mTrace->mLock);
mTrace->mTracedWindowDispatches.push_back(args);
diff --git a/services/inputflinger/tests/FakeInputTracingBackend.h b/services/inputflinger/tests/FakeInputTracingBackend.h
index 108419a..1b3613d 100644
--- a/services/inputflinger/tests/FakeInputTracingBackend.h
+++ b/services/inputflinger/tests/FakeInputTracingBackend.h
@@ -83,9 +83,9 @@
private:
std::shared_ptr<VerifyingTrace> mTrace;
- void traceKeyEvent(const trace::TracedKeyEvent& entry) const override;
- void traceMotionEvent(const trace::TracedMotionEvent& entry) const override;
- void traceWindowDispatch(const WindowDispatchArgs& entry) const override;
+ void traceKeyEvent(const trace::TracedKeyEvent& entry) override;
+ void traceMotionEvent(const trace::TracedMotionEvent& entry) override;
+ void traceWindowDispatch(const WindowDispatchArgs& entry) override;
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp
index 31e1173..dc199e2 100644
--- a/services/inputflinger/tests/FakePointerController.cpp
+++ b/services/inputflinger/tests/FakePointerController.cpp
@@ -37,16 +37,22 @@
}
void FakePointerController::setPosition(float x, float y) {
+ if (!mEnabled) return;
+
mX = x;
mY = y;
}
FloatPoint FakePointerController::getPosition() const {
+ if (!mEnabled) {
+ return {0, 0};
+ }
+
return {mX, mY};
}
int32_t FakePointerController::getDisplayId() const {
- if (!mDisplayId) {
+ if (!mEnabled || !mDisplayId) {
return ADISPLAY_ID_NONE;
}
return *mDisplayId;
@@ -64,6 +70,8 @@
}
void FakePointerController::setCustomPointerIcon(const SpriteIcon& icon) {
+ if (!mEnabled) return;
+
ASSERT_FALSE(mCustomIconStyle.has_value()) << "Custom pointer icon was set more than once";
mCustomIconStyle = icon.style;
}
@@ -114,10 +122,14 @@
}
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;
+
mX += deltaX;
if (mX < mMinX) mX = mMinX;
if (mX > mMaxX) mX = mMaxX;
@@ -127,14 +139,20 @@
}
void FakePointerController::fade(Transition) {
+ if (!mEnabled) return;
+
mIsPointerShown = false;
}
void FakePointerController::unfade(Transition) {
+ if (!mEnabled) return;
+
mIsPointerShown = true;
}
void FakePointerController::setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits,
int32_t displayId) {
+ if (!mEnabled) return;
+
std::vector<int32_t> newSpots;
// Add spots for fingers that are down.
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
@@ -146,6 +164,8 @@
}
void FakePointerController::clearSpots() {
+ if (!mEnabled) return;
+
mSpotsByDisplay.clear();
}
diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h
index 061ae62..536b447 100644
--- a/services/inputflinger/tests/FakePointerController.h
+++ b/services/inputflinger/tests/FakePointerController.h
@@ -30,6 +30,9 @@
class FakePointerController : public PointerControllerInterface {
public:
+ FakePointerController() : FakePointerController(/*enabled=*/true) {}
+ FakePointerController(bool enabled) : mEnabled(enabled) {}
+
virtual ~FakePointerController() {}
void setBounds(float minX, float minY, float maxX, float maxY);
@@ -64,6 +67,7 @@
int32_t displayId) override;
void clearSpots() override;
+ const bool mEnabled;
bool mHaveBounds{false};
float mMinX{0}, mMinY{0}, mMaxX{0}, mMaxY{0};
float mX{0}, mY{0};
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index dd88165..337b52b 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -69,7 +69,8 @@
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, -500, 500, 0, 0, 20);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 500, 0, 0, 20);
- mFakePointerController = std::make_shared<FakePointerController>();
+ mFakePointerController = std::make_shared<FakePointerController>(
+ /*enabled=*/!input_flags::enable_pointer_choreographer());
mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
mFakePointerController->setPosition(POINTER_X, POINTER_Y);
mFakePolicy->setPointerController(mFakePointerController);
@@ -1167,6 +1168,38 @@
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 +2589,38 @@
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 759485f..61ab47a 100644
--- a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
+++ b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
@@ -70,12 +70,14 @@
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 @@
if (hal == nullptr) {
ALOGV("Power HAL not available, skipping test...");
+ state.SkipWithMessage("Power HAL unavailable");
return;
}
@@ -109,12 +112,14 @@
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 @@
if (hal == nullptr) {
ALOGV("Power HAL not available, skipping test...");
+ state.SkipWithMessage("Power HAL unavailable");
return;
}
@@ -170,6 +176,7 @@
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 111b5d7..bcb376b 100644
--- a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
+++ b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
@@ -50,6 +50,7 @@
if (hal == nullptr) {
ALOGV("Power HAL HIDL not available, skipping test...");
+ state.SkipWithMessage("Power HAL unavailable");
return;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 1c2f6cb..921e05d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1276,7 +1276,9 @@
if (isProtected && supportsProtectedContent) {
auto layers = getOutputLayersOrderedByZ();
bool needsProtected = std::any_of(layers.begin(), layers.end(), [](auto* layer) {
- return layer->getLayerFE().getCompositionState()->hasProtectedContent;
+ return layer->getLayerFE().getCompositionState()->hasProtectedContent &&
+ (!FlagManager::getInstance().protected_if_client() ||
+ layer->requiresClientComposition());
});
if (needsProtected != mRenderSurface->isProtected()) {
mRenderSurface->setProtected(needsProtected);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 62cfaf4..799c7ed 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -4051,6 +4051,7 @@
Layer() {
EXPECT_CALL(*mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState));
EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*mLayerFE));
+ EXPECT_CALL(mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
}
StrictMock<mock::OutputLayer> mOutputLayer;
@@ -4091,6 +4092,7 @@
};
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) {
+ SET_FLAG_FOR_TEST(flags::protected_if_client, true);
if (FlagManager::getInstance().display_protected()) {
mOutput.mState.isProtected = true;
} else {
@@ -4109,6 +4111,7 @@
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) {
+ SET_FLAG_FOR_TEST(flags::protected_if_client, true);
if (FlagManager::getInstance().display_protected()) {
mOutput.mState.isProtected = true;
} else {
@@ -4135,6 +4138,7 @@
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) {
+ SET_FLAG_FOR_TEST(flags::protected_if_client, true);
if (FlagManager::getInstance().display_protected()) {
mOutput.mState.isProtected = true;
} else {
@@ -4152,6 +4156,7 @@
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) {
+ SET_FLAG_FOR_TEST(flags::protected_if_client, true);
if (FlagManager::getInstance().display_protected()) {
mOutput.mState.isProtected = true;
} else {
@@ -5096,5 +5101,79 @@
mOutput->present(mRefreshArgs);
}
+/*
+ * Output::updateProtectedContentState()
+ */
+
+struct OutputUpdateProtectedContentStateTest : public testing::Test {
+ struct OutputPartialMock : public OutputPartialMockBase {
+ // Sets up the helper functions called by the function under test to use
+ // mock implementations.
+ MOCK_CONST_METHOD0(getCompositionEngine, const CompositionEngine&());
+ };
+
+ OutputUpdateProtectedContentStateTest() {
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
+ EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0))
+ .WillRepeatedly(Return(&mLayer1.mOutputLayer));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(1))
+ .WillRepeatedly(Return(&mLayer2.mOutputLayer));
+ }
+
+ struct Layer {
+ Layer() {
+ EXPECT_CALL(*mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState));
+ EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*mLayerFE));
+ }
+
+ StrictMock<mock::OutputLayer> mOutputLayer;
+ sp<StrictMock<mock::LayerFE>> mLayerFE = sp<StrictMock<mock::LayerFE>>::make();
+ LayerFECompositionState mLayerFEState;
+ };
+
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<OutputPartialMock> mOutput;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
+ Layer mLayer1;
+ Layer mLayer2;
+};
+
+TEST_F(OutputUpdateProtectedContentStateTest, ifProtectedContentLayerComposeByHWC) {
+ SET_FLAG_FOR_TEST(flags::protected_if_client, true);
+ if (FlagManager::getInstance().display_protected()) {
+ mOutput.mState.isProtected = true;
+ } else {
+ mOutput.mState.isSecure = true;
+ }
+ mLayer1.mLayerFEState.hasProtectedContent = false;
+ mLayer2.mLayerFEState.hasProtectedContent = true;
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
+ EXPECT_CALL(mLayer1.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mLayer2.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
+ mOutput.updateProtectedContentState();
+}
+
+TEST_F(OutputUpdateProtectedContentStateTest, ifProtectedContentLayerComposeByClient) {
+ SET_FLAG_FOR_TEST(flags::protected_if_client, true);
+ if (FlagManager::getInstance().display_protected()) {
+ mOutput.mState.isProtected = true;
+ } else {
+ mOutput.mState.isSecure = true;
+ }
+ mLayer1.mLayerFEState.hasProtectedContent = false;
+ mLayer2.mLayerFEState.hasProtectedContent = true;
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
+ EXPECT_CALL(*mRenderSurface, setProtected(true));
+ EXPECT_CALL(mLayer1.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mLayer2.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+ mOutput.updateProtectedContentState();
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index cfa0339..776bcd3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -92,7 +92,7 @@
mMaxVirtualDisplayDimension(static_cast<size_t>(sysprop::max_virtual_display_dimension(0))),
mUpdateDeviceProductInfoOnHotplugReconnect(
sysprop::update_device_product_info_on_hotplug_reconnect(false)),
- mEnableVrrTimeout(base::GetBoolProperty("debug.sf.vrr_timeout_hint_enabled"s, false)) {}
+ mEnableVrrTimeout(base::GetBoolProperty("debug.sf.vrr_timeout_hint_enabled"s, true)) {}
HWComposer::HWComposer(const std::string& composerServiceName)
: HWComposer(Hwc2::Composer::create(composerServiceName)) {}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index a145e59..ff88d71 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -17,7 +17,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <binder/IPCThreadState.h>
-#include <gui/DisplayEventReceiver.h>
#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/threads.h>
@@ -66,7 +65,7 @@
{
std::lock_guard lock(mVsync.mutex);
mVsync.lastCallbackTime = expectedVsyncTime;
- mVsync.scheduledFrameTime.reset();
+ mVsync.scheduledFrameTimeOpt.reset();
}
const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
@@ -122,7 +121,7 @@
std::placeholders::_3),
"sf");
if (reschedule) {
- mVsync.scheduledFrameTime =
+ mVsync.scheduledFrameTimeOpt =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.lastVsync = mVsync.lastCallbackTime.ns()});
@@ -140,7 +139,7 @@
ATRACE_CALL();
std::lock_guard lock(mVsync.mutex);
mVsync.workDuration = workDuration;
- mVsync.scheduledFrameTime =
+ mVsync.scheduledFrameTimeOpt =
mVsync.registration->update({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.lastVsync = mVsync.lastCallbackTime.ns()});
@@ -193,22 +192,20 @@
ATRACE_CALL();
std::lock_guard lock(mVsync.mutex);
- mVsync.scheduledFrameTime =
+ mVsync.scheduledFrameTimeOpt =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.lastVsync = mVsync.lastCallbackTime.ns()});
}
-auto MessageQueue::getScheduledFrameTime() const -> std::optional<Clock::time_point> {
+std::optional<scheduler::ScheduleResult> MessageQueue::getScheduledFrameResult() const {
if (mHandler->isFramePending()) {
- return Clock::now();
+ return scheduler::ScheduleResult{TimePoint::now(), mHandler->getExpectedVsyncTime()};
}
-
std::lock_guard lock(mVsync.mutex);
- if (const auto time = mVsync.scheduledFrameTime) {
- return Clock::time_point(std::chrono::nanoseconds(*time));
+ if (const auto scheduledFrameTimeline = mVsync.scheduledFrameTimeOpt) {
+ return scheduledFrameTimeline;
}
-
return std::nullopt;
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index edb424b..c5fc371 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -76,8 +76,7 @@
virtual void scheduleConfigure() = 0;
virtual void scheduleFrame() = 0;
- using Clock = std::chrono::steady_clock;
- virtual std::optional<Clock::time_point> getScheduledFrameTime() const = 0;
+ virtual std::optional<scheduler::ScheduleResult> getScheduledFrameResult() const = 0;
};
namespace impl {
@@ -95,7 +94,9 @@
explicit Handler(MessageQueue& queue) : mQueue(queue) {}
void handleMessage(const Message& message) override;
- bool isFramePending() const;
+ virtual TimePoint getExpectedVsyncTime() const { return mExpectedVsyncTime.load(); }
+
+ virtual bool isFramePending() const;
virtual void dispatchFrame(VsyncId, TimePoint expectedVsyncTime);
};
@@ -124,7 +125,7 @@
TracedOrdinal<std::chrono::nanoseconds> workDuration
GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
TimePoint lastCallbackTime GUARDED_BY(mutex);
- std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex);
+ std::optional<scheduler::ScheduleResult> scheduledFrameTimeOpt GUARDED_BY(mutex);
TracedOrdinal<int> value = {"VSYNC-sf", 0};
};
@@ -150,7 +151,7 @@
void scheduleConfigure() override;
void scheduleFrame() override;
- std::optional<Clock::time_point> getScheduledFrameTime() const override;
+ std::optional<scheduler::ScheduleResult> getScheduledFrameResult() const override;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6979f03..3f91682 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -60,14 +60,6 @@
#include "VsyncController.h"
#include "VsyncSchedule.h"
-#define RETURN_IF_INVALID_HANDLE(handle, ...) \
- do { \
- if (mConnections.count(handle) == 0) { \
- ALOGE("Invalid connection handle %" PRIuPTR, handle.id); \
- return __VA_ARGS__; \
- } \
- } while (false)
-
namespace android::scheduler {
Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features,
@@ -162,9 +154,13 @@
if (isNew) {
onHardwareVsyncRequest(displayId, false);
}
+
+ dispatchHotplug(displayId, Hotplug::Connected);
}
void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
+ dispatchHotplug(displayId, Hotplug::Disconnected);
+
demotePacesetterDisplay();
std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
@@ -344,40 +340,26 @@
}
}
-ConnectionHandle Scheduler::createEventThread(Cycle cycle,
- frametimeline::TokenManager* tokenManager,
- std::chrono::nanoseconds workDuration,
- std::chrono::nanoseconds readyDuration) {
+void Scheduler::createEventThread(Cycle cycle, frametimeline::TokenManager* tokenManager,
+ std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) {
auto eventThread =
std::make_unique<android::impl::EventThread>(cycle == Cycle::Render ? "app" : "appSf",
getVsyncSchedule(), tokenManager, *this,
workDuration, readyDuration);
- auto& handle = cycle == Cycle::Render ? mAppConnectionHandle : mSfConnectionHandle;
- handle = createConnection(std::move(eventThread));
- return handle;
-}
-
-ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) {
- const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
- ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
-
- auto connection = eventThread->createEventConnection();
-
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
- return handle;
+ if (cycle == Cycle::Render) {
+ mRenderEventThread = std::move(eventThread);
+ mRenderEventConnection = mRenderEventThread->createEventConnection();
+ } else {
+ mLastCompositeEventThread = std::move(eventThread);
+ mLastCompositeEventConnection = mLastCompositeEventThread->createEventConnection();
+ }
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- ConnectionHandle handle, EventRegistrationFlags eventRegistration,
- const sp<IBinder>& layerHandle) {
- const auto connection = [&]() -> sp<EventThreadConnection> {
- std::scoped_lock lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle, nullptr);
-
- return mConnections[handle].thread->createEventConnection(eventRegistration);
- }();
+ Cycle cycle, EventRegistrationFlags eventRegistration, const sp<IBinder>& layerHandle) {
+ const auto connection = eventThreadFor(cycle).createEventConnection(eventRegistration);
const auto layerId = static_cast<int32_t>(LayerHandle::getLayerId(layerHandle));
if (layerId != static_cast<int32_t>(UNASSIGNED_LAYER_ID)) {
@@ -397,85 +379,51 @@
return connection;
}
-sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle, nullptr);
- return mConnections[handle].connection;
+void Scheduler::dispatchHotplug(PhysicalDisplayId displayId, Hotplug hotplug) {
+ if (hasEventThreads()) {
+ const bool connected = hotplug == Hotplug::Connected;
+ eventThreadFor(Cycle::Render).onHotplugReceived(displayId, connected);
+ eventThreadFor(Cycle::LastComposite).onHotplugReceived(displayId, connected);
+ }
}
-void Scheduler::onHotplugReceived(ConnectionHandle handle, PhysicalDisplayId displayId,
- bool connected) {
- android::EventThread* thread;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections[handle].thread.get();
+void Scheduler::dispatchHotplugError(int32_t errorCode) {
+ if (hasEventThreads()) {
+ eventThreadFor(Cycle::Render).onHotplugConnectionError(errorCode);
+ eventThreadFor(Cycle::LastComposite).onHotplugConnectionError(errorCode);
}
-
- thread->onHotplugReceived(displayId, connected);
-}
-
-void Scheduler::onHotplugConnectionError(ConnectionHandle handle, int32_t errorCode) {
- android::EventThread* thread;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections[handle].thread.get();
- }
-
- thread->onHotplugConnectionError(errorCode);
}
void Scheduler::enableSyntheticVsync(bool enable) {
- // TODO(b/241285945): Remove connection handles.
- const ConnectionHandle handle = mAppConnectionHandle;
- android::EventThread* thread;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections[handle].thread.get();
- }
- thread->enableSyntheticVsync(enable);
+ eventThreadFor(Cycle::Render).enableSyntheticVsync(enable);
}
-void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
+void Scheduler::onFrameRateOverridesChanged(Cycle cycle, PhysicalDisplayId displayId) {
const bool supportsFrameRateOverrideByContent =
pacesetterSelectorPtr()->supportsAppFrameRateOverrideByContent();
std::vector<FrameRateOverride> overrides =
mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent);
- android::EventThread* thread;
- {
- std::lock_guard lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections[handle].thread.get();
- }
- thread->onFrameRateOverridesChanged(displayId, std::move(overrides));
+ eventThreadFor(cycle).onFrameRateOverridesChanged(displayId, std::move(overrides));
}
-void Scheduler::onHdcpLevelsChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
+void Scheduler::onHdcpLevelsChanged(Cycle cycle, PhysicalDisplayId displayId,
int32_t connectedLevel, int32_t maxLevel) {
- android::EventThread* thread;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections[handle].thread.get();
- }
- thread->onHdcpLevelsChanged(displayId, connectedLevel, maxLevel);
+ eventThreadFor(cycle).onHdcpLevelsChanged(displayId, connectedLevel, maxLevel);
}
-void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) {
+void Scheduler::onPrimaryDisplayModeChanged(Cycle cycle, const FrameRateMode& mode) {
{
std::lock_guard<std::mutex> lock(mPolicyLock);
// Cache the last reported modes for primary display.
- mPolicy.cachedModeChangedParams = {handle, mode};
+ mPolicy.cachedModeChangedParams = {cycle, mode};
// Invalidate content based refresh rate selection so it could be calculated
// again for the new refresh rate.
mPolicy.contentRequirements.clear();
}
- onNonPrimaryDisplayModeChanged(handle, mode);
+ onNonPrimaryDisplayModeChanged(cycle, mode);
}
void Scheduler::dispatchCachedReportedMode() {
@@ -502,39 +450,25 @@
}
mPolicy.cachedModeChangedParams->mode = *mPolicy.modeOpt;
- onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->handle,
+ onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->cycle,
mPolicy.cachedModeChangedParams->mode);
}
-void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) {
- android::EventThread* thread;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections[handle].thread.get();
+void Scheduler::onNonPrimaryDisplayModeChanged(Cycle cycle, const FrameRateMode& mode) {
+ if (hasEventThreads()) {
+ eventThreadFor(cycle).onModeChanged(mode);
}
- thread->onModeChanged(mode);
}
-void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
- android::EventThread* thread;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections.at(handle).thread.get();
- }
- thread->dump(result);
+void Scheduler::dump(Cycle cycle, std::string& result) const {
+ eventThreadFor(cycle).dump(result);
}
-void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds workDuration,
+void Scheduler::setDuration(Cycle cycle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration) {
- android::EventThread* thread;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections[handle].thread.get();
+ if (hasEventThreads()) {
+ eventThreadFor(cycle).setDuration(workDuration, readyDuration);
}
- thread->setDuration(workDuration, readyDuration);
}
void Scheduler::updatePhaseConfiguration(Fps refreshRate) {
@@ -557,10 +491,10 @@
}
void Scheduler::setVsyncConfig(const VsyncConfig& config, Period vsyncPeriod) {
- setDuration(mAppConnectionHandle,
+ setDuration(Cycle::Render,
/* workDuration */ config.appWorkDuration,
/* readyDuration */ config.sfWorkDuration);
- setDuration(mSfConnectionHandle,
+ setDuration(Cycle::LastComposite,
/* workDuration */ vsyncPeriod,
/* readyDuration */ config.sfWorkDuration);
setDuration(config.sfWorkDuration);
@@ -1027,16 +961,10 @@
void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedule) {
onNewVsyncSchedule(vsyncSchedule->getDispatch());
- std::vector<android::EventThread*> threads;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- threads.reserve(mConnections.size());
- for (auto& [_, connection] : mConnections) {
- threads.push_back(connection.thread.get());
- }
- }
- for (auto* thread : threads) {
- thread->onNewVsyncSchedule(vsyncSchedule);
+
+ if (hasEventThreads()) {
+ eventThreadFor(Cycle::Render).onNewVsyncSchedule(vsyncSchedule);
+ eventThreadFor(Cycle::LastComposite).onNewVsyncSchedule(vsyncSchedule);
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9f29e9f..09f75fd 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -56,35 +56,6 @@
#include <FrontEnd/LayerHierarchy.h>
-namespace android::scheduler {
-
-// Opaque handle to scheduler connection.
-struct ConnectionHandle {
- using Id = std::uintptr_t;
- static constexpr Id INVALID_ID = static_cast<Id>(-1);
-
- Id id = INVALID_ID;
-
- explicit operator bool() const { return id != INVALID_ID; }
-};
-
-inline bool operator==(ConnectionHandle lhs, ConnectionHandle rhs) {
- return lhs.id == rhs.id;
-}
-
-} // namespace android::scheduler
-
-namespace std {
-
-template <>
-struct hash<android::scheduler::ConnectionHandle> {
- size_t operator()(android::scheduler::ConnectionHandle handle) const {
- return hash<android::scheduler::ConnectionHandle::Id>()(handle.id);
- }
-};
-
-} // namespace std
-
namespace android {
class FenceTime;
@@ -106,6 +77,11 @@
class VsyncConfiguration;
class VsyncSchedule;
+enum class Cycle {
+ Render, // Surface rendering.
+ LastComposite // Ahead of display compositing by one refresh period.
+};
+
class Scheduler : public IEventThreadCallback, android::impl::MessageQueue {
using Impl = android::impl::MessageQueue;
@@ -133,9 +109,9 @@
void initVsync(frametimeline::TokenManager&, std::chrono::nanoseconds workDuration);
- using Impl::getScheduledFrameTime;
using Impl::setDuration;
+ using Impl::getScheduledFrameResult;
using Impl::scheduleConfigure;
using Impl::scheduleFrame;
@@ -154,36 +130,34 @@
return std::move(future);
}
- enum class Cycle {
- Render, // Surface rendering.
- LastComposite // Ahead of display compositing by one refresh period.
- };
-
- ConnectionHandle createEventThread(Cycle, frametimeline::TokenManager*,
- std::chrono::nanoseconds workDuration,
- std::chrono::nanoseconds readyDuration);
+ void createEventThread(Cycle, frametimeline::TokenManager*,
+ std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration);
sp<IDisplayEventConnection> createDisplayEventConnection(
- ConnectionHandle, EventRegistrationFlags eventRegistration = {},
+ Cycle, EventRegistrationFlags eventRegistration = {},
const sp<IBinder>& layerHandle = nullptr) EXCLUDES(mChoreographerLock);
- sp<EventThreadConnection> getEventConnection(ConnectionHandle);
+ const sp<EventThreadConnection>& getEventConnection(Cycle cycle) const {
+ return cycle == Cycle::Render ? mRenderEventConnection : mLastCompositeEventConnection;
+ }
- void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
- void onHotplugConnectionError(ConnectionHandle, int32_t errorCode);
+ enum class Hotplug { Connected, Disconnected };
+ void dispatchHotplug(PhysicalDisplayId, Hotplug);
- void onPrimaryDisplayModeChanged(ConnectionHandle, const FrameRateMode&) EXCLUDES(mPolicyLock);
- void onNonPrimaryDisplayModeChanged(ConnectionHandle, const FrameRateMode&);
+ void dispatchHotplugError(int32_t errorCode);
+
+ void onPrimaryDisplayModeChanged(Cycle, const FrameRateMode&) EXCLUDES(mPolicyLock);
+ void onNonPrimaryDisplayModeChanged(Cycle, const FrameRateMode&);
void enableSyntheticVsync(bool = true) REQUIRES(kMainThreadContext);
- void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId)
- EXCLUDES(mConnectionsLock);
+ void onFrameRateOverridesChanged(Cycle, PhysicalDisplayId);
- void onHdcpLevelsChanged(ConnectionHandle, PhysicalDisplayId, int32_t, int32_t);
+ void onHdcpLevelsChanged(Cycle, PhysicalDisplayId, int32_t, int32_t);
// Modifies work duration in the event thread.
- void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
+ void setDuration(Cycle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration);
VsyncModulator& vsyncModulator() { return *mVsyncModulator; }
@@ -288,7 +262,7 @@
bool isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const;
void dump(utils::Dumper&) const;
- void dump(ConnectionHandle, std::string&) const;
+ void dump(Cycle, std::string&) const;
void dumpVsync(std::string&) const EXCLUDES(mDisplayLock);
// Returns the preferred refresh rate and frame rate for the pacesetter display.
@@ -369,8 +343,15 @@
void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override
REQUIRES(kMainThreadContext, mDisplayLock);
- // Create a connection on the given EventThread.
- ConnectionHandle createConnection(std::unique_ptr<EventThread>);
+ // Used to skip event dispatch before EventThread creation during boot.
+ // TODO: b/241285191 - Reorder Scheduler initialization to avoid this.
+ bool hasEventThreads() const {
+ return CC_LIKELY(mRenderEventThread && mLastCompositeEventThread);
+ }
+
+ EventThread& eventThreadFor(Cycle cycle) const {
+ return *(cycle == Cycle::Render ? mRenderEventThread : mLastCompositeEventThread);
+ }
// Update feature state machine to given state when corresponding timer resets or expires.
void kernelIdleTimerCallback(TimerState) EXCLUDES(mDisplayLock);
@@ -460,18 +441,11 @@
void resync() override EXCLUDES(mDisplayLock);
void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock);
- // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
- struct Connection {
- sp<EventThreadConnection> connection;
- std::unique_ptr<EventThread> thread;
- };
+ std::unique_ptr<EventThread> mRenderEventThread;
+ sp<EventThreadConnection> mRenderEventConnection;
- ConnectionHandle::Id mNextConnectionHandleId = 0;
- mutable std::mutex mConnectionsLock;
- std::unordered_map<ConnectionHandle, Connection> mConnections GUARDED_BY(mConnectionsLock);
-
- ConnectionHandle mAppConnectionHandle;
- ConnectionHandle mSfConnectionHandle;
+ std::unique_ptr<EventThread> mLastCompositeEventThread;
+ sp<EventThreadConnection> mLastCompositeEventConnection;
std::atomic<nsecs_t> mLastResyncTime = 0;
@@ -585,7 +559,7 @@
ftl::Optional<FrameRateMode> modeOpt;
struct ModeChangedParams {
- ConnectionHandle handle;
+ Cycle cycle;
FrameRateMode mode;
};
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index ed8f8fe..0c43ffb 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -21,11 +21,15 @@
#include <string>
#include <ftl/mixins.h>
+#include <scheduler/Time.h>
#include <utils/Timers.h>
namespace android::scheduler {
-using ScheduleResult = std::optional<nsecs_t>;
+struct ScheduleResult {
+ TimePoint callbackTime;
+ TimePoint vsyncTime;
+};
enum class CancelResult { Cancelled, TooLate, Error };
@@ -124,10 +128,12 @@
*
* \param [in] token The callback to schedule.
* \param [in] scheduleTiming The timing information for this schedule call
- * \return The expected callback time if a callback was scheduled.
+ * \return The expected callback time if a callback was scheduled,
+ * along with VSYNC time for the callback scheduled.
* std::nullopt if the callback is not registered.
*/
- virtual ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) = 0;
+ virtual std::optional<ScheduleResult> schedule(CallbackToken token,
+ ScheduleTiming scheduleTiming) = 0;
/*
* Update the timing information for a scheduled callback.
@@ -135,10 +141,12 @@
*
* \param [in] token The callback to schedule.
* \param [in] scheduleTiming The timing information for this schedule call
- * \return The expected callback time if a callback was scheduled.
+ * \return The expected callback time if a callback was scheduled,
+ * along with VSYNC time for the callback scheduled.
* std::nullopt if the callback is not registered.
*/
- virtual ScheduleResult update(CallbackToken token, ScheduleTiming scheduleTiming) = 0;
+ virtual std::optional<ScheduleResult> update(CallbackToken token,
+ ScheduleTiming scheduleTiming) = 0;
/* Cancels a scheduled callback, if possible.
*
@@ -168,10 +176,10 @@
VSyncCallbackRegistration& operator=(VSyncCallbackRegistration&&);
// See documentation for VSyncDispatch::schedule.
- ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming);
+ std::optional<ScheduleResult> schedule(VSyncDispatch::ScheduleTiming scheduleTiming);
// See documentation for VSyncDispatch::update.
- ScheduleResult update(VSyncDispatch::ScheduleTiming scheduleTiming);
+ std::optional<ScheduleResult> update(VSyncDispatch::ScheduleTiming scheduleTiming);
// See documentation for VSyncDispatch::cancel.
CancelResult cancel();
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index b92fa24..84ccf8e 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -38,9 +38,10 @@
namespace {
-nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime,
- const VSyncDispatch::ScheduleTiming& timing) {
- return nextVsyncTime - timing.readyDuration - timing.workDuration;
+ScheduleResult getExpectedCallbackTime(nsecs_t nextVsyncTime,
+ const VSyncDispatch::ScheduleTiming& timing) {
+ return {TimePoint::fromNs(nextVsyncTime - timing.readyDuration - timing.workDuration),
+ TimePoint::fromNs(nextVsyncTime)};
}
} // namespace
@@ -115,14 +116,15 @@
auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
mScheduleTiming = timing;
mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
- return nextWakeupTime;
+ return ScheduleResult{TimePoint::fromNs(nextWakeupTime), TimePoint::fromNs(nextVsyncTime)};
}
-nsecs_t VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
+ScheduleResult VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
VSyncTracker& tracker, nsecs_t now, VSyncDispatch::ScheduleTiming timing) {
mWorkloadUpdateInfo = timing;
const auto armedInfo = update(tracker, now, timing, mArmedInfo);
- return armedInfo.mActualWakeupTime;
+ return {TimePoint::fromNs(armedInfo.mActualWakeupTime),
+ TimePoint::fromNs(armedInfo.mActualVsyncTime)};
}
bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
@@ -383,14 +385,14 @@
}
}
-ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
- ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncDispatchTimerQueue::schedule(CallbackToken token,
+ ScheduleTiming scheduleTiming) {
std::lock_guard lock(mMutex);
return scheduleLocked(token, scheduleTiming);
}
-ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
- ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncDispatchTimerQueue::scheduleLocked(
+ CallbackToken token, ScheduleTiming scheduleTiming) {
auto it = mCallbacks.find(token);
if (it == mCallbacks.end()) {
return {};
@@ -405,10 +407,7 @@
return callback->addPendingWorkloadUpdate(*mTracker, now, scheduleTiming);
}
- const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);
- if (!result.has_value()) {
- return {};
- }
+ const auto result = callback->schedule(scheduleTiming, *mTracker, now);
if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
rearmTimerSkippingUpdateFor(now, it);
@@ -417,7 +416,8 @@
return result;
}
-ScheduleResult VSyncDispatchTimerQueue::update(CallbackToken token, ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncDispatchTimerQueue::update(CallbackToken token,
+ ScheduleTiming scheduleTiming) {
std::lock_guard lock(mMutex);
const auto it = mCallbacks.find(token);
if (it == mCallbacks.end()) {
@@ -494,14 +494,16 @@
if (mToken) mDispatch->unregisterCallback(*mToken);
}
-ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncCallbackRegistration::schedule(
+ VSyncDispatch::ScheduleTiming scheduleTiming) {
if (!mToken) {
return std::nullopt;
}
return mDispatch->schedule(*mToken, scheduleTiming);
}
-ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncCallbackRegistration::update(
+ VSyncDispatch::ScheduleTiming scheduleTiming) {
if (!mToken) {
return std::nullopt;
}
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index b5ddd25..252c09c 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -69,7 +69,8 @@
// Adds a pending upload of the earliestVSync and workDuration that will be applied on the next
// call to update()
- nsecs_t addPendingWorkloadUpdate(VSyncTracker&, nsecs_t now, VSyncDispatch::ScheduleTiming);
+ ScheduleResult addPendingWorkloadUpdate(VSyncTracker&, nsecs_t now,
+ VSyncDispatch::ScheduleTiming);
// Checks if there is a pending update to the workload, returning true if so.
bool hasPendingWorkloadUpdate() const;
@@ -128,8 +129,8 @@
CallbackToken registerCallback(Callback, std::string callbackName) final;
void unregisterCallback(CallbackToken) final;
- ScheduleResult schedule(CallbackToken, ScheduleTiming) final;
- ScheduleResult update(CallbackToken, ScheduleTiming) final;
+ std::optional<ScheduleResult> schedule(CallbackToken, ScheduleTiming) final;
+ std::optional<ScheduleResult> update(CallbackToken, ScheduleTiming) final;
CancelResult cancel(CallbackToken) final;
void dump(std::string&) const final;
@@ -147,7 +148,7 @@
void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::const_iterator skipUpdate)
REQUIRES(mMutex);
void cancelTimer() REQUIRES(mMutex);
- ScheduleResult scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex);
+ std::optional<ScheduleResult> scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex);
std::mutex mutable mMutex;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 84956d0..85bdc1c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -233,31 +233,25 @@
}
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 @@
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);
@@ -893,7 +886,6 @@
// the DisplayDevice, hence the above commit of the primary display. Remove that special case by
// initializing the Scheduler after configureLocked, once decoupled from DisplayDevice.
initScheduler(display);
- dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
mLayerTracing.setTakeLayersSnapshotProtoFunction([&](uint32_t traceFlags) {
auto snapshot = perfetto::protos::LayersSnapshotProto{};
@@ -1763,7 +1755,7 @@
}
display->overrideHdrTypes(hdrTypes);
- dispatchDisplayHotplugEvent(display->getPhysicalId(), true /* connected */);
+ mScheduler->dispatchHotplug(display->getPhysicalId(), scheduler::Scheduler::Hotplug::Connected);
return NO_ERROR;
}
@@ -2092,12 +2084,11 @@
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
gui::ISurfaceComposer::VsyncSource vsyncSource, EventRegistrationFlags eventRegistration,
const sp<IBinder>& layerHandle) {
- const auto& handle =
- vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger
- ? mSfConnectionHandle
- : mAppConnectionHandle;
+ const auto cycle = vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger
+ ? scheduler::Cycle::LastComposite
+ : scheduler::Cycle::Render;
- return mScheduler->createDisplayEventConnection(handle, eventRegistration, layerHandle);
+ return mScheduler->createDisplayEventConnection(cycle, eventRegistration, layerHandle);
}
void SurfaceFlinger::scheduleCommit(FrameHint hint) {
@@ -2136,10 +2127,9 @@
vsyncPeriod.has_value()) {
// use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32
if (mIsHotplugErrViaNegVsync && vsyncPeriod.value() == ~0) {
- const int32_t hotplugErrorCode = static_cast<int32_t>(-timestamp);
- ALOGD("SurfaceFlinger got hotplugErrorCode=%d for display %" PRIu64, hotplugErrorCode,
- hwcDisplayId);
- mScheduler->onHotplugConnectionError(mAppConnectionHandle, hotplugErrorCode);
+ const auto errorCode = static_cast<int32_t>(-timestamp);
+ ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId);
+ mScheduler->dispatchHotplugError(errorCode);
return;
}
@@ -2148,8 +2138,7 @@
// one byte is good enough to encode android.hardware.drm.HdcpLevel
const int32_t maxLevel = (value >> 8) & 0xFF;
const int32_t connectedLevel = value & 0xFF;
- ALOGD("SurfaceFlinger got HDCP level changed: connected=%d, max=%d for "
- "display=%" PRIu64,
+ ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for display %" PRIu64, __func__,
connectedLevel, maxLevel, hwcDisplayId);
updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel);
return;
@@ -2188,9 +2177,10 @@
}
if (FlagManager::getInstance().hotplug2()) {
- ALOGD("SurfaceFlinger got hotplug event=%d", static_cast<int32_t>(event));
// TODO(b/311403559): use enum type instead of int
- mScheduler->onHotplugConnectionError(mAppConnectionHandle, static_cast<int32_t>(event));
+ const auto errorCode = static_cast<int32_t>(event);
+ ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId);
+ mScheduler->dispatchHotplugError(errorCode);
}
}
@@ -2759,7 +2749,11 @@
// TODO(b/255601557) Update frameInterval per display
refreshArgs.frameInterval =
mScheduler->getNextFrameInterval(pacesetterId, pacesetterTarget.expectedPresentTime());
- refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
+ const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+ const auto scheduledFrameTimeOpt = scheduledFrameResultOpt
+ ? std::optional{scheduledFrameResultOpt->callbackTime}
+ : std::nullopt;
+ refreshArgs.scheduledFrameTime = scheduledFrameTimeOpt;
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
@@ -3480,9 +3474,8 @@
if (!activeMode) {
ALOGE("Failed to hotplug display %s", to_string(displayId).c_str());
if (FlagManager::getInstance().hotplug2()) {
- mScheduler->onHotplugConnectionError(mAppConnectionHandle,
- static_cast<int32_t>(
- DisplayHotplugEvent::ERROR_UNKNOWN));
+ mScheduler->dispatchHotplugError(
+ static_cast<int32_t>(DisplayHotplugEvent::ERROR_UNKNOWN));
}
getHwComposer().disconnectDisplay(displayId);
return nullptr;
@@ -3532,11 +3525,6 @@
return "Connecting";
}
-void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
- mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected);
- mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected);
-}
-
void SurfaceFlinger::dispatchDisplayModeChangeEvent(PhysicalDisplayId displayId,
const scheduler::FrameRateMode& mode) {
// TODO(b/255635821): Merge code paths and move to Scheduler.
@@ -3544,7 +3532,7 @@
? &scheduler::Scheduler::onPrimaryDisplayModeChanged
: &scheduler::Scheduler::onNonPrimaryDisplayModeChanged;
- ((*mScheduler).*onDisplayModeChanged)(mAppConnectionHandle, mode);
+ ((*mScheduler).*onDisplayModeChanged)(scheduler::Cycle::Render, mode);
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
@@ -3571,10 +3559,10 @@
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};
@@ -3725,16 +3713,11 @@
displaySurface, producer);
if (mScheduler && !display->isVirtual()) {
- const auto displayId = display->getPhysicalId();
- {
- // TODO(b/241285876): Annotate `processDisplayAdded` instead.
- ftl::FakeGuard guard(kMainThreadContext);
+ // TODO(b/241285876): Annotate `processDisplayAdded` instead.
+ ftl::FakeGuard guard(kMainThreadContext);
- // For hotplug reconnect, renew the registration since display modes have been reloaded.
- mScheduler->registerDisplay(displayId, display->holdRefreshRateSelector());
- }
-
- dispatchDisplayHotplugEvent(displayId, true);
+ // For hotplug reconnect, renew the registration since display modes have been reloaded.
+ mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
}
if (display->isVirtual()) {
@@ -3773,7 +3756,6 @@
if (display->isVirtual()) {
releaseVirtualDisplay(display->getVirtualId());
} else {
- dispatchDisplayHotplugEvent(display->getPhysicalId(), false);
mScheduler->unregisterDisplay(display->getPhysicalId());
}
}
@@ -4196,7 +4178,7 @@
return getDefaultDisplayDeviceLocked()->getPhysicalId();
}();
- mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
+ mScheduler->onFrameRateOverridesChanged(scheduler::Cycle::Render, displayId);
}
void SurfaceFlinger::notifyCpuLoadUp() {
@@ -4258,7 +4240,8 @@
auto hintStatus = data.hintStatus.load();
if (!expectedPresentWithinTimeout) {
- if (hintStatus != NotifyExpectedPresentHintStatus::Sent ||
+ if ((hintStatus != NotifyExpectedPresentHintStatus::Sent &&
+ hintStatus != NotifyExpectedPresentHintStatus::ScheduleOnTx) ||
(timeoutOpt && timeoutOpt->ns() == 0)) {
// Send the hint immediately if timeout, as the hint gets
// delayed otherwise, as the frame is scheduled close
@@ -4267,11 +4250,16 @@
.compare_exchange_strong(hintStatus,
NotifyExpectedPresentHintStatus::ScheduleOnTx)) {
scheduleNotifyExpectedPresentHint(displayId);
+ return;
}
- return;
}
}
+ if (hintStatus == NotifyExpectedPresentHintStatus::Sent &&
+ data.hintStatus.compare_exchange_strong(hintStatus,
+ NotifyExpectedPresentHintStatus::ScheduleOnTx)) {
+ return;
+ }
if (hintStatus != NotifyExpectedPresentHintStatus::Start) {
return;
}
@@ -4279,7 +4267,8 @@
mScheduler->scheduleFrame();
}
-void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId,
+ VsyncId vsyncId) {
auto itr = mNotifyExpectedPresentMap.find(displayId);
if (itr == mNotifyExpectedPresentMap.end()) {
return;
@@ -4288,10 +4277,30 @@
const char* const whence = __func__;
const auto sendHint = [=, this]() {
auto& data = mNotifyExpectedPresentMap.at(displayId);
- data.hintStatus.store(NotifyExpectedPresentHintStatus::Sent);
- const auto status =
- getHwComposer().notifyExpectedPresent(displayId, data.lastExpectedPresentTimestamp,
- data.lastFrameInterval);
+ TimePoint expectedPresentTime = data.lastExpectedPresentTimestamp;
+ if (ftl::to_underlying(vsyncId) != FrameTimelineInfo::INVALID_VSYNC_ID) {
+ const auto predictionOpt = mFrameTimeline->getTokenManager()->getPredictionsForToken(
+ ftl::to_underlying(vsyncId));
+ const auto expectedPresentTimeOnPredictor = TimePoint::fromNs(
+ predictionOpt ? predictionOpt->presentTime : expectedPresentTime.ns());
+ const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+ const auto expectedPresentTimeOnScheduler = scheduledFrameResultOpt.has_value()
+ ? scheduledFrameResultOpt->vsyncTime
+ : TimePoint::fromNs(0);
+ expectedPresentTime =
+ std::max(expectedPresentTimeOnPredictor, expectedPresentTimeOnScheduler);
+ }
+
+ if (expectedPresentTime < TimePoint::now()) {
+ expectedPresentTime =
+ mScheduler->getVsyncSchedule()->vsyncDeadlineAfter(TimePoint::now());
+ if (mScheduler->vsyncModulator().getVsyncConfig().sfWorkDuration >
+ mScheduler->getVsyncSchedule(displayId)->period()) {
+ expectedPresentTime += mScheduler->getVsyncSchedule(displayId)->period();
+ }
+ }
+ const auto status = getHwComposer().notifyExpectedPresent(displayId, expectedPresentTime,
+ data.lastFrameInterval);
if (status != NO_ERROR) {
ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, whence,
displayId.value);
@@ -4309,7 +4318,11 @@
}
}));
}
- sendHint();
+ auto scheduleHintOnPresent = NotifyExpectedPresentHintStatus::ScheduleOnPresent;
+ if (itr->second.hintStatus.compare_exchange_strong(scheduleHintOnPresent,
+ NotifyExpectedPresentHintStatus::Sent)) {
+ sendHint();
+ }
}
void SurfaceFlinger::sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
@@ -4361,24 +4374,25 @@
mScheduler = std::make_unique<Scheduler>(static_cast<ICompositor&>(*this),
static_cast<ISchedulerCallback&>(*this), features,
getFactory(), activeRefreshRate, *mTimeStats);
+
+ // The pacesetter must be registered before EventThread creation below.
mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
if (FlagManager::getInstance().vrr_config()) {
mScheduler->setRenderRate(display->getPhysicalId(), activeMode.fps);
}
- mScheduler->startTimers();
const auto configs = mScheduler->getVsyncConfiguration().getCurrentConfigs();
- mAppConnectionHandle =
- mScheduler->createEventThread(Scheduler::Cycle::Render,
- mFrameTimeline->getTokenManager(),
- /* workDuration */ configs.late.appWorkDuration,
- /* readyDuration */ configs.late.sfWorkDuration);
- mSfConnectionHandle =
- mScheduler->createEventThread(Scheduler::Cycle::LastComposite,
- mFrameTimeline->getTokenManager(),
- /* workDuration */ activeRefreshRate.getPeriod(),
- /* readyDuration */ configs.late.sfWorkDuration);
+ mScheduler->createEventThread(scheduler::Cycle::Render, mFrameTimeline->getTokenManager(),
+ /* workDuration */ configs.late.appWorkDuration,
+ /* readyDuration */ configs.late.sfWorkDuration);
+ mScheduler->createEventThread(scheduler::Cycle::LastComposite,
+ mFrameTimeline->getTokenManager(),
+ /* workDuration */ activeRefreshRate.getPeriod(),
+ /* readyDuration */ configs.late.sfWorkDuration);
+
+ // Dispatch after EventThread creation, since registerDisplay above skipped dispatch.
+ mScheduler->dispatchHotplug(display->getPhysicalId(), scheduler::Scheduler::Hotplug::Connected);
mScheduler->initVsync(*mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration);
@@ -4386,6 +4400,9 @@
sp<RegionSamplingThread>::make(*this,
RegionSamplingThread::EnvironmentTimingTunables());
mFpsReporter = sp<FpsReporter>::make(*mFrameTimeline);
+
+ // Timer callbacks may fire, so do this last.
+ mScheduler->startTimers();
}
void SurfaceFlinger::doCommitTransactions() {
@@ -5112,6 +5129,11 @@
const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;
mTransactionHandler.queueTransaction(std::move(state));
+ for (const auto& [displayId, data] : mNotifyExpectedPresentMap) {
+ if (data.hintStatus.load() == NotifyExpectedPresentHintStatus::ScheduleOnTx) {
+ scheduleNotifyExpectedPresentHint(displayId, VsyncId{frameTimelineInfo.vsyncId});
+ }
+ }
setTransactionFlags(eTransactionFlushNeeded, schedule, applyToken, frameHint);
return NO_ERROR;
}
@@ -6322,7 +6344,7 @@
}
void SurfaceFlinger::dumpEvents(std::string& result) const {
- mScheduler->dump(mAppConnectionHandle, result);
+ mScheduler->dump(scheduler::Cycle::Render, result);
}
void SurfaceFlinger::dumpVsync(std::string& result) const {
@@ -7094,14 +7116,15 @@
mForceFullDamage = n != 0;
return NO_ERROR;
}
- case 1018: { // Modify Choreographer's duration
+ case 1018: { // Set the render deadline as a duration until VSYNC.
n = data.readInt32();
- mScheduler->setDuration(mAppConnectionHandle, std::chrono::nanoseconds(n), 0ns);
+ mScheduler->setDuration(scheduler::Cycle::Render, std::chrono::nanoseconds(n), 0ns);
return NO_ERROR;
}
- case 1019: { // Modify SurfaceFlinger's duration
+ case 1019: { // Set the deadline of the last composite as a duration until VSYNC.
n = data.readInt32();
- mScheduler->setDuration(mSfConnectionHandle, std::chrono::nanoseconds(n), 0ns);
+ mScheduler->setDuration(scheduler::Cycle::LastComposite,
+ std::chrono::nanoseconds(n), 0ns);
return NO_ERROR;
}
case 1020: { // Unused
@@ -7333,7 +7356,7 @@
auto inUid = static_cast<uid_t>(data.readInt32());
const auto refreshRate = data.readFloat();
mScheduler->setPreferredRefreshRateForUid(FrameRateOverride{inUid, refreshRate});
- mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
+ mScheduler->onFrameRateOverridesChanged(scheduler::Cycle::Render, displayId);
return NO_ERROR;
}
// Toggle caching feature
@@ -7691,7 +7714,7 @@
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
@@ -8479,10 +8502,10 @@
// TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
// be depending in this callback.
if (const auto activeMode = selector.getActiveMode(); displayId == mActiveDisplayId) {
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
+ mScheduler->onPrimaryDisplayModeChanged(scheduler::Cycle::Render, activeMode);
toggleKernelIdleTimer();
} else {
- mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
+ mScheduler->onNonPrimaryDisplayModeChanged(scheduler::Cycle::Render, activeMode);
}
auto preferredModeOpt = getPreferredDisplayMode(displayId, currentPolicy.defaultMode);
@@ -8670,7 +8693,7 @@
}();
mScheduler->setGameModeFrameRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate});
- mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
+ mScheduler->onFrameRateOverridesChanged(scheduler::Cycle::Render, displayId);
return NO_ERROR;
}
@@ -8826,7 +8849,11 @@
return;
}
- mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime());
+ const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+ const auto scheduleFrameTimeOpt = scheduledFrameResultOpt
+ ? std::optional{scheduledFrameResultOpt->callbackTime}
+ : std::nullopt;
+ mRegionSamplingThread->onCompositionComplete(scheduleFrameTimeOpt);
}
void SurfaceFlinger::onActiveDisplaySizeChanged(const DisplayDevice& activeDisplay) {
@@ -8932,7 +8959,8 @@
Mutex::Autolock lock(mStateLock);
display->setSecure(connectedLevel >= 2 /* HDCP_V1 */);
}
- mScheduler->onHdcpLevelsChanged(mAppConnectionHandle, displayId, connectedLevel, maxLevel);
+ mScheduler->onHdcpLevelsChanged(scheduler::Cycle::Render, displayId, connectedLevel,
+ maxLevel);
}));
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index fdeede1..1ce8606 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1054,7 +1054,6 @@
const DisplayDeviceState& drawingState)
REQUIRES(mStateLock, kMainThreadContext);
- void dispatchDisplayHotplugEvent(PhysicalDisplayId, bool connected);
void dispatchDisplayModeChangeEvent(PhysicalDisplayId, const scheduler::FrameRateMode&)
REQUIRES(mStateLock);
@@ -1360,12 +1359,7 @@
const std::string mHwcServiceName;
- /*
- * Scheduler
- */
std::unique_ptr<scheduler::Scheduler> mScheduler;
- scheduler::ConnectionHandle mAppConnectionHandle;
- scheduler::ConnectionHandle mSfConnectionHandle;
scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext);
@@ -1504,7 +1498,9 @@
std::unordered_map<PhysicalDisplayId, NotifyExpectedPresentData> mNotifyExpectedPresentMap;
void sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) override
REQUIRES(kMainThreadContext);
- void scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId);
+ void scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId,
+ VsyncId vsyncId = VsyncId{
+ FrameTimelineInfo::INVALID_VSYNC_ID});
void notifyExpectedPresentIfRequired(PhysicalDisplayId, Period vsyncPeriod,
TimePoint expectedPresentTime, Fps frameInterval,
std::optional<Period> timeoutOpt);
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index f7adc0e..b7f06a9 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -131,6 +131,7 @@
DUMP_READ_ONLY_FLAG(renderable_buffer_usage);
DUMP_READ_ONLY_FLAG(restore_blur_step);
DUMP_READ_ONLY_FLAG(dont_skip_on_early_ro);
+ DUMP_READ_ONLY_FLAG(protected_if_client);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
#undef DUMP_FLAG_INTERVAL
@@ -210,6 +211,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(renderable_buffer_usage, "")
FLAG_MANAGER_READ_ONLY_FLAG(restore_blur_step, "debug.renderengine.restore_blur_step")
FLAG_MANAGER_READ_ONLY_FLAG(dont_skip_on_early_ro, "")
+FLAG_MANAGER_READ_ONLY_FLAG(protected_if_client, "")
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 18f623f..241c814 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -71,6 +71,7 @@
bool renderable_buffer_usage() const;
bool restore_blur_step() const;
bool dont_skip_on_early_ro() const;
+ bool protected_if_client() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index f5ec1ee..c8f4218 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -189,6 +189,13 @@
namespace: "core_graphics"
description: "This flag is guarding the behaviour where SurfaceFlinger is trying to opportunistically present a frame when the configuration change from late to early"
bug: "273702768"
+}
+
+flag {
+ name: "protected_if_client"
+ namespace: "core_graphics"
+ description: "Only set the RenderSurface to protected if protected layers are in client composition."
+ bug: "307674749"
is_fixed_read_only: true
metadata {
purpose: PURPOSE_BUGFIX
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index d5ec654..3eabe1f 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -117,14 +117,16 @@
mThread->onVsync(expectedPresentationTime, timestamp, deadlineTimestamp);
}
+ static constexpr scheduler::ScheduleResult kScheduleResult{TimePoint::fromNs(0),
+ TimePoint::fromNs(0)};
AsyncCallRecorderWithCannedReturn<
scheduler::ScheduleResult (*)(scheduler::VSyncDispatch::CallbackToken,
scheduler::VSyncDispatch::ScheduleTiming)>
- mVSyncCallbackScheduleRecorder{0};
+ mVSyncCallbackScheduleRecorder{kScheduleResult};
AsyncCallRecorderWithCannedReturn<
scheduler::ScheduleResult (*)(scheduler::VSyncDispatch::CallbackToken,
scheduler::VSyncDispatch::ScheduleTiming)>
- mVSyncCallbackUpdateRecorder{0};
+ mVSyncCallbackUpdateRecorder{kScheduleResult};
AsyncCallRecorderWithCannedReturn<
scheduler::VSyncDispatch::CallbackToken (*)(scheduler::VSyncDispatch::Callback,
std::string)>
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index f5661fc..71f9f88 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -25,6 +25,7 @@
#include "FrameTimeline.h"
#include "Scheduler/MessageQueue.h"
#include "mock/MockVSyncDispatch.h"
+#include "utils/Timers.h"
namespace android {
@@ -49,6 +50,8 @@
using MessageQueue::Handler::Handler;
MOCK_METHOD(void, dispatchFrame, (VsyncId, TimePoint), (override));
+ MOCK_METHOD(bool, isFramePending, (), (const, override));
+ MOCK_METHOD(TimePoint, getExpectedVsyncTime, (), (const override));
};
explicit TestableMessageQueue(sp<MockHandler> handler)
@@ -94,13 +97,17 @@
const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
.readyDuration = 0,
.lastVsync = 0};
- EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
+ EXPECT_FALSE(mEventQueue.getScheduledFrameResult());
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
+ const auto timePoint = TimePoint::fromNs(1234);
+ const auto scheduleResult = scheduler::ScheduleResult{timePoint, timePoint};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
- ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
- EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
+ const auto scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_EQ(1234, scheduledFrameResult->callbackTime.ns());
+ EXPECT_EQ(1234, scheduledFrameResult->vsyncTime.ns());
}
TEST_F(MessageQueueTest, commitTwice) {
@@ -109,17 +116,25 @@
.readyDuration = 0,
.lastVsync = 0};
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
+ auto timePoint = TimePoint::fromNs(1234);
+ auto scheduleResult = scheduler::ScheduleResult{timePoint, timePoint};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
- ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
- EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
+ auto scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_EQ(1234, scheduledFrameResult->callbackTime.ns());
+ EXPECT_EQ(1234, scheduledFrameResult->vsyncTime.ns());
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567));
+ timePoint = TimePoint::fromNs(4567);
+ scheduleResult = scheduler::ScheduleResult{timePoint, timePoint};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
- ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
- EXPECT_EQ(4567, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
+ scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_EQ(4567, scheduledFrameResult->callbackTime.ns());
+ EXPECT_EQ(4567, scheduledFrameResult->vsyncTime.ns());
}
TEST_F(MessageQueueTest, commitTwiceWithCallback) {
@@ -128,11 +143,15 @@
.readyDuration = 0,
.lastVsync = 0};
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
+ const auto timePoint = TimePoint::fromNs(1234);
+ auto scheduleResult = scheduler::ScheduleResult{timePoint, timePoint};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
- ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
- EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
+ auto scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_EQ(1234, scheduledFrameResult->callbackTime.ns());
+ EXPECT_EQ(1234, scheduledFrameResult->vsyncTime.ns());
constexpr TimePoint kStartTime = TimePoint::fromNs(100);
constexpr TimePoint kEndTime = kStartTime + kDuration;
@@ -148,14 +167,15 @@
EXPECT_NO_FATAL_FAILURE(
mEventQueue.vsyncCallback(kPresentTime.ns(), kStartTime.ns(), kEndTime.ns()));
- EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
+ EXPECT_FALSE(mEventQueue.getScheduledFrameResult());
const auto timingAfterCallback =
scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
.readyDuration = 0,
.lastVsync = kPresentTime.ns()};
-
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0));
+ scheduleResult = scheduler::ScheduleResult{TimePoint::fromNs(0), TimePoint::fromNs(0)};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback))
+ .WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
}
@@ -167,9 +187,24 @@
.readyDuration = 0,
.lastVsync = 0};
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0));
+ const auto scheduleResult =
+ scheduler::ScheduleResult{TimePoint::fromNs(0), TimePoint::fromNs(0)};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
}
+TEST_F(MessageQueueTest, scheduleResultWhenFrameIsPending) {
+ const auto timePoint = TimePoint::now();
+ EXPECT_CALL(*mEventQueue.mHandler, isFramePending()).WillOnce(Return(true));
+ EXPECT_CALL(*mEventQueue.mHandler, getExpectedVsyncTime()).WillRepeatedly(Return(timePoint));
+
+ const auto scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_NEAR(static_cast<double>(TimePoint::now().ns()),
+ static_cast<double>(scheduledFrameResult->callbackTime.ns()), ms2ns(1));
+ EXPECT_EQ(timePoint, scheduledFrameResult->vsyncTime);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index b059525..10e2220 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -99,7 +99,6 @@
TestableScheduler* mScheduler = new TestableScheduler{mSelector, mFlinger, mSchedulerCallback};
surfaceflinger::frontend::LayerHierarchyBuilder mLayerHierarchyBuilder;
- ConnectionHandle mConnectionHandle;
MockEventThread* mEventThread;
sp<MockEventThreadConnection> mEventThreadConnection;
};
@@ -116,54 +115,13 @@
EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection(std::move(eventThread));
- EXPECT_TRUE(mConnectionHandle);
+ mScheduler->setEventThread(Cycle::Render, std::move(eventThread));
mFlinger.resetScheduler(mScheduler);
}
} // namespace
-TEST_F(SchedulerTest, invalidConnectionHandle) {
- ConnectionHandle handle;
-
- const sp<IDisplayEventConnection> connection = mScheduler->createDisplayEventConnection(handle);
-
- EXPECT_FALSE(connection);
- EXPECT_FALSE(mScheduler->getEventConnection(handle));
-
- // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
- EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
- mScheduler->onHotplugReceived(handle, kDisplayId1, false);
-
- std::string output;
- EXPECT_CALL(*mEventThread, dump(_)).Times(0);
- mScheduler->dump(handle, output);
- EXPECT_TRUE(output.empty());
-
- EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(0);
- mScheduler->setDuration(handle, 10ns, 20ns);
-}
-
-TEST_F(SchedulerTest, validConnectionHandle) {
- const sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle);
-
- ASSERT_EQ(mEventThreadConnection, connection);
- EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle));
-
- EXPECT_CALL(*mEventThread, onHotplugReceived(kDisplayId1, false)).Times(1);
- mScheduler->onHotplugReceived(mConnectionHandle, kDisplayId1, false);
-
- std::string output("dump");
- EXPECT_CALL(*mEventThread, dump(output)).Times(1);
- mScheduler->dump(mConnectionHandle, output);
- EXPECT_FALSE(output.empty());
-
- EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(1);
- mScheduler->setDuration(mConnectionHandle, 10ns, 20ns);
-}
-
TEST_F(SchedulerTest, registerDisplay) FTL_FAKE_GUARD(kMainThreadContext) {
// Hardware VSYNC should not change if the display is already registered.
EXPECT_CALL(mSchedulerCallback, requestHardwareVsync(kDisplayId1, false)).Times(0);
@@ -235,22 +193,6 @@
EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode());
}
-TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) {
- const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
- .setId(DisplayModeId(111))
- .setPhysicalDisplayId(kDisplayId1)
- .setVsyncPeriod(111111)
- .build();
-
- // If the handle is incorrect, the function should return before
- // onModeChange is called.
- ConnectionHandle invalidHandle = {.id = 123};
- EXPECT_NO_FATAL_FAILURE(
- mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle,
- {90_Hz, ftl::as_non_null(mode)}));
- EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0);
-}
-
TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 30ms));
EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(90_Hz, 30ms));
@@ -753,7 +695,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
const sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer->getHandle());
EXPECT_EQ(1u, mScheduler->mutableAttachedChoreographers().size());
ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
@@ -782,9 +724,9 @@
.WillOnce(Return(mockConnection2));
const sp<IDisplayEventConnection> connection1 =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, handle);
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, handle);
const sp<IDisplayEventConnection> connection2 =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, handle);
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, handle);
EXPECT_EQ(1u, mScheduler->mutableAttachedChoreographers().size());
ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
@@ -802,9 +744,9 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached).Times(2);
const sp<IDisplayEventConnection> connection1 =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer1->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer1->getHandle());
const sp<IDisplayEventConnection> connection2 =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer2->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer2->getHandle());
EXPECT_EQ(2u, mScheduler->mutableAttachedChoreographers().size());
@@ -831,7 +773,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer->getHandle());
ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence()));
EXPECT_EQ(1u,
@@ -861,7 +803,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
const sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer->getHandle());
layer.clear();
mFlinger.mutableLayersPendingRemoval().clear();
@@ -875,7 +817,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer->getHandle());
RequestedLayerState layerState(LayerCreationArgs(layer->getSequence()));
LayerHierarchy hierarchy(&layerState);
@@ -935,7 +877,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, parent->getHandle());
RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
LayerHierarchy parentHierarchy(&parentState);
@@ -962,7 +904,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, parent->getHandle());
RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
LayerHierarchy parentHierarchy(&parentState);
@@ -997,7 +939,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, parent->getHandle());
RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
LayerHierarchy parentHierarchy(&parentState);
@@ -1031,7 +973,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer->getHandle());
RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
LayerHierarchy parentHierarchy(&parentState);
@@ -1057,7 +999,7 @@
EXPECT_CALL(mSchedulerCallback, onChoreographerAttached);
sp<IDisplayEventConnection> connection =
- mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle());
+ mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer->getHandle());
RequestedLayerState parentState(LayerCreationArgs(parent->getSequence()));
LayerHierarchy parentHierarchy(&parentState);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
index 91b9018..20a3315 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
@@ -41,6 +41,33 @@
}
protected:
+ void setTransactionState() {
+ ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
+ TransactionInfo transaction;
+ mFlinger.setTransactionState(FrameTimelineInfo{}, transaction.states, transaction.displays,
+ transaction.flags, transaction.applyToken,
+ transaction.inputWindowCommands,
+ TimePoint::now().ns() + s2ns(1), transaction.isAutoTimestamp,
+ transaction.unCachedBuffers,
+ /*HasListenerCallbacks=*/false, transaction.callbacks,
+ transaction.id, transaction.mergedTransactionIds);
+ }
+
+ struct TransactionInfo {
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
+ uint32_t flags = 0;
+ sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ InputWindowCommands inputWindowCommands;
+ int64_t desiredPresentTime = 0;
+ bool isAutoTimestamp = false;
+ FrameTimelineInfo frameTimelineInfo{};
+ std::vector<client_cache_t> unCachedBuffers;
+ uint64_t id = static_cast<uint64_t>(-1);
+ std::vector<uint64_t> mergedTransactionIds;
+ std::vector<ListenerCallbacks> callbacks;
+ };
+
struct Compositor final : ICompositor {
explicit Compositor(PhysicalDisplayId displayId, TestableSurfaceFlinger& surfaceFlinger)
: displayId(displayId), surfaceFlinger(surfaceFlinger) {}
@@ -102,7 +129,7 @@
};
TEST_F(NotifyExpectedPresentTest, noNotifyExpectedPresentHintCall_absentTimeout) {
- auto expectedPresentTime = systemTime() + ms2ns(10);
+ auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
ASSERT_NO_FATAL_FAILURE(
mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
TimePoint::fromNs(expectedPresentTime),
@@ -120,7 +147,7 @@
}
TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentHint_zeroTimeout) {
- auto expectedPresentTime = systemTime() + ms2ns(10);
+ auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
{
// Very first ExpectedPresent after idle, no previous timestamp.
EXPECT_CALL(*mComposer,
@@ -139,6 +166,10 @@
{
mCompositor->committed = false;
expectedPresentTime += kFrameInterval60HzNs;
+ EXPECT_CALL(static_cast<mock::VSyncTracker&>(
+ mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
+ nextAnticipatedVSyncTimeFrom(_, _))
+ .WillRepeatedly(Return(expectedPresentTime));
EXPECT_CALL(*mComposer,
notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
.WillOnce(Return(Error::NONE));
@@ -154,6 +185,10 @@
}
{
expectedPresentTime += kFrameInterval60HzNs;
+ EXPECT_CALL(static_cast<mock::VSyncTracker&>(
+ mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
+ nextAnticipatedVSyncTimeFrom(_, _))
+ .WillRepeatedly(Return(expectedPresentTime));
EXPECT_CALL(*mComposer,
notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
.WillOnce(Return(Error::NONE));
@@ -168,9 +203,8 @@
ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
}
}
-
TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentTimeout) {
- auto expectedPresentTime = systemTime() + ms2ns(10);
+ auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
{
// Very first ExpectedPresent after idle, no previous timestamp
mCompositor->committed = false;
@@ -185,6 +219,27 @@
ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
}
{
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ expectedPresentTime += 2 * kFrameInterval5HzNs;
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
+ {
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime,
+ kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ // Hint sent with the setTransactionState
+ setTransactionState();
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ }
+ }
+ {
// ExpectedPresentTime is after the timeoutNs
mCompositor->committed = true;
expectedPresentTime += 2 * kFrameInterval5HzNs;
@@ -194,7 +249,7 @@
kTimeoutNs);
EXPECT_TRUE(
mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
- ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
// Present happens notifyExpectedPresentHintStatus is Start
ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
@@ -259,7 +314,7 @@
}
TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentRenderRateChanged) {
- const auto now = systemTime();
+ const auto now = TimePoint::now().ns();
auto expectedPresentTime = now;
static constexpr Period kTimeoutNs = Period::fromNs(static_cast<Fps>(1_Hz).getPeriodNsecs());
@@ -298,6 +353,10 @@
TimePoint::fromNs(expectedPresentTime),
Fps::fromPeriodNsecs(frameIntervalNs), kTimeoutNs);
+ EXPECT_CALL(static_cast<mock::VSyncTracker&>(
+ mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
+ nextAnticipatedVSyncTimeFrom(_, _))
+ .WillRepeatedly(Return(expectedPresentTime));
if (callNotifyExpectedPresentHint) {
mCompositor->committed = false;
ASSERT_TRUE(mFlinger.verifyHintIsScheduledOnPresent(mPhysicalDisplayId))
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 25a85df..1472ebf 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -71,9 +71,14 @@
Scheduler::onFrameSignal(compositor, vsyncId, TimePoint());
}
- // Used to inject mock event thread.
- ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
- return Scheduler::createConnection(std::move(eventThread));
+ 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();
+ }
}
auto refreshRateSelector() { return pacesetterSelectorPtr(); }
@@ -124,7 +129,6 @@
using Scheduler::resyncAllToHardwareVsync;
- auto& mutableAppConnectionHandle() { return mAppConnectionHandle; }
auto& mutableLayerHistory() { return mLayerHistory; }
auto& mutableAttachedChoreographers() { return mAttachedChoreographers; }
@@ -180,10 +184,6 @@
mPolicy.cachedModeChangedParams.reset();
}
- void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) {
- Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
- }
-
void setInitialHwVsyncEnabled(PhysicalDisplayId id, bool enabled) {
auto schedule = getVsyncSchedule(id);
std::lock_guard<std::mutex> lock(schedule->mHwVsyncLock);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 46a079c..bce7729 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -258,11 +258,9 @@
mScheduler->initVsync(*mTokenManager, 0ms);
- mScheduler->mutableAppConnectionHandle() =
- mScheduler->createConnection(std::move(appEventThread));
+ mScheduler->setEventThread(scheduler::Cycle::Render, std::move(appEventThread));
+ mScheduler->setEventThread(scheduler::Cycle::LastComposite, std::move(sfEventThread));
- mFlinger->mAppConnectionHandle = mScheduler->mutableAppConnectionHandle();
- mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
resetScheduler(mScheduler);
}
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index eb4e84e..9b70d92 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -247,7 +247,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
}
}
@@ -260,7 +261,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = intended});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
@@ -279,12 +281,14 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = intended});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result =
mDispatch->update(cb, {.workDuration = 300, .readyDuration = 0, .lastVsync = intended});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(700, *result);
+ EXPECT_EQ(700, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
@@ -332,7 +336,8 @@
.readyDuration = 0,
.lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod, *result);
+ EXPECT_EQ(mPeriod, result->callbackTime.ns());
+ EXPECT_EQ(workDuration + mPeriod, result->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
@@ -344,7 +349,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod - 100, *result);
+ EXPECT_EQ(mPeriod - 100, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod, result->vsyncTime.ns());
EXPECT_EQ(mDispatch->cancel(cb), CancelResult::Cancelled);
}
@@ -357,7 +363,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod - 100, *result);
+ EXPECT_EQ(mPeriod - 100, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod, result->vsyncTime.ns());
mMockClock.advanceBy(950);
EXPECT_EQ(mDispatch->cancel(cb), CancelResult::TooLate);
}
@@ -371,7 +378,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod - 100, *result);
+ EXPECT_EQ(mPeriod - 100, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod, result->vsyncTime.ns());
std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
EXPECT_TRUE(cb.waitForPause());
@@ -392,7 +400,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod - 100, *result);
+ EXPECT_EQ(mPeriod - 100, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod, result->vsyncTime.ns());
std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
EXPECT_TRUE(cb.waitForPause());
@@ -625,19 +634,22 @@
.readyDuration = 0,
.lastVsync = timestamp - mVsyncMoveThreshold});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod + timestamp - 400, *result);
+ EXPECT_EQ(mPeriod + timestamp - 400, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod + timestamp, result->vsyncTime.ns());
result = mDispatch->schedule(tmp,
{.workDuration = 400,
.readyDuration = 0,
.lastVsync = timestamp});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod + timestamp - 400, *result);
+ EXPECT_EQ(mPeriod + timestamp - 400, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod + timestamp, result->vsyncTime.ns());
result = mDispatch->schedule(tmp,
{.workDuration = 400,
.readyDuration = 0,
.lastVsync = timestamp + mVsyncMoveThreshold});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod + timestamp - 400, *result);
+ EXPECT_EQ(mPeriod + timestamp - 400, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod + timestamp, result->vsyncTime.ns());
lastTarget = timestamp;
},
"oo");
@@ -726,10 +738,12 @@
auto result =
mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
}
// b/1450138150
@@ -741,12 +755,14 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(400);
result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1200, *result);
+ EXPECT_EQ(1200, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -763,12 +779,14 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(400);
result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(400, *result);
+ EXPECT_EQ(400, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -784,11 +802,13 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(400);
result = mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(602, *result);
+ EXPECT_EQ(602, result->callbackTime.ns());
+ EXPECT_EQ(1002, result->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
@@ -796,12 +816,14 @@
auto result =
mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
result =
mDispatch->schedule(cb0, {.workDuration = 1100, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
@@ -812,12 +834,14 @@
auto result =
mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
result =
mDispatch->schedule(cb0, {.workDuration = 1900, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1100, *result);
+ EXPECT_EQ(1100, result->callbackTime.ns());
+ EXPECT_EQ(3000, result->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
@@ -829,11 +853,13 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
advanceToNextCallback();
}
@@ -849,11 +875,13 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(0, *result);
+ EXPECT_EQ(0, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
}
@@ -899,14 +927,16 @@
auto result =
mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1900, *result);
+ EXPECT_EQ(1900, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
mMockClock.advanceBy(80);
EXPECT_THAT(cb1.mCalls.size(), Eq(1));
@@ -927,14 +957,16 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
result = mDispatch->schedule(cb, {.workDuration = 370, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1630, *result);
+ EXPECT_EQ(1630, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
mMockClock.advanceBy(80);
EXPECT_THAT(cb.mCalls.size(), Eq(1));
@@ -954,14 +986,16 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
result = mDispatch->schedule(cb, {.workDuration = 370, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(80);
ASSERT_EQ(1, cb.mCalls.size());
@@ -982,10 +1016,12 @@
auto result =
mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1900, *result);
+ EXPECT_EQ(1900, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
@@ -1009,10 +1045,12 @@
auto result =
mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1900, *result);
+ EXPECT_EQ(1900, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
@@ -1045,10 +1083,12 @@
auto result =
mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb2, {.workDuration = 390, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(610, *result);
+ EXPECT_EQ(610, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(700);
@@ -1072,7 +1112,8 @@
mDispatch->schedule(cb,
{.workDuration = 70, .readyDuration = 30, .lastVsync = intended});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -1138,12 +1179,14 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(300);
result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1200, *result);
+ EXPECT_EQ(1200, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -1159,12 +1202,14 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(300);
result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(300, *result);
+ EXPECT_EQ(300, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -1197,9 +1242,11 @@
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ const auto scheduleResult =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ EXPECT_EQ(900, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResult.vsyncTime.ns());
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
@@ -1220,9 +1267,11 @@
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_TRUE(entry.schedule({.workDuration = 500, .readyDuration = 0, .lastVsync = 994},
- *mStubTracker.get(), now)
- .has_value());
+ const auto scheduleResult =
+ entry.schedule({.workDuration = 500, .readyDuration = 0, .lastVsync = 994},
+ *mStubTracker, now);
+ EXPECT_EQ(9500, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(10000, scheduleResult.vsyncTime.ns());
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(9500));
@@ -1243,9 +1292,11 @@
},
mVsyncMoveThreshold);
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ const auto scheduleResult =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ EXPECT_EQ(900, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResult.vsyncTime.ns());
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
@@ -1275,17 +1326,19 @@
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
- entry.update(*mStubTracker.get(), 0);
+ entry.update(*mStubTracker, 0);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ const auto scheduleResult =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ EXPECT_EQ(900, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResult.vsyncTime.ns());
auto wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(wakeup, Eq(900));
- entry.update(*mStubTracker.get(), 0);
+ entry.update(*mStubTracker, 0);
wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(920));
@@ -1294,9 +1347,10 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
VSyncDispatchTimerQueueEntry entry(
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ EXPECT_EQ(900,
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker.get(), 0)
+ .callbackTime.ns());
entry.update(*mStubTracker.get(), 0);
auto const wakeup = entry.wakeupTime();
@@ -1307,26 +1361,32 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
VSyncDispatchTimerQueueEntry entry(
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ auto scheduleResult =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+
+ EXPECT_EQ(900, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResult.vsyncTime.ns());
entry.executing(); // 1000 is executing
// had 1000 not been executing, this could have been scheduled for time 800.
- EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ scheduleResult = entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ EXPECT_EQ(1800, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(2000, scheduleResult.vsyncTime.ns());
EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
EXPECT_THAT(*entry.readyTime(), Eq(2000));
- EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ scheduleResult = entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ EXPECT_EQ(1950, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(2000, scheduleResult.vsyncTime.ns());
EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
EXPECT_THAT(*entry.readyTime(), Eq(2000));
- EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 1001},
- *mStubTracker.get(), 0)
- .has_value());
+ scheduleResult = entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 1001},
+ *mStubTracker, 0);
+ EXPECT_EQ(1800, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(2000, scheduleResult.vsyncTime.ns());
EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
EXPECT_THAT(*entry.readyTime(), Eq(2000));
}
@@ -1349,32 +1409,48 @@
.InSequence(seq)
.WillOnce(Return(2000));
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ auto scheduleResult =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ EXPECT_EQ(900, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResult.vsyncTime.ns());
entry.executing(); // 1000 is executing
- EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ scheduleResult = entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ EXPECT_EQ(1800, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(2000, scheduleResult.vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
- VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
- EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
- EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
- EXPECT_TRUE(entry.schedule({.workDuration = 1200, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ VSyncDispatchTimerQueueEntry entry("test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_EQ(900,
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0)
+ .callbackTime.ns());
+ EXPECT_EQ(800,
+ entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0)
+ .callbackTime.ns());
+ EXPECT_EQ(950,
+ entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0)
+ .callbackTime.ns());
+ {
+ SET_FLAG_FOR_TEST(flags::dont_skip_on_early_ro, true);
+ EXPECT_EQ(0,
+ entry.schedule({.workDuration = 1200, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0)
+ .callbackTime.ns());
+ }
+ {
+ SET_FLAG_FOR_TEST(flags::dont_skip_on_early_ro, false);
+ EXPECT_EQ(800,
+ entry.schedule({.workDuration = 1200, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0)
+ .callbackTime.ns());
+ }
}
TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdateAndDontSkip) {
@@ -1389,7 +1465,7 @@
.readyDuration = 0,
.lastVsync = 400});
EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
- entry.update(*mStubTracker.get(), 0);
+ entry.update(*mStubTracker, 0);
EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset));
}
@@ -1409,9 +1485,11 @@
},
mVsyncMoveThreshold);
- EXPECT_TRUE(entry.schedule({.workDuration = 70, .readyDuration = 30, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ const auto scheduleResult =
+ entry.schedule({.workDuration = 70, .readyDuration = 30, .lastVsync = 500},
+ *mStubTracker, 0);
+ EXPECT_EQ(900, scheduleResult.callbackTime.ns());
+ EXPECT_EQ(mPeriod, scheduleResult.vsyncTime.ns());
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h
index dc32ff9..1dc2ef4 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h
@@ -29,8 +29,10 @@
MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
- MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
- MOCK_METHOD(scheduler::ScheduleResult, update, (CallbackToken, ScheduleTiming), (override));
+ MOCK_METHOD(std::optional<scheduler::ScheduleResult>, schedule, (CallbackToken, ScheduleTiming),
+ (override));
+ MOCK_METHOD(std::optional<scheduler::ScheduleResult>, update, (CallbackToken, ScheduleTiming),
+ (override));
MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken token), (override));
MOCK_METHOD(void, dump, (std::string&), (const, override));
};
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 63ecaec..f10ba44 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -56,75 +56,6 @@
// -------------------------------------------------------------------------------------------------
-const constexpr char* STATUS_T_ERROR_MESSAGE_PREFIX = "status_t = ";
-const constexpr char* STATUS_V_1_0_ERROR_MESSAGE_PREFIX =
- "android::hardware::vibrator::V1_0::Status = ";
-
-template <typename T>
-HalResult<T> HalResult<T>::fromStatus(V1_0::Status status, T data) {
- switch (status) {
- case V1_0::Status::OK:
- return HalResult<T>::ok(data);
- case V1_0::Status::UNSUPPORTED_OPERATION:
- return HalResult<T>::unsupported();
- default:
- return HalResult<T>::failed(STATUS_V_1_0_ERROR_MESSAGE_PREFIX + toString(status));
- }
-}
-
-template <typename T>
-template <typename R>
-HalResult<T> HalResult<T>::fromReturn(hardware::Return<R>& ret, T data) {
- return ret.isOk() ? HalResult<T>::ok(data) : HalResult<T>::failed(ret.description());
-}
-
-template <typename T>
-template <typename R>
-HalResult<T> HalResult<T>::fromReturn(hardware::Return<R>& ret, V1_0::Status status, T data) {
- return ret.isOk() ? HalResult<T>::fromStatus(status, data)
- : HalResult<T>::failed(ret.description());
-}
-
-// -------------------------------------------------------------------------------------------------
-
-HalResult<void> HalResult<void>::fromStatus(status_t status) {
- if (status == android::OK) {
- return HalResult<void>::ok();
- }
- return HalResult<void>::failed(STATUS_T_ERROR_MESSAGE_PREFIX + statusToString(status));
-}
-
-HalResult<void> HalResult<void>::fromStatus(binder::Status status) {
- if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION ||
- status.transactionError() == android::UNKNOWN_TRANSACTION) {
- // UNKNOWN_TRANSACTION means the HAL implementation is an older version, so this is
- // the same as the operation being unsupported by this HAL. Should not retry.
- return HalResult<void>::unsupported();
- }
- if (status.isOk()) {
- return HalResult<void>::ok();
- }
- return HalResult<void>::failed(std::string(status.toString8().c_str()));
-}
-
-HalResult<void> HalResult<void>::fromStatus(V1_0::Status status) {
- switch (status) {
- case V1_0::Status::OK:
- return HalResult<void>::ok();
- case V1_0::Status::UNSUPPORTED_OPERATION:
- return HalResult<void>::unsupported();
- default:
- return HalResult<void>::failed(STATUS_V_1_0_ERROR_MESSAGE_PREFIX + toString(status));
- }
-}
-
-template <typename R>
-HalResult<void> HalResult<void>::fromReturn(hardware::Return<R>& ret) {
- return ret.isOk() ? HalResult<void>::ok() : HalResult<void>::failed(ret.description());
-}
-
-// -------------------------------------------------------------------------------------------------
-
Info HalWrapper::getInfo() {
getCapabilities();
getPrimitiveDurations();
@@ -269,7 +200,7 @@
// -------------------------------------------------------------------------------------------------
HalResult<void> AidlHalWrapper::ping() {
- return HalResult<void>::fromStatus(IInterface::asBinder(getHal())->pingBinder());
+ return HalResultFactory::fromStatus(IInterface::asBinder(getHal())->pingBinder());
}
void AidlHalWrapper::tryReconnect() {
@@ -291,7 +222,7 @@
static_cast<int32_t>(capabilities.value() & Capabilities::ON_CALLBACK);
auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
- auto ret = HalResult<void>::fromStatus(getHal()->on(timeout.count(), cb));
+ auto ret = HalResultFactory::fromStatus(getHal()->on(timeout.count(), cb));
if (!supportsCallback && ret.isOk()) {
mCallbackScheduler->schedule(completionCallback, timeout);
}
@@ -300,23 +231,23 @@
}
HalResult<void> AidlHalWrapper::off() {
- return HalResult<void>::fromStatus(getHal()->off());
+ return HalResultFactory::fromStatus(getHal()->off());
}
HalResult<void> AidlHalWrapper::setAmplitude(float amplitude) {
- return HalResult<void>::fromStatus(getHal()->setAmplitude(amplitude));
+ return HalResultFactory::fromStatus(getHal()->setAmplitude(amplitude));
}
HalResult<void> AidlHalWrapper::setExternalControl(bool enabled) {
- return HalResult<void>::fromStatus(getHal()->setExternalControl(enabled));
+ return HalResultFactory::fromStatus(getHal()->setExternalControl(enabled));
}
HalResult<void> AidlHalWrapper::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
- return HalResult<void>::fromStatus(getHal()->alwaysOnEnable(id, effect, strength));
+ return HalResultFactory::fromStatus(getHal()->alwaysOnEnable(id, effect, strength));
}
HalResult<void> AidlHalWrapper::alwaysOnDisable(int32_t id) {
- return HalResult<void>::fromStatus(getHal()->alwaysOnDisable(id));
+ return HalResultFactory::fromStatus(getHal()->alwaysOnDisable(id));
}
HalResult<milliseconds> AidlHalWrapper::performEffect(
@@ -330,7 +261,7 @@
auto result = getHal()->perform(effect, strength, cb, &lengthMs);
milliseconds length = milliseconds(lengthMs);
- auto ret = HalResult<milliseconds>::fromStatus(result, length);
+ auto ret = HalResultFactory::fromStatus<milliseconds>(result, length);
if (!supportsCallback && ret.isOk()) {
mCallbackScheduler->schedule(completionCallback, length);
}
@@ -357,38 +288,40 @@
duration += milliseconds(effect.delayMs);
}
- return HalResult<milliseconds>::fromStatus(getHal()->compose(primitives, cb), duration);
+ return HalResultFactory::fromStatus<milliseconds>(getHal()->compose(primitives, cb), duration);
}
HalResult<void> AidlHalWrapper::performPwleEffect(const std::vector<PrimitivePwle>& primitives,
const std::function<void()>& completionCallback) {
// This method should always support callbacks, so no need to double check.
auto cb = new HalCallbackWrapper(completionCallback);
- return HalResult<void>::fromStatus(getHal()->composePwle(primitives, cb));
+ return HalResultFactory::fromStatus(getHal()->composePwle(primitives, cb));
}
HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
int32_t capabilities = 0;
auto result = getHal()->getCapabilities(&capabilities);
- return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
+ return HalResultFactory::fromStatus<Capabilities>(result,
+ static_cast<Capabilities>(capabilities));
}
HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffectsInternal() {
std::vector<Effect> supportedEffects;
auto result = getHal()->getSupportedEffects(&supportedEffects);
- return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
+ return HalResultFactory::fromStatus<std::vector<Effect>>(result, supportedEffects);
}
HalResult<std::vector<Braking>> AidlHalWrapper::getSupportedBrakingInternal() {
std::vector<Braking> supportedBraking;
auto result = getHal()->getSupportedBraking(&supportedBraking);
- return HalResult<std::vector<Braking>>::fromStatus(result, supportedBraking);
+ return HalResultFactory::fromStatus<std::vector<Braking>>(result, supportedBraking);
}
HalResult<std::vector<CompositePrimitive>> AidlHalWrapper::getSupportedPrimitivesInternal() {
std::vector<CompositePrimitive> supportedPrimitives;
auto result = getHal()->getSupportedPrimitives(&supportedPrimitives);
- return HalResult<std::vector<CompositePrimitive>>::fromStatus(result, supportedPrimitives);
+ return HalResultFactory::fromStatus<std::vector<CompositePrimitive>>(result,
+ supportedPrimitives);
}
HalResult<std::vector<milliseconds>> AidlHalWrapper::getPrimitiveDurationsInternal(
@@ -408,7 +341,7 @@
}
int32_t duration = 0;
auto result = getHal()->getPrimitiveDuration(primitive, &duration);
- auto halResult = HalResult<int32_t>::fromStatus(result, duration);
+ auto halResult = HalResultFactory::fromStatus<int32_t>(result, duration);
if (halResult.isUnsupported()) {
// Should not happen, supported primitives should always support requesting duration.
ALOGE("Supported primitive %zu returned unsupported for getPrimitiveDuration",
@@ -427,55 +360,55 @@
HalResult<milliseconds> AidlHalWrapper::getPrimitiveDelayMaxInternal() {
int32_t delay = 0;
auto result = getHal()->getCompositionDelayMax(&delay);
- return HalResult<milliseconds>::fromStatus(result, milliseconds(delay));
+ return HalResultFactory::fromStatus<milliseconds>(result, milliseconds(delay));
}
HalResult<milliseconds> AidlHalWrapper::getPrimitiveDurationMaxInternal() {
int32_t delay = 0;
auto result = getHal()->getPwlePrimitiveDurationMax(&delay);
- return HalResult<milliseconds>::fromStatus(result, milliseconds(delay));
+ return HalResultFactory::fromStatus<milliseconds>(result, milliseconds(delay));
}
HalResult<int32_t> AidlHalWrapper::getCompositionSizeMaxInternal() {
int32_t size = 0;
auto result = getHal()->getCompositionSizeMax(&size);
- return HalResult<int32_t>::fromStatus(result, size);
+ return HalResultFactory::fromStatus<int32_t>(result, size);
}
HalResult<int32_t> AidlHalWrapper::getPwleSizeMaxInternal() {
int32_t size = 0;
auto result = getHal()->getPwleCompositionSizeMax(&size);
- return HalResult<int32_t>::fromStatus(result, size);
+ return HalResultFactory::fromStatus<int32_t>(result, size);
}
HalResult<float> AidlHalWrapper::getMinFrequencyInternal() {
float minFrequency = 0;
auto result = getHal()->getFrequencyMinimum(&minFrequency);
- return HalResult<float>::fromStatus(result, minFrequency);
+ return HalResultFactory::fromStatus<float>(result, minFrequency);
}
HalResult<float> AidlHalWrapper::getResonantFrequencyInternal() {
float f0 = 0;
auto result = getHal()->getResonantFrequency(&f0);
- return HalResult<float>::fromStatus(result, f0);
+ return HalResultFactory::fromStatus<float>(result, f0);
}
HalResult<float> AidlHalWrapper::getFrequencyResolutionInternal() {
float frequencyResolution = 0;
auto result = getHal()->getFrequencyResolution(&frequencyResolution);
- return HalResult<float>::fromStatus(result, frequencyResolution);
+ return HalResultFactory::fromStatus<float>(result, frequencyResolution);
}
HalResult<float> AidlHalWrapper::getQFactorInternal() {
float qFactor = 0;
auto result = getHal()->getQFactor(&qFactor);
- return HalResult<float>::fromStatus(result, qFactor);
+ return HalResultFactory::fromStatus<float>(result, qFactor);
}
HalResult<std::vector<float>> AidlHalWrapper::getMaxAmplitudesInternal() {
std::vector<float> amplitudes;
auto result = getHal()->getBandwidthAmplitudeMap(&litudes);
- return HalResult<std::vector<float>>::fromStatus(result, amplitudes);
+ return HalResultFactory::fromStatus<std::vector<float>>(result, amplitudes);
}
sp<Aidl::IVibrator> AidlHalWrapper::getHal() {
@@ -488,7 +421,7 @@
template <typename I>
HalResult<void> HidlHalWrapper<I>::ping() {
auto result = getHal()->ping();
- return HalResult<void>::fromReturn(result);
+ return HalResultFactory::fromReturn(result);
}
template <typename I>
@@ -504,7 +437,7 @@
HalResult<void> HidlHalWrapper<I>::on(milliseconds timeout,
const std::function<void()>& completionCallback) {
auto result = getHal()->on(timeout.count());
- auto ret = HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+ auto ret = HalResultFactory::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
if (ret.isOk()) {
mCallbackScheduler->schedule(completionCallback, timeout);
}
@@ -514,14 +447,14 @@
template <typename I>
HalResult<void> HidlHalWrapper<I>::off() {
auto result = getHal()->off();
- return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+ return HalResultFactory::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
}
template <typename I>
HalResult<void> HidlHalWrapper<I>::setAmplitude(float amplitude) {
uint8_t amp = static_cast<uint8_t>(amplitude * std::numeric_limits<uint8_t>::max());
auto result = getHal()->setAmplitude(amp);
- return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+ return HalResultFactory::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
}
template <typename I>
@@ -547,7 +480,7 @@
hardware::Return<bool> result = getHal()->supportsAmplitudeControl();
Capabilities capabilities =
result.withDefault(false) ? Capabilities::AMPLITUDE_CONTROL : Capabilities::NONE;
- return HalResult<Capabilities>::fromReturn(result, capabilities);
+ return HalResultFactory::fromReturn<Capabilities>(result, capabilities);
}
template <typename I>
@@ -566,7 +499,7 @@
auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
milliseconds length = milliseconds(lengthMs);
- auto ret = HalResult<milliseconds>::fromReturn(result, status, length);
+ auto ret = HalResultFactory::fromReturn<milliseconds>(result, status, length);
if (ret.isOk()) {
mCallbackScheduler->schedule(completionCallback, length);
}
@@ -638,7 +571,7 @@
HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) {
auto result = getHal()->setExternalControl(static_cast<uint32_t>(enabled));
- return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+ return HalResultFactory::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
}
HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(
@@ -671,7 +604,7 @@
sp<V1_3::IVibrator> hal = getHal();
auto amplitudeResult = hal->supportsAmplitudeControl();
if (!amplitudeResult.isOk()) {
- return HalResult<Capabilities>::fromReturn(amplitudeResult, capabilities);
+ return HalResultFactory::fromReturn<Capabilities>(amplitudeResult, capabilities);
}
auto externalControlResult = hal->supportsExternalControl();
@@ -686,7 +619,7 @@
}
}
- return HalResult<Capabilities>::fromReturn(externalControlResult, capabilities);
+ return HalResultFactory::fromReturn<Capabilities>(externalControlResult, capabilities);
}
// -------------------------------------------------------------------------------------------------
diff --git a/services/vibratorservice/VibratorManagerHalController.cpp b/services/vibratorservice/VibratorManagerHalController.cpp
index 0df0bfa..aa5b7fc 100644
--- a/services/vibratorservice/VibratorManagerHalController.cpp
+++ b/services/vibratorservice/VibratorManagerHalController.cpp
@@ -46,8 +46,6 @@
HalResult<T> ManagerHalController::processHalResult(HalResult<T> result, const char* functionName) {
if (result.isFailed()) {
ALOGE("VibratorManager HAL %s failed: %s", functionName, result.errorMessage());
- std::lock_guard<std::mutex> lock(mConnectedHalMutex);
- mConnectedHal->tryReconnect();
}
return result;
}
@@ -70,12 +68,16 @@
hal = mConnectedHal;
}
- HalResult<T> ret = processHalResult(halFn(hal), functionName);
- for (int i = 0; i < MAX_RETRIES && ret.isFailed(); i++) {
- ret = processHalResult(halFn(hal), functionName);
+ HalResult<T> result = processHalResult(halFn(hal), functionName);
+ for (int i = 0; i < MAX_RETRIES && result.shouldRetry(); i++) {
+ {
+ std::lock_guard<std::mutex> lock(mConnectedHalMutex);
+ mConnectedHal->tryReconnect();
+ }
+ result = processHalResult(halFn(hal), functionName);
}
- return ret;
+ return result;
}
// -------------------------------------------------------------------------------------------------
diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp
index 6e660e7..1341266 100644
--- a/services/vibratorservice/VibratorManagerHalWrapper.cpp
+++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp
@@ -55,8 +55,8 @@
return HalResult<std::shared_ptr<HalController>>::ok(mController);
}
// Controller.init did not connect to any vibrator HAL service, so the device has no vibrator.
- return HalResult<std::shared_ptr<HalController>>::failed(MISSING_VIBRATOR_MESSAGE_PREFIX +
- std::to_string(id));
+ return HalResult<std::shared_ptr<HalController>>::failed(
+ (MISSING_VIBRATOR_MESSAGE_PREFIX + std::to_string(id)).c_str());
}
HalResult<void> LegacyManagerHalWrapper::prepareSynced(const std::vector<int32_t>&) {
@@ -75,10 +75,10 @@
std::shared_ptr<HalWrapper> AidlManagerHalWrapper::connectToVibrator(
int32_t vibratorId, std::shared_ptr<CallbackScheduler> callbackScheduler) {
- std::function<HalResult<sp<Aidl::IVibrator>>()> reconnectFn = [=]() {
+ std::function<HalResult<sp<Aidl::IVibrator>>()> reconnectFn = [=, this]() {
sp<Aidl::IVibrator> vibrator;
auto result = this->getHal()->getVibrator(vibratorId, &vibrator);
- return HalResult<sp<Aidl::IVibrator>>::fromStatus(result, vibrator);
+ return HalResultFactory::fromStatus<sp<Aidl::IVibrator>>(result, vibrator);
};
auto result = reconnectFn();
if (!result.isOk()) {
@@ -88,12 +88,12 @@
if (!vibrator) {
return nullptr;
}
- return std::move(std::make_unique<AidlHalWrapper>(std::move(callbackScheduler),
- std::move(vibrator), reconnectFn));
+ return std::make_unique<AidlHalWrapper>(std::move(callbackScheduler), std::move(vibrator),
+ reconnectFn);
}
HalResult<void> AidlManagerHalWrapper::ping() {
- return HalResult<void>::fromStatus(IInterface::asBinder(getHal())->pingBinder());
+ return HalResultFactory::fromStatus(IInterface::asBinder(getHal())->pingBinder());
}
void AidlManagerHalWrapper::tryReconnect() {
@@ -112,8 +112,8 @@
}
int32_t cap = 0;
auto result = getHal()->getCapabilities(&cap);
- auto ret = HalResult<ManagerCapabilities>::fromStatus(result,
- static_cast<ManagerCapabilities>(cap));
+ auto capabilities = static_cast<ManagerCapabilities>(cap);
+ auto ret = HalResultFactory::fromStatus<ManagerCapabilities>(result, capabilities);
if (ret.isOk()) {
// Cache copy of returned value.
mCapabilities.emplace(ret.value());
@@ -129,7 +129,7 @@
}
std::vector<int32_t> ids;
auto result = getHal()->getVibratorIds(&ids);
- auto ret = HalResult<std::vector<int32_t>>::fromStatus(result, ids);
+ auto ret = HalResultFactory::fromStatus<std::vector<int32_t>>(result, ids);
if (ret.isOk()) {
// Cache copy of returned value and the individual controllers.
mVibratorIds.emplace(ret.value());
@@ -152,12 +152,12 @@
if (it != mVibrators.end()) {
return HalResult<std::shared_ptr<HalController>>::ok(it->second);
}
- return HalResult<std::shared_ptr<HalController>>::failed(MISSING_VIBRATOR_MESSAGE_PREFIX +
- std::to_string(id));
+ return HalResult<std::shared_ptr<HalController>>::failed(
+ (MISSING_VIBRATOR_MESSAGE_PREFIX + std::to_string(id)).c_str());
}
HalResult<void> AidlManagerHalWrapper::prepareSynced(const std::vector<int32_t>& ids) {
- auto ret = HalResult<void>::fromStatus(getHal()->prepareSynced(ids));
+ auto ret = HalResultFactory::fromStatus(getHal()->prepareSynced(ids));
if (ret.isOk()) {
// Force reload of all vibrator controllers that were prepared for a sync operation here.
// This will trigger calls to getVibrator(id) on each controller, so they can use the
@@ -179,11 +179,11 @@
bool supportsCallback = capabilities.isOk() &&
static_cast<int32_t>(capabilities.value() & ManagerCapabilities::TRIGGER_CALLBACK);
auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
- return HalResult<void>::fromStatus(getHal()->triggerSynced(cb));
+ return HalResultFactory::fromStatus(getHal()->triggerSynced(cb));
}
HalResult<void> AidlManagerHalWrapper::cancelSynced() {
- auto ret = HalResult<void>::fromStatus(getHal()->cancelSynced());
+ auto ret = HalResultFactory::fromStatus(getHal()->cancelSynced());
if (ret.isOk()) {
// Force reload of all vibrator controllers that were prepared for a sync operation before.
// This will trigger calls to getVibrator(id) on each controller, so they can use the
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index 6b73d17..f97442d 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -64,7 +64,29 @@
*/
Info getInfo() {
static Info sDefaultInfo = InfoCache().get();
- return apply<Info>([](HalWrapper* hal) { return hal->getInfo(); }, sDefaultInfo, "getInfo");
+ if (!init()) {
+ ALOGV("Skipped getInfo because Vibrator HAL is not available");
+ return sDefaultInfo;
+ }
+ std::shared_ptr<HalWrapper> hal;
+ {
+ std::lock_guard<std::mutex> lock(mConnectedHalMutex);
+ hal = mConnectedHal;
+ }
+
+ for (int i = 0; i < MAX_RETRIES; i++) {
+ Info result = hal.get()->getInfo();
+ result.logFailures();
+ if (result.shouldRetry()) {
+ tryReconnect();
+ } else {
+ return result;
+ }
+ }
+
+ Info result = hal.get()->getInfo();
+ result.logFailures();
+ return result;
}
/* Calls given HAL function, applying automatic retries to reconnect with the HAL when the
@@ -72,7 +94,7 @@
*/
template <typename T>
HalResult<T> doWithRetry(const HalFunction<HalResult<T>>& halFn, const char* functionName) {
- return apply(halFn, HalResult<T>::unsupported(), functionName);
+ return doWithRetry<T>(halFn, HalResult<T>::unsupported(), functionName);
}
private:
@@ -90,7 +112,8 @@
* function name is for logging purposes.
*/
template <typename T>
- T apply(const HalFunction<T>& halFn, T defaultValue, const char* functionName) {
+ HalResult<T> doWithRetry(const HalFunction<HalResult<T>>& halFn, HalResult<T> defaultValue,
+ const char* functionName) {
if (!init()) {
ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
return defaultValue;
@@ -101,16 +124,22 @@
hal = mConnectedHal;
}
- for (int i = 0; i < MAX_RETRIES; i++) {
- T result = halFn(hal.get());
- if (result.isFailedLogged(functionName)) {
- tryReconnect();
- } else {
- return result;
- }
+ HalResult<T> result = doOnce(hal.get(), halFn, functionName);
+ for (int i = 0; i < MAX_RETRIES && result.shouldRetry(); i++) {
+ tryReconnect();
+ result = doOnce(hal.get(), halFn, functionName);
}
+ return result;
+ }
- return halFn(hal.get());
+ template <typename T>
+ HalResult<T> doOnce(HalWrapper* hal, const HalFunction<HalResult<T>>& halFn,
+ const char* functionName) {
+ HalResult<T> result = halFn(hal);
+ if (result.isFailed()) {
+ ALOGE("Vibrator HAL %s failed: %s", functionName, result.errorMessage());
+ }
+ return result;
}
};
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index d2cc9ad..39c4eb4 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -31,101 +31,154 @@
// -------------------------------------------------------------------------------------------------
+// Base class to represent a generic result of a call to the Vibrator HAL wrapper.
+class BaseHalResult {
+public:
+ bool isOk() const { return mStatus == SUCCESS; }
+ bool isFailed() const { return mStatus == FAILED; }
+ bool isUnsupported() const { return mStatus == UNSUPPORTED; }
+ bool shouldRetry() const { return isFailed() && mDeadObject; }
+ const char* errorMessage() const { return mErrorMessage.c_str(); }
+
+protected:
+ enum Status { SUCCESS, UNSUPPORTED, FAILED };
+ Status mStatus;
+ std::string mErrorMessage;
+ bool mDeadObject;
+
+ explicit BaseHalResult(Status status, const char* errorMessage = "", bool deadObject = false)
+ : mStatus(status), mErrorMessage(errorMessage), mDeadObject(deadObject) {}
+ virtual ~BaseHalResult() = default;
+};
+
// Result of a call to the Vibrator HAL wrapper, holding data if successful.
template <typename T>
-class HalResult {
+class HalResult : public BaseHalResult {
public:
static HalResult<T> ok(T value) { return HalResult(value); }
- static HalResult<T> failed(std::string msg) {
- return HalResult(std::move(msg), /* unsupported= */ false);
+ static HalResult<T> unsupported() { return HalResult(Status::UNSUPPORTED); }
+ static HalResult<T> failed(const char* msg) { return HalResult(Status::FAILED, msg); }
+ static HalResult<T> transactionFailed(const char* msg) {
+ return HalResult(Status::FAILED, msg, /* deadObject= */ true);
}
- static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); }
+ // This will throw std::bad_optional_access if this result is not ok.
+ const T& value() const { return mValue.value(); }
+ const T valueOr(T&& defaultValue) const { return mValue.value_or(defaultValue); }
+
+private:
+ std::optional<T> mValue;
+
+ explicit HalResult(T value)
+ : BaseHalResult(Status::SUCCESS), mValue(std::make_optional(value)) {}
+ explicit HalResult(Status status, const char* errorMessage = "", bool deadObject = false)
+ : BaseHalResult(status, errorMessage, deadObject), mValue() {}
+};
+
+// Empty result of a call to the Vibrator HAL wrapper.
+template <>
+class HalResult<void> : public BaseHalResult {
+public:
+ static HalResult<void> ok() { return HalResult(Status::SUCCESS); }
+ static HalResult<void> unsupported() { return HalResult(Status::UNSUPPORTED); }
+ static HalResult<void> failed(const char* msg) { return HalResult(Status::FAILED, msg); }
+ static HalResult<void> transactionFailed(const char* msg) {
+ return HalResult(Status::FAILED, msg, /* deadObject= */ true);
+ }
+
+private:
+ explicit HalResult(Status status, const char* errorMessage = "", bool deadObject = false)
+ : BaseHalResult(status, errorMessage, deadObject) {}
+};
+
+// -------------------------------------------------------------------------------------------------
+
+// Factory functions that convert failed HIDL/AIDL results into HalResult instances.
+// Implementation of static template functions needs to be in this header file for the linker.
+class HalResultFactory {
+public:
+ template <typename T>
static HalResult<T> fromStatus(binder::Status status, T data) {
+ return status.isOk() ? HalResult<T>::ok(data) : fromFailedStatus<T>(status);
+ }
+
+ template <typename T>
+ static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status status, T data) {
+ return (status == hardware::vibrator::V1_0::Status::OK) ? HalResult<T>::ok(data)
+ : fromFailedStatus<T>(status);
+ }
+
+ template <typename T, typename R>
+ static HalResult<T> fromReturn(hardware::Return<R>& ret, T data) {
+ return ret.isOk() ? HalResult<T>::ok(data) : fromFailedReturn<T, R>(ret);
+ }
+
+ template <typename T, typename R>
+ static HalResult<T> fromReturn(hardware::Return<R>& ret,
+ hardware::vibrator::V1_0::Status status, T data) {
+ return ret.isOk() ? fromStatus<T>(status, data) : fromFailedReturn<T, R>(ret);
+ }
+
+ static HalResult<void> fromStatus(status_t status) {
+ return (status == android::OK) ? HalResult<void>::ok() : fromFailedStatus<void>(status);
+ }
+
+ static HalResult<void> fromStatus(binder::Status status) {
+ return status.isOk() ? HalResult<void>::ok() : fromFailedStatus<void>(status);
+ }
+
+ static HalResult<void> fromStatus(hardware::vibrator::V1_0::Status status) {
+ return (status == hardware::vibrator::V1_0::Status::OK) ? HalResult<void>::ok()
+ : fromFailedStatus<void>(status);
+ }
+
+ template <typename R>
+ static HalResult<void> fromReturn(hardware::Return<R>& ret) {
+ return ret.isOk() ? HalResult<void>::ok() : fromFailedReturn<void, R>(ret);
+ }
+
+private:
+ template <typename T>
+ static HalResult<T> fromFailedStatus(status_t status) {
+ auto msg = "status_t = " + statusToString(status);
+ return (status == android::DEAD_OBJECT) ? HalResult<T>::transactionFailed(msg.c_str())
+ : HalResult<T>::failed(msg.c_str());
+ }
+
+ template <typename T>
+ static HalResult<T> fromFailedStatus(binder::Status status) {
if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION ||
status.transactionError() == android::UNKNOWN_TRANSACTION) {
// UNKNOWN_TRANSACTION means the HAL implementation is an older version, so this is
// the same as the operation being unsupported by this HAL. Should not retry.
return HalResult<T>::unsupported();
}
- if (status.isOk()) {
- return HalResult<T>::ok(data);
+ if (status.exceptionCode() == binder::Status::EX_TRANSACTION_FAILED) {
+ return HalResult<T>::transactionFailed(status.toString8().c_str());
}
return HalResult<T>::failed(status.toString8().c_str());
}
- static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status status, T data);
- template <typename R>
- static HalResult<T> fromReturn(hardware::Return<R>& ret, T data);
-
- template <typename R>
- static HalResult<T> fromReturn(hardware::Return<R>& ret,
- hardware::vibrator::V1_0::Status status, T data);
-
- // This will throw std::bad_optional_access if this result is not ok.
- const T& value() const { return mValue.value(); }
- const T valueOr(T&& defaultValue) const { return mValue.value_or(defaultValue); }
- bool isOk() const { return !mUnsupported && mValue.has_value(); }
- bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
- bool isUnsupported() const { return mUnsupported; }
- const char* errorMessage() const { return mErrorMessage.c_str(); }
- bool isFailedLogged(const char* functionNameForLogging) const {
- if (isFailed()) {
- ALOGE("Vibrator HAL %s failed: %s", functionNameForLogging, errorMessage());
- return true;
+ template <typename T>
+ static HalResult<T> fromFailedStatus(hardware::vibrator::V1_0::Status status) {
+ switch (status) {
+ case hardware::vibrator::V1_0::Status::UNSUPPORTED_OPERATION:
+ return HalResult<T>::unsupported();
+ default:
+ auto msg = "android::hardware::vibrator::V1_0::Status = " + toString(status);
+ return HalResult<T>::failed(msg.c_str());
}
- return false;
}
-private:
- std::optional<T> mValue;
- std::string mErrorMessage;
- bool mUnsupported;
-
- explicit HalResult(T value)
- : mValue(std::make_optional(value)), mErrorMessage(), mUnsupported(false) {}
- explicit HalResult(std::string errorMessage, bool unsupported)
- : mValue(), mErrorMessage(std::move(errorMessage)), mUnsupported(unsupported) {}
-};
-
-// Empty result of a call to the Vibrator HAL wrapper.
-template <>
-class HalResult<void> {
-public:
- static HalResult<void> ok() { return HalResult(); }
- static HalResult<void> failed(std::string msg) { return HalResult(std::move(msg)); }
- static HalResult<void> unsupported() { return HalResult(/* unsupported= */ true); }
-
- static HalResult<void> fromStatus(status_t status);
- static HalResult<void> fromStatus(binder::Status status);
- static HalResult<void> fromStatus(hardware::vibrator::V1_0::Status status);
-
- template <typename R>
- static HalResult<void> fromReturn(hardware::Return<R>& ret);
-
- bool isOk() const { return !mUnsupported && !mFailed; }
- bool isFailed() const { return !mUnsupported && mFailed; }
- bool isUnsupported() const { return mUnsupported; }
- const char* errorMessage() const { return mErrorMessage.c_str(); }
- bool isFailedLogged(const char* functionNameForLogging) const {
- if (isFailed()) {
- ALOGE("Vibrator HAL %s failed: %s", functionNameForLogging, errorMessage());
- return true;
- }
- return false;
+ template <typename T, typename R>
+ static HalResult<T> fromFailedReturn(hardware::Return<R>& ret) {
+ return ret.isDeadObject() ? HalResult<T>::transactionFailed(ret.description().c_str())
+ : HalResult<T>::failed(ret.description().c_str());
}
-
-private:
- std::string mErrorMessage;
- bool mFailed;
- bool mUnsupported;
-
- explicit HalResult(bool unsupported = false)
- : mErrorMessage(), mFailed(false), mUnsupported(unsupported) {}
- explicit HalResult(std::string errorMessage)
- : mErrorMessage(std::move(errorMessage)), mFailed(true), mUnsupported(false) {}
};
+// -------------------------------------------------------------------------------------------------
+
class HalCallbackWrapper : public hardware::vibrator::BnVibratorCallback {
public:
HalCallbackWrapper(std::function<void()> completionCallback)
@@ -192,21 +245,44 @@
const HalResult<float> qFactor;
const HalResult<std::vector<float>> maxAmplitudes;
- bool isFailedLogged(const char*) const {
- return capabilities.isFailedLogged("getCapabilities") ||
- supportedEffects.isFailedLogged("getSupportedEffects") ||
- supportedBraking.isFailedLogged("getSupportedBraking") ||
- supportedPrimitives.isFailedLogged("getSupportedPrimitives") ||
- primitiveDurations.isFailedLogged("getPrimitiveDuration") ||
- primitiveDelayMax.isFailedLogged("getPrimitiveDelayMax") ||
- pwlePrimitiveDurationMax.isFailedLogged("getPwlePrimitiveDurationMax") ||
- compositionSizeMax.isFailedLogged("getCompositionSizeMax") ||
- pwleSizeMax.isFailedLogged("getPwleSizeMax") ||
- minFrequency.isFailedLogged("getMinFrequency") ||
- resonantFrequency.isFailedLogged("getResonantFrequency") ||
- frequencyResolution.isFailedLogged("getFrequencyResolution") ||
- qFactor.isFailedLogged("getQFactor") ||
- maxAmplitudes.isFailedLogged("getMaxAmplitudes");
+ void logFailures() const {
+ logFailure<Capabilities>(capabilities, "getCapabilities");
+ logFailure<std::vector<hardware::vibrator::Effect>>(supportedEffects,
+ "getSupportedEffects");
+ logFailure<std::vector<hardware::vibrator::Braking>>(supportedBraking,
+ "getSupportedBraking");
+ logFailure<std::vector<hardware::vibrator::CompositePrimitive>>(supportedPrimitives,
+ "getSupportedPrimitives");
+ logFailure<std::vector<std::chrono::milliseconds>>(primitiveDurations,
+ "getPrimitiveDuration");
+ logFailure<std::chrono::milliseconds>(primitiveDelayMax, "getPrimitiveDelayMax");
+ logFailure<std::chrono::milliseconds>(pwlePrimitiveDurationMax,
+ "getPwlePrimitiveDurationMax");
+ logFailure<int32_t>(compositionSizeMax, "getCompositionSizeMax");
+ logFailure<int32_t>(pwleSizeMax, "getPwleSizeMax");
+ logFailure<float>(minFrequency, "getMinFrequency");
+ logFailure<float>(resonantFrequency, "getResonantFrequency");
+ logFailure<float>(frequencyResolution, "getFrequencyResolution");
+ logFailure<float>(qFactor, "getQFactor");
+ logFailure<std::vector<float>>(maxAmplitudes, "getMaxAmplitudes");
+ }
+
+ bool shouldRetry() const {
+ return capabilities.shouldRetry() || supportedEffects.shouldRetry() ||
+ supportedBraking.shouldRetry() || supportedPrimitives.shouldRetry() ||
+ primitiveDurations.shouldRetry() || primitiveDelayMax.shouldRetry() ||
+ pwlePrimitiveDurationMax.shouldRetry() || compositionSizeMax.shouldRetry() ||
+ pwleSizeMax.shouldRetry() || minFrequency.shouldRetry() ||
+ resonantFrequency.shouldRetry() || frequencyResolution.shouldRetry() ||
+ qFactor.shouldRetry() || maxAmplitudes.shouldRetry();
+ }
+
+private:
+ template <typename T>
+ void logFailure(HalResult<T> result, const char* functionName) const {
+ if (result.isFailed()) {
+ ALOGE("Vibrator HAL %s failed: %s", functionName, result.errorMessage());
+ }
}
};
@@ -230,27 +306,29 @@
}
private:
+ // Create a transaction failed results as default so we can retry on the first time we get them.
static const constexpr char* MSG = "never loaded";
- HalResult<Capabilities> mCapabilities = HalResult<Capabilities>::failed(MSG);
+ HalResult<Capabilities> mCapabilities = HalResult<Capabilities>::transactionFailed(MSG);
HalResult<std::vector<hardware::vibrator::Effect>> mSupportedEffects =
- HalResult<std::vector<hardware::vibrator::Effect>>::failed(MSG);
+ HalResult<std::vector<hardware::vibrator::Effect>>::transactionFailed(MSG);
HalResult<std::vector<hardware::vibrator::Braking>> mSupportedBraking =
- HalResult<std::vector<hardware::vibrator::Braking>>::failed(MSG);
+ HalResult<std::vector<hardware::vibrator::Braking>>::transactionFailed(MSG);
HalResult<std::vector<hardware::vibrator::CompositePrimitive>> mSupportedPrimitives =
- HalResult<std::vector<hardware::vibrator::CompositePrimitive>>::failed(MSG);
+ HalResult<std::vector<hardware::vibrator::CompositePrimitive>>::transactionFailed(MSG);
HalResult<std::vector<std::chrono::milliseconds>> mPrimitiveDurations =
- HalResult<std::vector<std::chrono::milliseconds>>::failed(MSG);
+ HalResult<std::vector<std::chrono::milliseconds>>::transactionFailed(MSG);
HalResult<std::chrono::milliseconds> mPrimitiveDelayMax =
- HalResult<std::chrono::milliseconds>::failed(MSG);
+ HalResult<std::chrono::milliseconds>::transactionFailed(MSG);
HalResult<std::chrono::milliseconds> mPwlePrimitiveDurationMax =
- HalResult<std::chrono::milliseconds>::failed(MSG);
- HalResult<int32_t> mCompositionSizeMax = HalResult<int>::failed(MSG);
- HalResult<int32_t> mPwleSizeMax = HalResult<int>::failed(MSG);
- HalResult<float> mMinFrequency = HalResult<float>::failed(MSG);
- HalResult<float> mResonantFrequency = HalResult<float>::failed(MSG);
- HalResult<float> mFrequencyResolution = HalResult<float>::failed(MSG);
- HalResult<float> mQFactor = HalResult<float>::failed(MSG);
- HalResult<std::vector<float>> mMaxAmplitudes = HalResult<std::vector<float>>::failed(MSG);
+ HalResult<std::chrono::milliseconds>::transactionFailed(MSG);
+ HalResult<int32_t> mCompositionSizeMax = HalResult<int>::transactionFailed(MSG);
+ HalResult<int32_t> mPwleSizeMax = HalResult<int>::transactionFailed(MSG);
+ HalResult<float> mMinFrequency = HalResult<float>::transactionFailed(MSG);
+ HalResult<float> mResonantFrequency = HalResult<float>::transactionFailed(MSG);
+ HalResult<float> mFrequencyResolution = HalResult<float>::transactionFailed(MSG);
+ HalResult<float> mQFactor = HalResult<float>::transactionFailed(MSG);
+ HalResult<std::vector<float>> mMaxAmplitudes =
+ HalResult<std::vector<float>>::transactionFailed(MSG);
friend class HalWrapper;
};
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index 8e77bc5..9b95d74 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -107,17 +107,38 @@
ASSERT_EQ(1, mConnectCounter);
}
-TEST_F(VibratorHalControllerTest, TestGetInfoRetriesOnAnyFailure) {
+TEST_F(VibratorHalControllerTest, TestGetInfoRetriesOnTransactionFailure) {
EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(), getCapabilitiesInternal())
.Times(Exactly(2))
- .WillOnce(Return(vibrator::HalResult<vibrator::Capabilities>::failed("message")))
+ .WillOnce(Return(vibrator::HalResult<vibrator::Capabilities>::transactionFailed("msg")))
.WillRepeatedly(Return(vibrator::HalResult<vibrator::Capabilities>::ok(
vibrator::Capabilities::ON_CALLBACK)));
auto result = mController->getInfo();
- ASSERT_FALSE(result.capabilities.isFailed());
+ ASSERT_TRUE(result.capabilities.isOk());
+ ASSERT_EQ(1, mConnectCounter);
+}
+TEST_F(VibratorHalControllerTest, TestGetInfoDoesNotRetryOnOperationFailure) {
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
+ EXPECT_CALL(*mMockHal.get(), getCapabilitiesInternal())
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(vibrator::HalResult<vibrator::Capabilities>::failed("msg")));
+
+ auto result = mController->getInfo();
+ ASSERT_TRUE(result.capabilities.isFailed());
+ ASSERT_EQ(1, mConnectCounter);
+}
+
+TEST_F(VibratorHalControllerTest, TestGetInfoDoesNotRetryOnUnsupported) {
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
+ EXPECT_CALL(*mMockHal.get(), getCapabilitiesInternal())
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(vibrator::HalResult<vibrator::Capabilities>::unsupported()));
+
+ auto result = mController->getInfo();
+ ASSERT_TRUE(result.capabilities.isUnsupported());
ASSERT_EQ(1, mConnectCounter);
}
@@ -128,48 +149,54 @@
auto result = mController->doWithRetry<void>(ON_FN, "on");
ASSERT_TRUE(result.isOk());
-
ASSERT_EQ(1, mConnectCounter);
}
-TEST_F(VibratorHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnection) {
+TEST_F(VibratorHalControllerTest, TestUnsupportedApiResultDoesNotResetHalConnection) {
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
EXPECT_CALL(*mMockHal.get(), off())
.Times(Exactly(1))
.WillRepeatedly(Return(vibrator::HalResult<void>::unsupported()));
- ASSERT_EQ(0, mConnectCounter);
auto result = mController->doWithRetry<void>(OFF_FN, "off");
ASSERT_TRUE(result.isUnsupported());
ASSERT_EQ(1, mConnectCounter);
}
-TEST_F(VibratorHalControllerTest, TestFailedApiResultResetsHalConnection) {
+TEST_F(VibratorHalControllerTest, TestOperationFailedApiResultDoesNotResetHalConnection) {
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
EXPECT_CALL(*mMockHal.get(), on(_, _))
- .Times(Exactly(2))
+ .Times(Exactly(1))
.WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
- EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
-
- ASSERT_EQ(0, mConnectCounter);
auto result = mController->doWithRetry<void>(ON_FN, "on");
ASSERT_TRUE(result.isFailed());
ASSERT_EQ(1, mConnectCounter);
}
-TEST_F(VibratorHalControllerTest, TestFailedApiResultReturnsSuccessAfterRetries) {
+TEST_F(VibratorHalControllerTest, TestTransactionFailedApiResultResetsHalConnection) {
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), on(_, _))
+ .Times(Exactly(2))
+ .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
+
+ auto result = mController->doWithRetry<void>(ON_FN, "on");
+ ASSERT_TRUE(result.isFailed());
+ ASSERT_EQ(1, mConnectCounter);
+}
+
+TEST_F(VibratorHalControllerTest, TestTransactionFailedApiResultReturnsSuccessAfterRetries) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), ping())
.Times(Exactly(1))
- .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
+ .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(), ping())
.Times(Exactly(1))
.WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
}
- ASSERT_EQ(0, mConnectCounter);
-
auto result = mController->doWithRetry<void>(PING_FN, "ping");
ASSERT_TRUE(result.isOk());
ASSERT_EQ(1, mConnectCounter);
@@ -221,11 +248,11 @@
});
EXPECT_CALL(*mMockHal.get(), ping())
.Times(Exactly(1))
- .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
+ .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(), ping())
.Times(Exactly(1))
- .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
+ .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
}
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
diff --git a/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp b/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
index e5fbbae..11a8b66 100644
--- a/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
@@ -98,8 +98,10 @@
.WillRepeatedly(Return(voidResult));
if (cardinality > 1) {
- // One reconnection call after each failure.
- EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(7 * cardinality));
+ // One reconnection for each retry.
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(7 * (cardinality - 1)));
+ } else {
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
}
}
};
@@ -141,14 +143,12 @@
ASSERT_EQ(1, mConnectCounter);
}
-TEST_F(VibratorManagerHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnection) {
+TEST_F(VibratorManagerHalControllerTest, TestUnsupportedApiResultDoesNotResetHalConnection) {
setHalExpectations(/* cardinality= */ 1, vibrator::HalResult<void>::unsupported(),
vibrator::HalResult<vibrator::ManagerCapabilities>::unsupported(),
vibrator::HalResult<std::vector<int32_t>>::unsupported(),
vibrator::HalResult<std::shared_ptr<HalController>>::unsupported());
- ASSERT_EQ(0, mConnectCounter);
-
ASSERT_TRUE(mController->ping().isUnsupported());
ASSERT_TRUE(mController->getCapabilities().isUnsupported());
ASSERT_TRUE(mController->getVibratorIds().isUnsupported());
@@ -160,13 +160,28 @@
ASSERT_EQ(1, mConnectCounter);
}
-TEST_F(VibratorManagerHalControllerTest, TestFailedApiResultResetsHalConnection) {
- setHalExpectations(MAX_ATTEMPTS, vibrator::HalResult<void>::failed("message"),
- vibrator::HalResult<vibrator::ManagerCapabilities>::failed("message"),
- vibrator::HalResult<std::vector<int32_t>>::failed("message"),
- vibrator::HalResult<std::shared_ptr<HalController>>::failed("message"));
+TEST_F(VibratorManagerHalControllerTest, TestOperationFailedApiResultDoesNotResetHalConnection) {
+ setHalExpectations(/* cardinality= */ 1, vibrator::HalResult<void>::failed("msg"),
+ vibrator::HalResult<vibrator::ManagerCapabilities>::failed("msg"),
+ vibrator::HalResult<std::vector<int32_t>>::failed("msg"),
+ vibrator::HalResult<std::shared_ptr<HalController>>::failed("msg"));
- ASSERT_EQ(0, mConnectCounter);
+ ASSERT_TRUE(mController->ping().isFailed());
+ ASSERT_TRUE(mController->getCapabilities().isFailed());
+ ASSERT_TRUE(mController->getVibratorIds().isFailed());
+ ASSERT_TRUE(mController->getVibrator(VIBRATOR_ID).isFailed());
+ ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isFailed());
+ ASSERT_TRUE(mController->triggerSynced([]() {}).isFailed());
+ ASSERT_TRUE(mController->cancelSynced().isFailed());
+
+ ASSERT_EQ(1, mConnectCounter);
+}
+
+TEST_F(VibratorManagerHalControllerTest, TestTransactionFailedApiResultResetsHalConnection) {
+ setHalExpectations(MAX_ATTEMPTS, vibrator::HalResult<void>::transactionFailed("m"),
+ vibrator::HalResult<vibrator::ManagerCapabilities>::transactionFailed("m"),
+ vibrator::HalResult<std::vector<int32_t>>::transactionFailed("m"),
+ vibrator::HalResult<std::shared_ptr<HalController>>::transactionFailed("m"));
ASSERT_TRUE(mController->ping().isFailed());
ASSERT_TRUE(mController->getCapabilities().isFailed());
@@ -184,14 +199,13 @@
InSequence seq;
EXPECT_CALL(*mMockHal.get(), ping())
.Times(Exactly(1))
- .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
+ .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(), ping())
.Times(Exactly(1))
.WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
}
- ASSERT_EQ(0, mConnectCounter);
ASSERT_TRUE(mController->ping().isOk());
ASSERT_EQ(1, mConnectCounter);
}
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index 1593cb1..dffc281 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -254,13 +254,14 @@
EXPECT_CALL(*mMockHal.get(), getVibrator(Eq(kVibratorId), _))
.Times(Exactly(3))
.WillOnce(DoAll(SetArgPointee<1>(nullptr),
- Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))))
+ Return(Status::fromExceptionCode(
+ Status::Exception::EX_TRANSACTION_FAILED))))
.WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status())));
EXPECT_CALL(*mMockVibrator.get(), off())
.Times(Exactly(3))
- .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
- .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_TRANSACTION_FAILED)))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_TRANSACTION_FAILED)))
.WillRepeatedly(Return(Status()));
// Get vibrator controller is successful even if first getVibrator.