Merge changes I5b0dd111,I40135534,Ief7fff69 into main
* changes:
[SF] Change VSyncDispatchTimerQueue::Schedule to return ScheduleResult
[SF] Enable vrr_timeout_hint_enabled
[SF] Send NotifyExpectedPresentHint at the transaction time
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/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/include/input/Input.h b/include/input/Input.h
index 7b253a5..a84dcfc 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -180,7 +180,8 @@
* Declare a concrete type for the NDK's input event forward declaration.
*/
struct AInputEvent {
- virtual ~AInputEvent() { }
+ virtual ~AInputEvent() {}
+ bool operator==(const AInputEvent&) const = default;
};
/*
@@ -545,6 +546,8 @@
static int32_t nextId();
+ bool operator==(const InputEvent&) const = default;
+
protected:
void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac);
@@ -598,6 +601,8 @@
static const char* actionToString(int32_t action);
+ bool operator==(const KeyEvent&) const = default;
+
protected:
int32_t mAction;
int32_t mFlags;
@@ -917,6 +922,9 @@
// The rounding precision for transformed motion events.
static constexpr float ROUNDING_PRECISION = 0.001f;
+ bool operator==(const MotionEvent&) const;
+ inline bool operator!=(const MotionEvent& o) const { return !(*this == o); };
+
protected:
int32_t mAction;
int32_t mActionButton;
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 1a9766d..319716e 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -14,6 +14,7 @@
package {
default_applicable_licenses: ["frameworks_native_libs_arect_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
// Added automatically by a large-scale-change
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index bf7a0ba..3af9ec7 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -258,11 +258,24 @@
}
}
+void ABBinder::addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& /* recipient */,
+ void* /* cookie */) {
+ LOG_ALWAYS_FATAL("Should not reach this. Can't linkToDeath local binders.");
+}
+
ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
: AIBinder(nullptr /*clazz*/), mRemote(binder) {
LOG_ALWAYS_FATAL_IF(binder == nullptr, "binder == nullptr");
}
-ABpBinder::~ABpBinder() {}
+
+ABpBinder::~ABpBinder() {
+ for (auto& recip : mDeathRecipients) {
+ sp<AIBinder_DeathRecipient> strongRecip = recip.recipient.promote();
+ if (strongRecip) {
+ strongRecip->pruneThisTransferEntry(getBinder(), recip.cookie);
+ }
+ }
+}
sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) {
if (binder == nullptr) {
@@ -301,6 +314,11 @@
return ret;
}
+void ABpBinder::addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient,
+ void* cookie) {
+ mDeathRecipients.emplace_back(recipient, cookie);
+}
+
struct AIBinder_Weak {
wp<AIBinder> binder;
};
@@ -426,6 +444,17 @@
LOG_ALWAYS_FATAL_IF(onDied == nullptr, "onDied == nullptr");
}
+void AIBinder_DeathRecipient::pruneThisTransferEntry(const sp<IBinder>& who, void* cookie) {
+ std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
+ mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(),
+ [&](const sp<TransferDeathRecipient>& tdr) {
+ auto tdrWho = tdr->getWho();
+ return tdrWho != nullptr && tdrWho.promote() == who &&
+ cookie == tdr->getCookie();
+ }),
+ mDeathRecipients.end());
+}
+
void AIBinder_DeathRecipient::pruneDeadTransferEntriesLocked() {
mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(),
[](const sp<TransferDeathRecipient>& tdr) {
@@ -554,8 +583,11 @@
return STATUS_UNEXPECTED_NULL;
}
- // returns binder_status_t
- return recipient->linkToDeath(binder->getBinder(), cookie);
+ binder_status_t ret = recipient->linkToDeath(binder->getBinder(), cookie);
+ if (ret == STATUS_OK) {
+ binder->addDeathRecipient(recipient, cookie);
+ }
+ return ret;
}
binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 9d5368f..a2682d8 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -51,6 +51,8 @@
::android::sp<::android::IBinder> binder = const_cast<AIBinder*>(this)->getBinder();
return binder->remoteBinder() != nullptr;
}
+ virtual void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient,
+ void* cookie) = 0;
private:
// AIBinder instance is instance of this class for a local object. In order to transact on a
@@ -78,6 +80,8 @@
::android::status_t dump(int fd, const ::android::Vector<::android::String16>& args) override;
::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
::android::Parcel* reply, binder_flags_t flags) override;
+ void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& /* recipient */,
+ void* /* cookie */) override;
private:
ABBinder(const AIBinder_Class* clazz, void* userData);
@@ -106,12 +110,19 @@
bool isServiceFuzzing() const { return mServiceFuzzing; }
void setServiceFuzzing() { mServiceFuzzing = true; }
+ void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient,
+ void* cookie) override;
private:
friend android::sp<ABpBinder>;
explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
::android::sp<::android::IBinder> mRemote;
bool mServiceFuzzing = false;
+ struct DeathRecipientInfo {
+ android::wp<AIBinder_DeathRecipient> recipient;
+ void* cookie;
+ };
+ std::vector<DeathRecipientInfo> mDeathRecipients;
};
struct AIBinder_Class {
@@ -183,6 +194,7 @@
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/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index b34b30d..a905dff 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -248,6 +248,8 @@
* \param instance identifier of the passthrough service (e.g. "mapper")
* \param instance identifier of the implemenatation (e.g. "default")
* \param flag passed to dlopen()
+ *
+ * \return the result of dlopen of the specified HAL
*/
void* AServiceManager_openDeclaredPassthroughHal(const char* interface, const char* instance,
int flag)
diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp
index 3ee36cd..ca92727 100644
--- a/libs/binder/ndk/tests/iface.cpp
+++ b/libs/binder/ndk/tests/iface.cpp
@@ -25,6 +25,7 @@
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 0a562f0..0cdd50b 100644
--- a/libs/binder/ndk/tests/include/iface/iface.h
+++ b/libs/binder/ndk/tests/include/iface/iface.h
@@ -27,6 +27,7 @@
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 966ec95..ce63b82 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -536,6 +536,7 @@
bool deathReceived = false;
std::function<void(void)> onDeath = [&] {
+ std::unique_lock<std::mutex> lockDeath(deathMutex);
std::cerr << "Binder died (as requested)." << std::endl;
deathReceived = true;
deathCv.notify_one();
@@ -547,6 +548,7 @@
bool wasDeathReceivedFirst = false;
std::function<void(void)> onUnlink = [&] {
+ std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
std::cerr << "Binder unlinked (as requested)." << std::endl;
wasDeathReceivedFirst = deathReceived;
unlinkReceived = true;
@@ -560,7 +562,6 @@
EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(cookie)));
- // the binder driver should return this if the service dies during the transaction
EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
foo = nullptr;
@@ -579,6 +580,123 @@
binder = nullptr;
}
+TEST(NdkBinder, DeathRecipientDropBinderNoDeath) {
+ using namespace std::chrono_literals;
+
+ std::mutex deathMutex;
+ std::condition_variable deathCv;
+ bool deathReceived = false;
+
+ std::function<void(void)> onDeath = [&] {
+ std::unique_lock<std::mutex> lockDeath(deathMutex);
+ std::cerr << "Binder died (as requested)." << std::endl;
+ deathReceived = true;
+ deathCv.notify_one();
+ };
+
+ std::mutex unlinkMutex;
+ std::condition_variable unlinkCv;
+ bool unlinkReceived = false;
+ bool wasDeathReceivedFirst = false;
+
+ std::function<void(void)> onUnlink = [&] {
+ std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
+ std::cerr << "Binder unlinked (as requested)." << std::endl;
+ wasDeathReceivedFirst = deathReceived;
+ unlinkReceived = true;
+ unlinkCv.notify_one();
+ };
+
+ // keep the death recipient around
+ ndk::ScopedAIBinder_DeathRecipient recipient(AIBinder_DeathRecipient_new(LambdaOnDeath));
+ AIBinder_DeathRecipient_setOnUnlinked(recipient.get(), LambdaOnUnlink);
+
+ {
+ AIBinder* binder;
+ sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor2, &binder);
+ ASSERT_NE(nullptr, foo.get());
+ ASSERT_NE(nullptr, binder);
+
+ DeathRecipientCookie* cookie = new DeathRecipientCookie{&onDeath, &onUnlink};
+
+ EXPECT_EQ(STATUS_OK,
+ AIBinder_linkToDeath(binder, recipient.get(), static_cast<void*>(cookie)));
+ // let the sp<IFoo> and AIBinder fall out of scope
+ AIBinder_decStrong(binder);
+ binder = nullptr;
+ }
+
+ {
+ std::unique_lock<std::mutex> lockDeath(deathMutex);
+ EXPECT_FALSE(deathCv.wait_for(lockDeath, 100ms, [&] { return deathReceived; }));
+ EXPECT_FALSE(deathReceived);
+ }
+
+ {
+ std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
+ EXPECT_TRUE(deathCv.wait_for(lockUnlink, 1s, [&] { return unlinkReceived; }));
+ EXPECT_TRUE(unlinkReceived);
+ EXPECT_FALSE(wasDeathReceivedFirst);
+ }
+}
+
+TEST(NdkBinder, DeathRecipientDropBinderOnDied) {
+ using namespace std::chrono_literals;
+
+ std::mutex deathMutex;
+ std::condition_variable deathCv;
+ bool deathReceived = false;
+
+ sp<IFoo> foo;
+ AIBinder* binder;
+ std::function<void(void)> onDeath = [&] {
+ std::unique_lock<std::mutex> lockDeath(deathMutex);
+ std::cerr << "Binder died (as requested)." << std::endl;
+ deathReceived = true;
+ AIBinder_decStrong(binder);
+ binder = nullptr;
+ deathCv.notify_one();
+ };
+
+ std::mutex unlinkMutex;
+ std::condition_variable unlinkCv;
+ bool unlinkReceived = false;
+ bool wasDeathReceivedFirst = false;
+
+ std::function<void(void)> onUnlink = [&] {
+ std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
+ std::cerr << "Binder unlinked (as requested)." << std::endl;
+ wasDeathReceivedFirst = deathReceived;
+ unlinkReceived = true;
+ unlinkCv.notify_one();
+ };
+
+ ndk::ScopedAIBinder_DeathRecipient recipient(AIBinder_DeathRecipient_new(LambdaOnDeath));
+ AIBinder_DeathRecipient_setOnUnlinked(recipient.get(), LambdaOnUnlink);
+
+ foo = IFoo::getService(IFoo::kInstanceNameToDieFor2, &binder);
+ ASSERT_NE(nullptr, foo.get());
+ ASSERT_NE(nullptr, binder);
+
+ DeathRecipientCookie* cookie = new DeathRecipientCookie{&onDeath, &onUnlink};
+ EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient.get(), static_cast<void*>(cookie)));
+
+ EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+
+ {
+ std::unique_lock<std::mutex> lockDeath(deathMutex);
+ EXPECT_TRUE(deathCv.wait_for(lockDeath, 1s, [&] { return deathReceived; }));
+ EXPECT_TRUE(deathReceived);
+ }
+
+ {
+ std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
+ EXPECT_TRUE(deathCv.wait_for(lockUnlink, 100ms, [&] { return unlinkReceived; }));
+ EXPECT_TRUE(unlinkReceived);
+ EXPECT_TRUE(wasDeathReceivedFirst);
+ }
+}
+
TEST(NdkBinder, RetrieveNonNdkService) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -958,6 +1076,10 @@
}
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/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
index 3fe71ce..3c8c41f 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/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_library_headers {
diff --git a/libs/bufferstreams/Android.bp b/libs/bufferstreams/Android.bp
index 6c2a980..03ab31e 100644
--- a/libs/bufferstreams/Android.bp
+++ b/libs/bufferstreams/Android.bp
@@ -14,6 +14,7 @@
package {
default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
aconfig_declarations {
diff --git a/libs/bufferstreams/aidl/Android.bp b/libs/bufferstreams/aidl/Android.bp
new file mode 100644
index 0000000..3f1fa4e
--- /dev/null
+++ b/libs/bufferstreams/aidl/Android.bp
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+aidl_interface {
+ name: "android.graphics.bufferstreams",
+ unstable: true,
+ flags: ["-Werror"],
+ srcs: ["android/graphics/bufferstreams/*.aidl"],
+ headers: [
+ "HardwareBuffer_aidl",
+ ],
+ imports: [
+ "android.hardware.common-V2",
+ ],
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ enabled: false,
+ },
+ ndk: {
+ enabled: false,
+ },
+ rust: {
+ enabled: true,
+ additional_rustlibs: [
+ "libnativewindow_rs",
+ ],
+ },
+ },
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferAttachment.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferAttachment.aidl
new file mode 100644
index 0000000..5c905b1
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferAttachment.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.bufferstreams;
+
+import android.graphics.bufferstreams.IBufferOwner;
+import android.hardware.HardwareBuffer;
+
+// Single mapping between a buffer reference and heavy-weight data (like the
+// buffer itself) and data that is stable between frames.
+parcelable BufferAttachment {
+ // The HardwareBuffer itself.
+ //
+ // This field is @nullable for codegen, since HardwareBuffer doesn't implement Default in Rust.
+ // In practice, it should never be null.
+ @nullable HardwareBuffer buffer;
+ // The buffer owner to which this buffer should be returned.
+ IBufferOwner owner;
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferCacheUpdate.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferCacheUpdate.aidl
new file mode 100644
index 0000000..7504119
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/BufferCacheUpdate.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.bufferstreams;
+
+import android.graphics.bufferstreams.BufferAttachment;
+
+// A event that changes the state downstream buffer caches. Clients are responsible for forwarding
+// these messages to their clients.
+union BufferCacheUpdate {
+ // Event requiring downstream caches to add new entries.
+ CacheBuffers cacheBuffers;
+ // Event requiring downstream caches to remove entries.
+ ForgetBuffers forgetBuffers;
+
+ parcelable CacheBuffers {
+ // Attachments to add.
+ List<BufferAttachment> attachments;
+ }
+
+ parcelable ForgetBuffers {
+ // References to remove.
+ long[] bufferIds;
+ }
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/Frame.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/Frame.aidl
new file mode 100644
index 0000000..1e0ec3b
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/Frame.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.bufferstreams;
+
+import android.os.ParcelFileDescriptor;
+
+// A Frame represents a single buffer passing through the stream.
+parcelable Frame {
+ // The service must have provided an associated BufferAttachment and the client is required to
+ // maintain a cache between the two.
+ long bufferId;
+ // The expected present time of this frame, or -1 if immediate.
+ long presentTimeNs;
+ // The acquire fence of the buffer for this frame.
+ @nullable ParcelFileDescriptor fence;
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferOwner.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferOwner.aidl
new file mode 100644
index 0000000..8b25a62
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferOwner.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.bufferstreams;
+
+import android.os.ParcelFileDescriptor;
+
+// Interface from a client back to the owner of a buffer.
+interface IBufferOwner {
+ // Called when the buffer is done being processed by the stream to return its owner.
+ oneway void onBufferReleased(in long bufferId, in @nullable ParcelFileDescriptor releaseFence);
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscriber.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscriber.aidl
new file mode 100644
index 0000000..52e8216
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscriber.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.bufferstreams;
+
+import android.graphics.bufferstreams.BufferCacheUpdate;
+import android.graphics.bufferstreams.IBufferSubscription;
+import android.graphics.bufferstreams.Frame;
+
+// Interface provided by clients to a service, mirroring the non-IPC interface.
+//
+// Clients are required to maintain a local cache of Buffer IDs to BufferAttachments.
+interface IBufferSubscriber {
+ // Provide a BufferSubscription object which the client can use to request frames.
+ oneway void onSubscribe(in IBufferSubscription subscription);
+
+ // Notifies the client to update its local caches.
+ oneway void onBufferCacheUpdate(in BufferCacheUpdate update);
+
+ // Notifies the client that a requested frame is available.
+ oneway void onNext(in Frame frame);
+
+ // Notifies the client that a fatal error has occurred. No subsequent on_next events will be
+ // sent by the service.
+ //
+ // Clients must empty their caches.
+ oneway void onError();
+
+ // Notifies the client that no further on_next events will be sent by the service in response
+ // to it cancelling the subscription.
+ //
+ // Clients must empty their caches.
+ oneway void onComplete();
+}
diff --git a/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscription.aidl b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscription.aidl
new file mode 100644
index 0000000..c37f4e6
--- /dev/null
+++ b/libs/bufferstreams/aidl/android/graphics/bufferstreams/IBufferSubscription.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.bufferstreams;
+
+// Interface provided to a IBufferSubscriber to request frames or gracefully cancel their
+// subscription.
+interface IBufferSubscription {
+ // Request n more frames.
+ oneway void request(long n);
+ // Cancel the subscription. Requested frames may continue to arrive.
+ oneway void cancel();
+}
diff --git a/libs/bufferstreams/examples/app/Android.bp b/libs/bufferstreams/examples/app/Android.bp
index bb573c5..5b3ec30 100644
--- a/libs/bufferstreams/examples/app/Android.bp
+++ b/libs/bufferstreams/examples/app/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
+}
+
android_app {
name: "BufferStreamsDemoApp",
srcs: ["java/**/*.kt"],
diff --git a/libs/bufferstreams/examples/app/jni/Android.bp b/libs/bufferstreams/examples/app/jni/Android.bp
index 67910a1..003f4ed 100644
--- a/libs/bufferstreams/examples/app/jni/Android.bp
+++ b/libs/bufferstreams/examples/app/jni/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
+}
+
cc_library_shared {
name: "libbufferstreamdemoapp",
cflags: [
diff --git a/libs/bufferstreams/rust/Android.bp b/libs/bufferstreams/rust/Android.bp
index 7fcb222..34feb5d 100644
--- a/libs/bufferstreams/rust/Android.bp
+++ b/libs/bufferstreams/rust/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
+}
+
rust_defaults {
name: "libbufferstreams_defaults",
srcs: ["src/lib.rs"],
diff --git a/libs/bufferstreams/rust/src/buffers/buffer_owner.rs b/libs/bufferstreams/rust/src/buffers/buffer_owner.rs
index a4abb9d..155a8bf 100644
--- a/libs/bufferstreams/rust/src/buffers/buffer_owner.rs
+++ b/libs/bufferstreams/rust/src/buffers/buffer_owner.rs
@@ -16,7 +16,7 @@
/// Trait that represents an owner of a buffer that might need to handle events such as a buffer
/// being dropped.
-pub trait BufferOwner {
+pub trait BufferOwner: Send + Sync {
/// Called when a buffer is dropped.
fn on_return(&self, buffer: &Buffer);
}
diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs
index be1525d..17d4d87 100644
--- a/libs/bufferstreams/rust/src/lib.rs
+++ b/libs/bufferstreams/rust/src/lib.rs
@@ -23,8 +23,6 @@
use buffers::Buffer;
pub use stream_config::*;
-use std::time::Instant;
-
/// This function will print Hello World.
#[no_mangle]
pub extern "C" fn hello() -> bool {
@@ -106,7 +104,8 @@
/// BufferSubscriptions serve as the bridge between BufferPublishers and
/// BufferSubscribers. BufferSubscribers receive a BufferSubscription when they
/// subscribe to a BufferPublisher via on_subscribe.
-/// This object is to be used by the BufferSubscriber to cancel its subscription
+///
+/// This object is used by the BufferSubscriber to cancel its subscription
/// or request more buffers.
///
/// BufferSubcriptions are required to adhere to the following, based on the
@@ -147,7 +146,7 @@
/// no other Subscription exists at this point.
/// * Calling Subscription.cancel MUST return normally.
/// * Calling Subscription.request MUST return normally.
-pub trait BufferSubscription {
+pub trait BufferSubscription: Send + Sync + 'static {
/// request
fn request(&self, n: u64);
/// cancel
@@ -161,8 +160,8 @@
pub struct Frame {
/// A buffer to be used this frame.
pub buffer: Buffer,
- /// The time at which the buffer was dispatched.
- pub present_time: Instant,
+ /// The time at which this buffer is expected to be displayed.
+ pub present_time: i64,
/// A fence used for reading/writing safely.
pub fence: i32,
}
@@ -175,14 +174,12 @@
use anyhow::anyhow;
use buffers::Buffer;
use nativewindow::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
- use std::borrow::BorrowMut;
- use std::error::Error;
- use std::ops::Add;
- use std::sync::Arc;
- use std::time::Duration;
+ use std::{borrow::BorrowMut, error::Error, ops::Add, sync::Arc};
- use crate::publishers::testing::*;
- use crate::subscribers::{testing::*, SharedSubscriber};
+ use crate::{
+ publishers::testing::*,
+ subscribers::{testing::*, SharedSubscriber},
+ };
const STREAM_CONFIG: StreamConfig = StreamConfig {
width: 1,
@@ -200,7 +197,7 @@
.create_hardware_buffer()
.expect("Unable to create hardware buffer for test"),
),
- present_time: Instant::now() + Duration::from_secs(1),
+ present_time: 1,
fence: 0,
}
}
diff --git a/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs b/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
index 846105d..73a15be 100644
--- a/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
+++ b/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs
@@ -14,8 +14,6 @@
//!
-use std::time::Instant;
-
use crate::{
buffers::BufferPool, subscriptions::SharedBufferSubscription, BufferPublisher,
BufferSubscriber, Frame, StreamConfig,
@@ -43,7 +41,7 @@
/// If the [SharedBufferSubscription] is ready for a [Frame], a buffer will be requested from
/// [BufferPool] and sent over to the [BufferSubscriber].
- pub fn send_next_frame(&mut self, present_time: Instant) -> bool {
+ pub fn send_next_frame(&mut self, present_time: i64) -> bool {
if let Some(subscriber) = self.subscriber.as_mut() {
if self.subscription.take_request() {
if let Some(buffer) = self.buffer_pool.next_buffer() {
@@ -103,7 +101,7 @@
subscriber.map_inner(|s| s.request(1));
- assert!(buffer_pool_publisher.send_next_frame(Instant::now()));
+ assert!(buffer_pool_publisher.send_next_frame(1));
let events = subscriber.map_inner_mut(|s| s.take_events());
assert!(matches!(events.last().unwrap(), TestingSubscriberEvent::Next(_)));
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/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index aab1276..f300da5 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -19,6 +19,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_library {
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 3c3b6af..8337182 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/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_fuzz {
diff --git a/libs/gralloc/types/tests/Android.bp b/libs/gralloc/types/tests/Android.bp
index 66eb0aa..b796c03 100644
--- a/libs/gralloc/types/tests/Android.bp
+++ b/libs/gralloc/types/tests/Android.bp
@@ -21,6 +21,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 {
@@ -30,5 +31,8 @@
"libhidlbase",
],
srcs: ["Gralloc4_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 4c3cc6c..70cb36b 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -18,6 +18,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",
}
aconfig_declarations {
diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp
index cd738ac..35dd9ec 100644
--- a/libs/gui/fuzzer/Android.bp
+++ b/libs/gui/fuzzer/Android.bp
@@ -20,6 +20,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_defaults {
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index cc33e4c..386767b 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/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",
}
sysprop_library {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 1c713f9..9e0ce1d 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -1007,6 +1007,33 @@
return out;
}
+bool MotionEvent::operator==(const android::MotionEvent& o) const {
+ // We use NaN values to represent invalid cursor positions. Since NaN values are not equal
+ // to themselves according to IEEE 754, we cannot use the default equality operator to compare
+ // MotionEvents. Therefore we define a custom equality operator with special handling for NaNs.
+ // clang-format off
+ return InputEvent::operator==(static_cast<const InputEvent&>(o)) &&
+ mAction == o.mAction &&
+ mActionButton == o.mActionButton &&
+ mFlags == o.mFlags &&
+ mEdgeFlags == o.mEdgeFlags &&
+ mMetaState == o.mMetaState &&
+ mButtonState == o.mButtonState &&
+ mClassification == o.mClassification &&
+ mTransform == o.mTransform &&
+ mXPrecision == o.mXPrecision &&
+ mYPrecision == o.mYPrecision &&
+ ((std::isnan(mRawXCursorPosition) && std::isnan(o.mRawXCursorPosition)) ||
+ mRawXCursorPosition == o.mRawXCursorPosition) &&
+ ((std::isnan(mRawYCursorPosition) && std::isnan(o.mRawYCursorPosition)) ||
+ mRawYCursorPosition == o.mRawYCursorPosition) &&
+ mRawTransform == o.mRawTransform && mDownTime == o.mDownTime &&
+ mPointerProperties == o.mPointerProperties &&
+ mSampleEventTimes == o.mSampleEventTimes &&
+ mSamplePointerCoords == o.mSamplePointerCoords;
+ // clang-format on
+}
+
std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction());
if (event.getActionButton() != 0) {
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/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index 342f5de..f7f20b4 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -16,6 +16,7 @@
default_applicable_licenses: [
"frameworks_native_libs_nativedisplay_license",
],
+ default_team: "trendy_team_android_core_graphics_stack",
}
// Added automatically by a large-scale-change
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index bc0bfc5..0e90327 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -16,6 +16,7 @@
default_applicable_licenses: [
"frameworks_native_libs_nativewindow_license",
],
+ default_team: "trendy_team_android_core_graphics_stack",
}
// Added automatically by a large-scale-change
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index bcfae10..48fb02f 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -107,7 +107,7 @@
};
/**
- * Additional options for AHardwareBuffer_allocate2. These correspond to
+ * Additional options for AHardwareBuffer_allocateWithOptions. These correspond to
* android.hardware.graphics.common.ExtendableType
*/
typedef struct {
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
index 90d0a8e..a3df482 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -16,6 +16,7 @@
default_applicable_licenses: [
"frameworks_native_libs_nativewindow_license",
],
+ default_team: "trendy_team_android_core_graphics_stack",
}
rust_bindgen {
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index d7c7eb3..a4ebcac 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -23,6 +23,7 @@
default_applicable_licenses: [
"frameworks_native_libs_nativewindow_license",
],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
diff --git a/libs/nativewindow/tests/benchmark/Android.bp b/libs/nativewindow/tests/benchmark/Android.bp
index 6f844cf..b815d80 100644
--- a/libs/nativewindow/tests/benchmark/Android.bp
+++ b/libs/nativewindow/tests/benchmark/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
+}
+
cc_defaults {
name: "nativewindow_benchmark_defaults_cc",
shared_libs: ["libnativewindow"],
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index fd45840..b501d40 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/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_defaults {
diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp
index 87e21c2..e1a6f6a 100644
--- a/libs/renderengine/benchmark/Android.bp
+++ b/libs/renderengine/benchmark/Android.bp
@@ -19,6 +19,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_benchmark {
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 473e1d4..0eea187 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -19,6 +19,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/shaders/Android.bp b/libs/shaders/Android.bp
index 960f845..82fbfda 100644
--- a/libs/shaders/Android.bp
+++ b/libs/shaders/Android.bp
@@ -19,6 +19,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_library_static {
diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp
index 5639d74..2103679 100644
--- a/libs/shaders/tests/Android.bp
+++ b/libs/shaders/tests/Android.bp
@@ -19,6 +19,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/tonemap/Android.bp b/libs/tonemap/Android.bp
index 8c8815d..d569ac3 100644
--- a/libs/tonemap/Android.bp
+++ b/libs/tonemap/Android.bp
@@ -19,6 +19,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_library_static {
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
index 5c5fc6c..79ee7c2 100644
--- a/libs/tonemap/tests/Android.bp
+++ b/libs/tonemap/tests/Android.bp
@@ -19,6 +19,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/ui/Android.bp b/libs/ui/Android.bp
index ec0ab4e..9cb298a 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -14,6 +14,7 @@
package {
default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
// Added automatically by a large-scale-change
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 9a20215..2d8a1e3 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -21,6 +21,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_test {
diff --git a/libs/ui/tools/Android.bp b/libs/ui/tools/Android.bp
index 5d6070c..cc233b9 100644
--- a/libs/ui/tools/Android.bp
+++ b/libs/ui/tools/Android.bp
@@ -21,6 +21,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+ default_team: "trendy_team_android_core_graphics_stack",
}
cc_defaults {
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/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 513cbfa..293ad66 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -285,5 +285,10 @@
{
"name": "CtsInputHostTestCases"
}
+ ],
+ "staged-platinum-postsubmit": [
+ {
+ "name": "inputflinger_tests"
+ }
]
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 8d43f3b..f31884e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -365,17 +365,20 @@
return i;
}
-std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
+std::unique_ptr<DispatchEntry> createDispatchEntry(const IdGenerator& idGenerator,
+ const InputTarget& inputTarget,
std::shared_ptr<const EventEntry> eventEntry,
ftl::Flags<InputTarget::Flags> inputTargetFlags,
int64_t vsyncId) {
+ const bool zeroCoords = inputTargetFlags.test(InputTarget::Flags::ZERO_COORDS);
const sp<WindowInfoHandle> win = inputTarget.windowHandle;
const std::optional<int32_t> windowId =
win ? std::make_optional(win->getInfo()->id) : std::nullopt;
// Assume the only targets that are not associated with a window are global monitors, and use
// the system UID for global monitors for tracing purposes.
const gui::Uid uid = win ? win->getInfo()->ownerUid : gui::Uid(AID_SYSTEM);
- if (inputTarget.useDefaultPointerTransform()) {
+
+ if (inputTarget.useDefaultPointerTransform() && !zeroCoords) {
const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
inputTarget.displayTransform,
@@ -386,33 +389,39 @@
ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
- std::vector<PointerCoords> pointerCoords;
- pointerCoords.resize(motionEntry.getPointerCount());
+ std::vector<PointerCoords> pointerCoords{motionEntry.getPointerCount()};
- // Use the first pointer information to normalize all other pointers. This could be any pointer
- // as long as all other pointers are normalized to the same value and the final DispatchEntry
- // uses the transform for the normalized pointer.
- const ui::Transform& firstPointerTransform =
- inputTarget.pointerTransforms[firstMarkedBit(inputTarget.pointerIds)];
- ui::Transform inverseFirstTransform = firstPointerTransform.inverse();
+ const ui::Transform* transform = &kIdentityTransform;
+ const ui::Transform* displayTransform = &kIdentityTransform;
+ if (zeroCoords) {
+ std::for_each(pointerCoords.begin(), pointerCoords.end(), [](auto& pc) { pc.clear(); });
+ } else {
+ // Use the first pointer information to normalize all other pointers. This could be any
+ // pointer as long as all other pointers are normalized to the same value and the final
+ // DispatchEntry uses the transform for the normalized pointer.
+ transform =
+ &inputTarget.getTransformForPointer(firstMarkedBit(inputTarget.getPointerIds()));
+ const ui::Transform inverseTransform = transform->inverse();
+ displayTransform = &inputTarget.displayTransform;
- // Iterate through all pointers in the event to normalize against the first.
- for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.getPointerCount(); pointerIndex++) {
- const PointerProperties& pointerProperties = motionEntry.pointerProperties[pointerIndex];
- uint32_t pointerId = uint32_t(pointerProperties.id);
- const ui::Transform& currTransform = inputTarget.pointerTransforms[pointerId];
+ // Iterate through all pointers in the event to normalize against the first.
+ for (size_t i = 0; i < motionEntry.getPointerCount(); i++) {
+ PointerCoords& newCoords = pointerCoords[i];
+ const auto pointerId = motionEntry.pointerProperties[i].id;
+ const ui::Transform& currTransform = inputTarget.getTransformForPointer(pointerId);
- pointerCoords[pointerIndex].copyFrom(motionEntry.pointerCoords[pointerIndex]);
- // First, apply the current pointer's transform to update the coordinates into
- // window space.
- pointerCoords[pointerIndex].transform(currTransform);
- // Next, apply the inverse transform of the normalized coordinates so the
- // current coordinates are transformed into the normalized coordinate space.
- pointerCoords[pointerIndex].transform(inverseFirstTransform);
+ newCoords.copyFrom(motionEntry.pointerCoords[i]);
+ // First, apply the current pointer's transform to update the coordinates into
+ // window space.
+ newCoords.transform(currTransform);
+ // Next, apply the inverse transform of the normalized coordinates so the
+ // current coordinates are transformed into the normalized coordinate space.
+ newCoords.transform(inverseTransform);
+ }
}
std::unique_ptr<MotionEntry> combinedMotionEntry =
- std::make_unique<MotionEntry>(motionEntry.id, motionEntry.injectionState,
+ std::make_unique<MotionEntry>(idGenerator.nextId(), motionEntry.injectionState,
motionEntry.eventTime, motionEntry.deviceId,
motionEntry.source, motionEntry.displayId,
motionEntry.policyFlags, motionEntry.action,
@@ -426,7 +435,7 @@
std::unique_ptr<DispatchEntry> dispatchEntry =
std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
- firstPointerTransform, inputTarget.displayTransform,
+ *transform, *displayTransform,
inputTarget.globalScaleFactor, uid, vsyncId, windowId);
return dispatchEntry;
}
@@ -1303,6 +1312,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;
}
@@ -1630,14 +1640,12 @@
if (connection == nullptr) {
return; // Connection has gone away
}
- InputTarget target;
- target.connection = connection;
entry->dispatchInProgress = true;
std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
connection->getInputChannelName();
std::string reason = std::string("reason=").append(entry->reason);
android_log_event_list(LOGTAG_INPUT_FOCUS) << message << reason << LOG_ID_EVENTS;
- dispatchEventLocked(currentTime, entry, {target});
+ dispatchEventLocked(currentTime, entry, {{connection}});
}
void InputDispatcher::dispatchPointerCaptureChangedLocked(
@@ -1703,10 +1711,8 @@
}
return;
}
- InputTarget target;
- target.connection = connection;
entry->dispatchInProgress = true;
- dispatchEventLocked(currentTime, entry, {target});
+ dispatchEventLocked(currentTime, entry, {{connection}});
dropReason = DropReason::NOT_DROPPED;
}
@@ -1739,9 +1745,7 @@
if (connection == nullptr) {
continue; // Connection has gone away
}
- InputTarget target;
- target.connection = connection;
- inputTargets.push_back(target);
+ inputTargets.emplace_back(connection);
}
return inputTargets;
}
@@ -2022,10 +2026,8 @@
if (connection == nullptr) {
return; // Connection has gone away
}
- InputTarget target;
- target.connection = connection;
entry->dispatchInProgress = true;
- dispatchEventLocked(currentTime, entry, {target});
+ dispatchEventLocked(currentTime, entry, {{connection}});
}
void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry& entry) {
@@ -2868,8 +2870,7 @@
ALOGW("Not creating InputTarget for %s, no input channel", windowHandle->getName().c_str());
return {};
}
- InputTarget inputTarget;
- inputTarget.connection = connection;
+ InputTarget inputTarget{connection};
inputTarget.windowHandle = windowHandle;
inputTarget.dispatchMode = dispatchMode;
inputTarget.flags = targetFlags;
@@ -2982,8 +2983,7 @@
if (monitorsIt == mGlobalMonitorsByDisplay.end()) return;
for (const Monitor& monitor : selectResponsiveMonitorsLocked(monitorsIt->second)) {
- InputTarget target;
- target.connection = monitor.connection;
+ InputTarget target{monitor.connection};
// target.firstDownTimeInTarget is not set for global monitors. It is only required in split
// touch and global monitoring works as intended even without setting firstDownTimeInTarget
if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
@@ -3275,7 +3275,7 @@
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=%s, "
"globalScaleFactor=%f, pointerIds=%s %s",
connection->getInputChannelName().c_str(), inputTarget.flags.string().c_str(),
- inputTarget.globalScaleFactor, bitsetToString(inputTarget.pointerIds).c_str(),
+ inputTarget.globalScaleFactor, bitsetToString(inputTarget.getPointerIds()).c_str(),
inputTarget.getPointerInfoString().c_str());
}
@@ -3297,7 +3297,7 @@
ftl::enum_string(eventEntry->type).c_str());
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
- if (inputTarget.pointerIds.count() != originalMotionEntry.getPointerCount()) {
+ if (inputTarget.getPointerIds().count() != originalMotionEntry.getPointerCount()) {
if (!inputTarget.firstDownTimeInTarget.has_value()) {
logDispatchStateLocked();
LOG(FATAL) << "Splitting motion events requires a down time to be set for the "
@@ -3306,7 +3306,7 @@
<< originalMotionEntry.getDescription();
}
std::unique_ptr<MotionEntry> splitMotionEntry =
- splitMotionEvent(originalMotionEntry, inputTarget.pointerIds,
+ splitMotionEvent(originalMotionEntry, inputTarget.getPointerIds(),
inputTarget.firstDownTimeInTarget.value());
if (!splitMotionEntry) {
return; // split event was dropped
@@ -3364,7 +3364,8 @@
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
std::unique_ptr<DispatchEntry> dispatchEntry =
- createDispatchEntry(inputTarget, eventEntry, inputTarget.flags, mWindowInfosVsyncId);
+ createDispatchEntry(mIdGenerator, inputTarget, eventEntry, inputTarget.flags,
+ mWindowInfosVsyncId);
// Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
// different EventEntry than what was passed in.
@@ -3485,7 +3486,7 @@
<< connection->getInputChannelName() << " with event "
<< cancelEvent->getDescription();
std::unique_ptr<DispatchEntry> cancelDispatchEntry =
- createDispatchEntry(inputTarget, std::move(cancelEvent),
+ createDispatchEntry(mIdGenerator, inputTarget, std::move(cancelEvent),
ftl::Flags<InputTarget::Flags>(), mWindowInfosVsyncId);
// Send these cancel events to the queue before sending the event from the new
@@ -3664,12 +3665,6 @@
}
usingCoords = scaledCoords;
}
- } else if (dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS)) {
- // We don't want the dispatch target to know the coordinates
- for (uint32_t i = 0; i < motionEntry.getPointerCount(); i++) {
- scaledCoords[i].clear();
- }
- usingCoords = scaledCoords;
}
std::array<uint8_t, 32> hmac = getSignature(motionEntry, dispatchEntry);
@@ -4109,7 +4104,7 @@
const bool wasEmpty = connection->outboundQueue.empty();
// The target to use if we don't find a window associated with the channel.
- const InputTarget fallbackTarget{.connection = connection};
+ const InputTarget fallbackTarget{connection};
const auto& token = connection->getToken();
for (size_t i = 0; i < cancelationEvents.size(); i++) {
@@ -4227,8 +4222,7 @@
targetFlags, pointerIds, motionEntry.downTime,
targets);
} else {
- targets.emplace_back(
- InputTarget{.connection = connection, .flags = targetFlags});
+ targets.emplace_back(connection, targetFlags);
const auto it = mDisplayInfos.find(motionEntry.displayId);
if (it != mDisplayInfos.end()) {
targets.back().displayTransform = it->second.transform;
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index 28e3c6d..35ad858 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -26,6 +26,15 @@
namespace android::inputdispatcher {
+namespace {
+
+const static ui::Transform kIdentityTransform{};
+
+}
+
+InputTarget::InputTarget(const std::shared_ptr<Connection>& connection, ftl::Flags<Flags> flags)
+ : connection(connection), flags(flags) {}
+
void InputTarget::addPointers(std::bitset<MAX_POINTER_ID + 1> newPointerIds,
const ui::Transform& transform) {
// The pointerIds can be empty, but still a valid InputTarget. This can happen when there is no
@@ -36,31 +45,46 @@
}
// Ensure that the new set of pointers doesn't overlap with the current set of pointers.
- if ((pointerIds & newPointerIds).any()) {
+ if ((getPointerIds() & newPointerIds).any()) {
LOG(FATAL) << __func__ << " - overlap with incoming pointers "
<< bitsetToString(newPointerIds) << " in " << *this;
}
- pointerIds |= newPointerIds;
- for (size_t i = 0; i < newPointerIds.size(); i++) {
- if (!newPointerIds.test(i)) {
- continue;
+ for (auto& [existingTransform, existingPointers] : mPointerTransforms) {
+ if (transform == existingTransform) {
+ existingPointers |= newPointerIds;
+ return;
}
- pointerTransforms[i] = transform;
}
+ mPointerTransforms.emplace_back(transform, newPointerIds);
}
void InputTarget::setDefaultPointerTransform(const ui::Transform& transform) {
- pointerIds.reset();
- pointerTransforms[0] = transform;
+ mPointerTransforms = {{transform, {}}};
}
bool InputTarget::useDefaultPointerTransform() const {
- return pointerIds.none();
+ return mPointerTransforms.size() <= 1;
}
const ui::Transform& InputTarget::getDefaultPointerTransform() const {
- return pointerTransforms[0];
+ if (!useDefaultPointerTransform()) {
+ LOG(FATAL) << __func__ << ": Not using default pointer transform";
+ }
+ return mPointerTransforms.size() == 1 ? mPointerTransforms[0].first : kIdentityTransform;
+}
+
+const ui::Transform& InputTarget::getTransformForPointer(int32_t pointerId) const {
+ for (const auto& [transform, ids] : mPointerTransforms) {
+ if (ids.test(pointerId)) {
+ return transform;
+ }
+ }
+
+ LOG(FATAL) << __func__
+ << ": Cannot get transform: The following Pointer ID does not exist in target: "
+ << pointerId;
+ return kIdentityTransform;
}
std::string InputTarget::getPointerInfoString() const {
@@ -71,17 +95,21 @@
return out;
}
- for (uint32_t i = 0; i < pointerIds.size(); i++) {
- if (!pointerIds.test(i)) {
- continue;
- }
-
- const std::string name = "pointerId " + std::to_string(i) + ":";
- pointerTransforms[i].dump(out, name.c_str(), " ");
+ for (const auto& [transform, ids] : mPointerTransforms) {
+ const std::string name = "pointerIds " + bitsetToString(ids) + ":";
+ transform.dump(out, name.c_str(), " ");
}
return out;
}
+std::bitset<MAX_POINTER_ID + 1> InputTarget::getPointerIds() const {
+ PointerIds allIds;
+ for (const auto& [_, ids] : mPointerTransforms) {
+ allIds |= ids;
+ }
+ return allIds;
+}
+
std::ostream& operator<<(std::ostream& out, const InputTarget& target) {
out << "{connection=";
if (target.connection != nullptr) {
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 5728bdf..058639a 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -33,7 +33,8 @@
* be added to input event coordinates to compensate for the absolute position of the
* window area.
*/
-struct InputTarget {
+class InputTarget {
+public:
using Flags = InputTargetFlags;
enum class DispatchMode {
@@ -80,20 +81,17 @@
// Current display transform. Used for compatibility for raw coordinates.
ui::Transform displayTransform;
- // The subset of pointer ids to include in motion events dispatched to this input target
- // if FLAG_SPLIT is set.
- std::bitset<MAX_POINTER_ID + 1> pointerIds;
// Event time for the first motion event (ACTION_DOWN) dispatched to this input target if
// FLAG_SPLIT is set.
std::optional<nsecs_t> firstDownTimeInTarget;
- // The data is stored by the pointerId. Use the bit position of pointerIds to look up
- // Transform per pointerId.
- ui::Transform pointerTransforms[MAX_POINTERS];
// The window that this input target is being dispatched to. It is possible for this to be
// null for cases like global monitors.
sp<gui::WindowInfoHandle> windowHandle;
+ InputTarget() = default;
+ InputTarget(const std::shared_ptr<Connection>&, ftl::Flags<Flags> = {});
+
void addPointers(std::bitset<MAX_POINTER_ID + 1> pointerIds, const ui::Transform& transform);
void setDefaultPointerTransform(const ui::Transform& transform);
@@ -111,7 +109,22 @@
*/
const ui::Transform& getDefaultPointerTransform() const;
+ const ui::Transform& getTransformForPointer(int32_t pointerId) const;
+
+ std::bitset<MAX_POINTER_ID + 1> getPointerIds() const;
+
std::string getPointerInfoString() const;
+
+private:
+ template <typename K, typename V>
+ using ArrayMap = std::vector<std::pair<K, V>>;
+ using PointerIds = std::bitset<MAX_POINTER_ID + 1>;
+ // The mapping of pointer IDs to the transform that should be used for that collection of IDs.
+ // Each of the pointer IDs are mutually disjoint, and their union makes up pointer IDs to
+ // include in the motion events dispatched to this target. We use an ArrayMap to store this to
+ // avoid having to define hash or comparison functions for ui::Transform, which would be needed
+ // to use std::unordered_map or std::map respectively.
+ ArrayMap<ui::Transform, PointerIds> mPointerTransforms;
};
std::ostream& operator<<(std::ostream& out, const InputTarget& target);
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 19788ce..797ebcc 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -67,7 +67,8 @@
: mDeviceId(deviceId),
mReaderContext(readerContext),
mPointerController(readerContext.getPointerController(deviceId)),
- mEnablePointerChoreographer(input_flags::enable_pointer_choreographer()) {
+ mEnablePointerChoreographer(input_flags::enable_pointer_choreographer()),
+ mEnableFlingStop(input_flags::enable_touchpad_fling_stop()) {
deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mXAxisInfo);
deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mYAxisInfo);
}
@@ -400,20 +401,55 @@
// ensure consistency between touchscreen and touchpad flings), so we're just using
// the "start fling" gestures as a marker for the end of a two-finger scroll
// gesture.
+ mFlingMayBeInProgress = true;
return endScroll(when, readTime);
}
break;
case GESTURES_FLING_TAP_DOWN:
if (mCurrentClassification == MotionClassification::NONE) {
- // Use the tap down state of a fling gesture as an indicator that a contact
- // has been initiated with the touchpad. We treat this as a move event with zero
- // magnitude, which will also result in the pointer icon being updated.
- // TODO(b/282023644): Add a signal in libgestures for when a stable contact has been
- // initiated with a touchpad.
- return handleMove(when, readTime, gestureStartTime,
- Gesture(kGestureMove, gesture.start_time, gesture.end_time,
- /*dx=*/0.f,
- /*dy=*/0.f));
+ if (mEnableFlingStop && mFlingMayBeInProgress) {
+ // The user has just touched the pad again after ending a two-finger scroll
+ // motion, which might have started a fling. We want to stop the fling, but
+ // unfortunately there's currently no API for doing so. Instead, send and
+ // immediately cancel a fake finger to cause the scrolling to stop and hopefully
+ // avoid side effects (e.g. activation of UI elements).
+ // TODO(b/326056750): add an API for fling stops.
+ mFlingMayBeInProgress = false;
+ const auto [xCursorPosition, yCursorPosition] = mEnablePointerChoreographer
+ ? FloatPoint{0, 0}
+ : mPointerController->getPosition();
+ PointerCoords coords;
+ coords.clear();
+ coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
+
+ std::list<NotifyArgs> out;
+ mDownTime = when;
+ out += exitHover(when, readTime, xCursorPosition, yCursorPosition);
+ // TODO(b/281106755): add a MotionClassification value for fling stops.
+ out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN,
+ /*actionButton=*/0, /*buttonState=*/0,
+ /*pointerCount=*/1, &coords, xCursorPosition,
+ yCursorPosition));
+ out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_CANCEL,
+ /*actionButton=*/0, /*buttonState=*/0,
+ /*pointerCount=*/1, &coords, xCursorPosition,
+ yCursorPosition));
+ out += enterHover(when, readTime, xCursorPosition, yCursorPosition);
+ return out;
+ } else {
+ // Use the tap down state of a fling gesture as an indicator that a contact
+ // has been initiated with the touchpad. We treat this as a move event with zero
+ // magnitude, which will also result in the pointer icon being updated.
+ // TODO(b/282023644): Add a signal in libgestures for when a stable contact has
+ // been initiated with a touchpad.
+ return handleMove(when, readTime, gestureStartTime,
+ Gesture(kGestureMove, gesture.start_time, gesture.end_time,
+ /*dx=*/0.f,
+ /*dy=*/0.f));
+ }
}
break;
default:
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index 07cc56c..ffab039 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -106,6 +106,7 @@
InputReaderContext& mReaderContext;
std::shared_ptr<PointerControllerInterface> mPointerController;
const bool mEnablePointerChoreographer;
+ const bool mEnableFlingStop;
std::optional<int32_t> mDisplayId;
FloatRect mBoundsInLogicalDisplay{};
@@ -120,6 +121,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/tests/FakeInputTracingBackend.cpp b/services/inputflinger/tests/FakeInputTracingBackend.cpp
index f4a06f7..b7af356 100644
--- a/services/inputflinger/tests/FakeInputTracingBackend.cpp
+++ b/services/inputflinger/tests/FakeInputTracingBackend.cpp
@@ -37,6 +37,30 @@
return std::visit([](const auto& event) { return event.id; }, v);
}
+MotionEvent toInputEvent(
+ const trace::TracedMotionEvent& e,
+ const trace::InputTracingBackendInterface::WindowDispatchArgs& dispatchArgs,
+ const std::array<uint8_t, 32>& hmac) {
+ MotionEvent traced;
+ traced.initialize(e.id, e.deviceId, e.source, e.displayId, hmac, e.action, e.actionButton,
+ dispatchArgs.resolvedFlags, e.edgeFlags, e.metaState, e.buttonState,
+ e.classification, dispatchArgs.transform, e.xPrecision, e.yPrecision,
+ e.xCursorPosition, e.yCursorPosition, dispatchArgs.rawTransform, e.downTime,
+ e.eventTime, e.pointerProperties.size(), e.pointerProperties.data(),
+ e.pointerCoords.data());
+ return traced;
+}
+
+KeyEvent toInputEvent(const trace::TracedKeyEvent& e,
+ const trace::InputTracingBackendInterface::WindowDispatchArgs& dispatchArgs,
+ const std::array<uint8_t, 32>& hmac) {
+ KeyEvent traced;
+ traced.initialize(e.id, e.deviceId, e.source, e.displayId, hmac, e.action,
+ dispatchArgs.resolvedFlags, e.keyCode, e.scanCode, e.metaState, e.repeatCount,
+ e.downTime, e.eventTime);
+ return traced;
+}
+
} // namespace
// --- VerifyingTrace ---
@@ -55,6 +79,7 @@
std::unique_lock lock(mLock);
base::ScopedLockAssertion assumeLocked(mLock);
+ // Poll for all expected events to be traced, and keep track of the latest poll result.
base::Result<void> result;
mEventTracedCondition.wait_for(lock, TRACE_TIMEOUT, [&]() REQUIRES(mLock) {
for (const auto& [expectedEvent, windowId] : mExpectedEvents) {
@@ -101,12 +126,39 @@
});
if (tracedDispatchesIt == mTracedWindowDispatches.end()) {
msg << "Expected dispatch of event with ID 0x" << std::hex << expectedEvent.getId()
- << " to window with ID 0x" << expectedWindowId << " to be traced, but it was not."
- << "\nExpected event: " << expectedEvent;
+ << " to window with ID 0x" << expectedWindowId << " to be traced, but it was not.\n"
+ << "Expected event: " << expectedEvent;
return error(msg);
}
- return {};
+ // Verify that the traced event matches the expected event exactly.
+ return std::visit(
+ [&](const auto& traced) -> base::Result<void> {
+ Event tracedEvent;
+ using T = std::decay_t<decltype(traced)>;
+ if constexpr (std::is_same_v<Event, MotionEvent> &&
+ std::is_same_v<T, trace::TracedMotionEvent>) {
+ tracedEvent =
+ toInputEvent(traced, *tracedDispatchesIt, expectedEvent.getHmac());
+ } else if constexpr (std::is_same_v<Event, KeyEvent> &&
+ std::is_same_v<T, trace::TracedKeyEvent>) {
+ tracedEvent =
+ toInputEvent(traced, *tracedDispatchesIt, expectedEvent.getHmac());
+ } else {
+ msg << "Received the wrong event type!\n"
+ << "Expected event: " << expectedEvent;
+ return error(msg);
+ }
+
+ const auto result = testing::internal::CmpHelperEQ("expectedEvent", "tracedEvent",
+ expectedEvent, tracedEvent);
+ if (!result) {
+ msg << result.failure_message();
+ return error(msg);
+ }
+ return {};
+ },
+ tracedEventsIt->second);
}
// --- FakeInputTracingBackend ---
@@ -114,7 +166,7 @@
void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) const {
{
std::scoped_lock lock(mTrace->mLock);
- mTrace->mTracedEvents.emplace(event.id);
+ mTrace->mTracedEvents.emplace(event.id, event);
}
mTrace->mEventTracedCondition.notify_all();
}
@@ -122,7 +174,7 @@
void FakeInputTracingBackend::traceMotionEvent(const trace::TracedMotionEvent& event) const {
{
std::scoped_lock lock(mTrace->mLock);
- mTrace->mTracedEvents.emplace(event.id);
+ mTrace->mTracedEvents.emplace(event.id, event);
}
mTrace->mEventTracedCondition.notify_all();
}
diff --git a/services/inputflinger/tests/FakeInputTracingBackend.h b/services/inputflinger/tests/FakeInputTracingBackend.h
index 40ca3a2..108419a 100644
--- a/services/inputflinger/tests/FakeInputTracingBackend.h
+++ b/services/inputflinger/tests/FakeInputTracingBackend.h
@@ -25,7 +25,7 @@
#include <condition_variable>
#include <memory>
#include <mutex>
-#include <unordered_set>
+#include <unordered_map>
#include <vector>
namespace android::inputdispatcher {
@@ -58,7 +58,7 @@
private:
std::mutex mLock;
std::condition_variable mEventTracedCondition;
- std::unordered_set<uint32_t /*eventId*/> mTracedEvents GUARDED_BY(mLock);
+ std::unordered_map<uint32_t /*eventId*/, trace::TracedEvent> mTracedEvents GUARDED_BY(mLock);
using WindowDispatchArgs = trace::InputTracingBackendInterface::WindowDispatchArgs;
std::vector<WindowDispatchArgs> mTracedWindowDispatches GUARDED_BY(mLock);
std::vector<std::pair<std::variant<KeyEvent, MotionEvent>, int32_t /*windowId*/>>
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index dd88165..ca9ef8e 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -1167,6 +1167,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 +2588,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/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index ceb3c41..f0f4d93 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3865,48 +3865,57 @@
// Touch down on the first window
mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}));
-
mDispatcher->waitForIdle();
- std::unique_ptr<MotionEvent> motionEvent1 = window1->consumeMotionEvent();
- ASSERT_NE(nullptr, motionEvent1);
+ const std::unique_ptr<MotionEvent> firstDown =
+ window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
+ ASSERT_EQ(firstDown->getDownTime(), firstDown->getEventTime());
window2->assertNoEvents();
- nsecs_t downTimeForWindow1 = motionEvent1->getDownTime();
- ASSERT_EQ(motionEvent1->getDownTime(), motionEvent1->getEventTime());
// Now touch down on the window with another pointer
mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
mDispatcher->waitForIdle();
- std::unique_ptr<MotionEvent> motionEvent2 = window2->consumeMotionEvent();
- ASSERT_NE(nullptr, motionEvent2);
- nsecs_t downTimeForWindow2 = motionEvent2->getDownTime();
- ASSERT_NE(downTimeForWindow1, downTimeForWindow2);
- ASSERT_EQ(motionEvent2->getDownTime(), motionEvent2->getEventTime());
+
+ const std::unique_ptr<MotionEvent> secondDown =
+ window2->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN)));
+ ASSERT_EQ(secondDown->getDownTime(), secondDown->getEventTime());
+ ASSERT_NE(firstDown->getDownTime(), secondDown->getDownTime());
+ // We currently send MOVE events to all windows receiving a split touch when there is any change
+ // in the touch state, even when none of the pointers in the split window actually moved.
+ // Document this behavior in the test.
+ window1->consumeMotionMove();
// Now move the pointer on the second window
mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
mDispatcher->waitForIdle();
- window2->consumeMotionEvent(WithDownTime(downTimeForWindow2));
+
+ window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
+ window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
// Now add new touch down on the second window
mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}));
mDispatcher->waitForIdle();
- window2->consumeMotionEvent(WithDownTime(downTimeForWindow2));
- // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
- window1->consumeMotionMove();
- window1->assertNoEvents();
+ window2->consumeMotionEvent(
+ AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(secondDown->getDownTime())));
+ window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
// Now move the pointer on the first window
mDispatcher->notifyMotion(
generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}));
mDispatcher->waitForIdle();
- window1->consumeMotionEvent(WithDownTime(downTimeForWindow1));
+ window1->consumeMotionEvent(WithDownTime(firstDown->getDownTime()));
+ window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
+
+ // Now add new touch down on the first window
mDispatcher->notifyMotion(
generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}));
mDispatcher->waitForIdle();
- window1->consumeMotionEvent(WithDownTime(downTimeForWindow1));
+
+ window1->consumeMotionEvent(
+ AllOf(WithMotionAction(POINTER_1_DOWN), WithDownTime(firstDown->getDownTime())));
+ window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
}
TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
@@ -10799,6 +10808,7 @@
InputEventInjectionSync::WAIT_FOR_RESULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ mSecondWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
// Perform drag and drop from first window.
ASSERT_TRUE(startDrag(false));
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 476f755..835f8b8 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -58,6 +58,7 @@
using namespace ftl::flag_operators;
using testing::AllOf;
using std::chrono_literals::operator""ms;
+using std::chrono_literals::operator""s;
// Arbitrary display properties.
static constexpr int32_t DISPLAY_ID = 0;
@@ -149,7 +150,7 @@
std::istringstream iss(dump);
for (std::string line; std::getline(iss, line);) {
ALOGE("%s", line.c_str());
- std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ std::this_thread::sleep_for(1ms);
}
}
@@ -1374,13 +1375,23 @@
mFakePolicy.clear();
}
- std::optional<InputDeviceInfo> findDeviceByName(const std::string& name) {
- const std::vector<InputDeviceInfo> inputDevices = mFakePolicy->getInputDevices();
- const auto& it = std::find_if(inputDevices.begin(), inputDevices.end(),
- [&name](const InputDeviceInfo& info) {
- return info.getIdentifier().name == name;
- });
- return it != inputDevices.end() ? std::make_optional(*it) : std::nullopt;
+ std::optional<InputDeviceInfo> waitForDevice(const std::string& deviceName) {
+ std::chrono::time_point start = std::chrono::steady_clock::now();
+ while (true) {
+ const std::vector<InputDeviceInfo> inputDevices = mFakePolicy->getInputDevices();
+ const auto& it = std::find_if(inputDevices.begin(), inputDevices.end(),
+ [&deviceName](const InputDeviceInfo& info) {
+ return info.getIdentifier().name == deviceName;
+ });
+ if (it != inputDevices.end()) {
+ return std::make_optional(*it);
+ }
+ std::this_thread::sleep_for(1ms);
+ std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
+ if (elapsed > 5s) {
+ return {};
+ }
+ }
}
void setupInputReader() {
@@ -1433,7 +1444,7 @@
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
ASSERT_EQ(initialNumDevices + 1, mFakePolicy->getInputDevices().size());
- const auto device = findDeviceByName(keyboard->getName());
+ const auto device = waitForDevice(keyboard->getName());
ASSERT_TRUE(device.has_value());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, device->getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, device->getSources());
@@ -1476,7 +1487,7 @@
std::unique_ptr<UinputExternalStylus> stylus = createUinputDevice<UinputExternalStylus>();
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
- const auto device = findDeviceByName(stylus->getName());
+ const auto device = waitForDevice(stylus->getName());
ASSERT_TRUE(device.has_value());
// An external stylus with buttons should also be recognized as a keyboard.
@@ -1516,7 +1527,7 @@
BTN_STYLUS3});
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
- const auto device = findDeviceByName(keyboard->getName());
+ const auto device = waitForDevice(keyboard->getName());
ASSERT_TRUE(device.has_value());
// An alphabetical keyboard that reports stylus buttons should not be recognized as a stylus.
@@ -1533,7 +1544,7 @@
std::initializer_list<int>{KEY_VOLUMEUP, KEY_VOLUMEDOWN});
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
- const auto device = findDeviceByName(keyboard->getName());
+ const auto device = waitForDevice(keyboard->getName());
ASSERT_TRUE(device.has_value());
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, device->getSources())
@@ -1587,7 +1598,7 @@
mDevice = createUinputDevice<UinputTouchScreen>(Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
- const auto info = findDeviceByName(mDevice->getName());
+ const auto info = waitForDevice(mDevice->getName());
ASSERT_TRUE(info);
mDeviceInfo = *info;
}
@@ -1658,7 +1669,7 @@
ViewportType::INTERNAL);
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
- const auto info = findDeviceByName(mDevice->getName());
+ const auto info = waitForDevice(mDevice->getName());
ASSERT_TRUE(info);
mDeviceInfo = *info;
}
@@ -1991,7 +2002,7 @@
auto externalStylus = createUinputDevice<UinputExternalStylus>();
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
- const auto stylusInfo = findDeviceByName(externalStylus->getName());
+ const auto stylusInfo = waitForDevice(externalStylus->getName());
ASSERT_TRUE(stylusInfo);
// Move
@@ -2062,7 +2073,7 @@
mStylus = mStylusDeviceLifecycleTracker.get();
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
- const auto info = findDeviceByName(mStylus->getName());
+ const auto info = waitForDevice(mStylus->getName());
ASSERT_TRUE(info);
mStylusInfo = *info;
}
@@ -2332,11 +2343,11 @@
createUinputDevice<UinputExternalStylusWithPressure>();
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
- const auto stylusInfo = findDeviceByName(stylus->getName());
+ const auto stylusInfo = waitForDevice(stylus->getName());
ASSERT_TRUE(stylusInfo);
// Connecting an external stylus changes the source of the touchscreen.
- const auto deviceInfo = findDeviceByName(mDevice->getName());
+ const auto deviceInfo = waitForDevice(mDevice->getName());
ASSERT_TRUE(deviceInfo);
ASSERT_TRUE(isFromSource(deviceInfo->getSources(), STYLUS_FUSION_SOURCE));
}
@@ -2350,7 +2361,7 @@
createUinputDevice<UinputExternalStylusWithPressure>();
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
- const auto stylusInfo = findDeviceByName(stylus->getName());
+ const auto stylusInfo = waitForDevice(stylus->getName());
ASSERT_TRUE(stylusInfo);
ASSERT_EQ(AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_KEYBOARD, stylusInfo->getSources());
@@ -2396,7 +2407,7 @@
createUinputDevice<UinputExternalStylusWithPressure>();
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
- const auto stylusInfo = findDeviceByName(stylus->getName());
+ const auto stylusInfo = waitForDevice(stylus->getName());
ASSERT_TRUE(stylusInfo);
ASSERT_EQ(AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_KEYBOARD, stylusInfo->getSources());
@@ -2476,7 +2487,7 @@
std::unique_ptr<UinputExternalStylus> stylus = createUinputDevice<UinputExternalStylus>();
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
- const auto stylusInfo = findDeviceByName(stylus->getName());
+ const auto stylusInfo = waitForDevice(stylus->getName());
ASSERT_TRUE(stylusInfo);
ASSERT_EQ(AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_KEYBOARD, stylusInfo->getSources());
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/Android.bp b/services/surfaceflinger/Android.bp
index dcef9a3..6a0ea22 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/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",
}
aconfig_declarations {
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index ae2f2db..0b01c66 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/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_defaults {
diff --git a/services/surfaceflinger/FrameTimeline/Android.bp b/services/surfaceflinger/FrameTimeline/Android.bp
index 29c9432..8e28cc3 100644
--- a/services/surfaceflinger/FrameTimeline/Android.bp
+++ b/services/surfaceflinger/FrameTimeline/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_library_static {
diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp
index d714848..16776cf 100644
--- a/services/surfaceflinger/Scheduler/Android.bp
+++ b/services/surfaceflinger/Scheduler/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_defaults {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6979f03..e6c58a3 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,
@@ -344,40 +336,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 +375,48 @@
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::onHotplugReceived(Cycle cycle, PhysicalDisplayId displayId, bool connected) {
+ if (hasEventThreads()) {
+ eventThreadFor(cycle).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::onHotplugConnectionError(Cycle cycle, int32_t errorCode) {
+ if (hasEventThreads()) {
+ eventThreadFor(cycle).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 +443,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 +484,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 +954,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 d1934f2..dc32225 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;
@@ -154,36 +130,32 @@
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);
+ void onHotplugReceived(Cycle, PhysicalDisplayId, bool connected);
+ void onHotplugConnectionError(Cycle, int32_t errorCode);
- void onPrimaryDisplayModeChanged(ConnectionHandle, const FrameRateMode&) EXCLUDES(mPolicyLock);
- void onNonPrimaryDisplayModeChanged(ConnectionHandle, const FrameRateMode&);
+ 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 +260,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 +341,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 +439,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 +557,7 @@
ftl::Optional<FrameRateMode> modeOpt;
struct ModeChangedParams {
- ConnectionHandle handle;
+ Cycle cycle;
FrameRateMode mode;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0436c3c..08a78cc 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);
@@ -2092,12 +2085,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) {
@@ -2139,7 +2131,7 @@
const int32_t hotplugErrorCode = static_cast<int32_t>(-timestamp);
ALOGD("SurfaceFlinger got hotplugErrorCode=%d for display %" PRIu64, hotplugErrorCode,
hwcDisplayId);
- mScheduler->onHotplugConnectionError(mAppConnectionHandle, hotplugErrorCode);
+ mScheduler->onHotplugConnectionError(scheduler::Cycle::Render, hotplugErrorCode);
return;
}
@@ -2190,7 +2182,7 @@
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));
+ mScheduler->onHotplugConnectionError(scheduler::Cycle::Render, static_cast<int32_t>(event));
}
}
@@ -3484,7 +3476,7 @@
if (!activeMode) {
ALOGE("Failed to hotplug display %s", to_string(displayId).c_str());
if (FlagManager::getInstance().hotplug2()) {
- mScheduler->onHotplugConnectionError(mAppConnectionHandle,
+ mScheduler->onHotplugConnectionError(scheduler::Cycle::Render,
static_cast<int32_t>(
DisplayHotplugEvent::ERROR_UNKNOWN));
}
@@ -3537,8 +3529,8 @@
}
void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
- mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected);
- mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected);
+ mScheduler->onHotplugReceived(scheduler::Cycle::Render, displayId, connected);
+ mScheduler->onHotplugReceived(scheduler::Cycle::LastComposite, displayId, connected);
}
void SurfaceFlinger::dispatchDisplayModeChangeEvent(PhysicalDisplayId displayId,
@@ -3548,7 +3540,7 @@
? &scheduler::Scheduler::onPrimaryDisplayModeChanged
: &scheduler::Scheduler::onNonPrimaryDisplayModeChanged;
- ((*mScheduler).*onDisplayModeChanged)(mAppConnectionHandle, mode);
+ ((*mScheduler).*onDisplayModeChanged)(scheduler::Cycle::Render, mode);
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
@@ -3575,10 +3567,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};
@@ -4200,7 +4192,7 @@
return getDefaultDisplayDeviceLocked()->getPhysicalId();
}();
- mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
+ mScheduler->onFrameRateOverridesChanged(scheduler::Cycle::Render, displayId);
}
void SurfaceFlinger::notifyCpuLoadUp() {
@@ -4396,24 +4388,22 @@
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);
mScheduler->initVsync(*mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration);
@@ -4421,6 +4411,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() {
@@ -6362,7 +6355,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 {
@@ -7134,14 +7127,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
@@ -7373,7 +7367,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
@@ -7731,7 +7725,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
@@ -8513,10 +8507,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);
@@ -8704,7 +8698,7 @@
}();
mScheduler->setGameModeFrameRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate});
- mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
+ mScheduler->onFrameRateOverridesChanged(scheduler::Cycle::Render, displayId);
return NO_ERROR;
}
@@ -8970,7 +8964,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 ce9fa15..bada829 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1356,12 +1356,7 @@
const std::string mHwcServiceName;
- /*
- * Scheduler
- */
std::unique_ptr<scheduler::Scheduler> mScheduler;
- scheduler::ConnectionHandle mAppConnectionHandle;
- scheduler::ConnectionHandle mSfConnectionHandle;
scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext);
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index c3141be..a631074 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/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_defaults {
diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp
index 0cf086f..be65510 100644
--- a/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp
+++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/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_library {
@@ -33,4 +34,4 @@
"-Wno-undef",
"-Wno-unused-parameter",
],
-}
\ No newline at end of file
+}
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
index 972edaa..e097da3 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/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_library {
diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp
index 2ff09c3..8afca41 100644
--- a/services/surfaceflinger/Tracing/tools/Android.bp
+++ b/services/surfaceflinger/Tracing/tools/Android.bp
@@ -19,6 +19,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_binary {
diff --git a/services/surfaceflinger/common/Android.bp b/services/surfaceflinger/common/Android.bp
index e125bbe..f2ff00b 100644
--- a/services/surfaceflinger/common/Android.bp
+++ b/services/surfaceflinger/common/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_defaults {
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index 33bfe8a..ae502cf 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -22,6 +22,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_defaults {
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index a4dc8a0..f77b137 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/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_library {
diff --git a/services/surfaceflinger/sysprop/Android.bp b/services/surfaceflinger/sysprop/Android.bp
index f579119..4ea00cc 100644
--- a/services/surfaceflinger/sysprop/Android.bp
+++ b/services/surfaceflinger/sysprop/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",
}
sysprop_library {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 5449aeb..dab0a3f 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -19,6 +19,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/services/surfaceflinger/tests/tracing/Android.bp b/services/surfaceflinger/tests/tracing/Android.bp
index aeceadb..bce1406 100644
--- a/services/surfaceflinger/tests/tracing/Android.bp
+++ b/services/surfaceflinger/tests/tracing/Android.bp
@@ -19,6 +19,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/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index da4e47f..f529f7c 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -19,6 +19,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",
}
filegroup {
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/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/vsync/Android.bp b/services/surfaceflinger/tests/vsync/Android.bp
index bae9796..c7daa88 100644
--- a/services/surfaceflinger/tests/vsync/Android.bp
+++ b/services/surfaceflinger/tests/vsync/Android.bp
@@ -19,6 +19,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_binary {
@@ -33,6 +34,6 @@
"libgui",
"libui",
"libutils",
- ]
+ ],
}
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.bp b/services/surfaceflinger/tests/waitforvsync/Android.bp
index ffed4d7..734fc20 100644
--- a/services/surfaceflinger/tests/waitforvsync/Android.bp
+++ b/services/surfaceflinger/tests/waitforvsync/Android.bp
@@ -19,6 +19,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_binary {
@@ -31,5 +32,5 @@
],
shared_libs: [
"libcutils",
- ]
+ ],
}