Merge "Support capturing a gainmapped screenshot" into main
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index fa7be18..041ffe1 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -24,3 +24,7 @@
chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/filter
chmod 0666 /sys/kernel/tracing/events/raw_syscalls/sys_exit/filter
chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_exit/filter
+
+ # Allow traced_probes to use the kprobe interface
+ chmod 0666 /sys/kernel/debug/tracing/kprobe_events
+ chmod 0666 /sys/kernel/tracing/kprobe_events
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index 28bd793..b7ad331 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -50,6 +50,37 @@
exit 1
fi
+# A source that infinitely emits arbitrary lines.
+# When connected to STDIN of another process, this source keeps STDIN open until
+# the consumer process closes STDIN or this script dies.
+function infinite_source {
+ while echo .; do
+ sleep 1
+ done
+}
+
+PR_DEXOPT_JOB_VERSION="$(pm art pr-dexopt-job --version)"
+if (( $? == 0 )) && (( $PR_DEXOPT_JOB_VERSION >= 3 )); then
+ # Delegate to Pre-reboot Dexopt, a feature of ART Service.
+ # ART Service decides what to do with this request:
+ # - If Pre-reboot Dexopt is disabled or unsupported, the command returns
+ # non-zero. This is always the case if the current system is Android 14 or
+ # earlier.
+ # - If Pre-reboot Dexopt is enabled in synchronous mode, the command blocks
+ # until Pre-reboot Dexopt finishes, and returns zero no matter it succeeds or
+ # not. This is the default behavior if the current system is Android 15.
+ # - If Pre-reboot Dexopt is enabled in asynchronous mode, the command schedules
+ # an asynchronous job and returns 0 immediately. The job will then run by the
+ # job scheduler when the device is idle and charging.
+ if infinite_source | pm art on-ota-staged --slot "$TARGET_SLOT_SUFFIX"; then
+ # Handled by Pre-reboot Dexopt.
+ exit 0
+ fi
+ echo "Pre-reboot Dexopt not enabled. Fall back to otapreopt."
+else
+ echo "Pre-reboot Dexopt is too old. Fall back to otapreopt."
+fi
+
if [ "$(/system/bin/otapreopt_chroot --version)" != 2 ]; then
# We require an updated chroot wrapper that reads dexopt commands from stdin.
# Even if we kept compat with the old binary, the OTA preopt wouldn't work due
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-0 b/cmds/installd/tests/corpus/seed-2024-08-29-0
new file mode 100644
index 0000000..a09fc84
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-0
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-1 b/cmds/installd/tests/corpus/seed-2024-08-29-1
new file mode 100644
index 0000000..c96616a
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-1
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-10 b/cmds/installd/tests/corpus/seed-2024-08-29-10
new file mode 100644
index 0000000..0b21bd1
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-10
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-100 b/cmds/installd/tests/corpus/seed-2024-08-29-100
new file mode 100644
index 0000000..225d123
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-100
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-101 b/cmds/installd/tests/corpus/seed-2024-08-29-101
new file mode 100644
index 0000000..c507b57
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-101
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-102 b/cmds/installd/tests/corpus/seed-2024-08-29-102
new file mode 100644
index 0000000..e75ef89
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-102
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-103 b/cmds/installd/tests/corpus/seed-2024-08-29-103
new file mode 100644
index 0000000..fb28f4d
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-103
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-104 b/cmds/installd/tests/corpus/seed-2024-08-29-104
new file mode 100644
index 0000000..b5a2222
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-104
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-105 b/cmds/installd/tests/corpus/seed-2024-08-29-105
new file mode 100644
index 0000000..a126c0e
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-105
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-106 b/cmds/installd/tests/corpus/seed-2024-08-29-106
new file mode 100644
index 0000000..ad84e57
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-106
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-107 b/cmds/installd/tests/corpus/seed-2024-08-29-107
new file mode 100644
index 0000000..6a2bc6f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-107
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-108 b/cmds/installd/tests/corpus/seed-2024-08-29-108
new file mode 100644
index 0000000..578b55a
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-108
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-109 b/cmds/installd/tests/corpus/seed-2024-08-29-109
new file mode 100644
index 0000000..44f853d
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-109
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-11 b/cmds/installd/tests/corpus/seed-2024-08-29-11
new file mode 100644
index 0000000..28fd841
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-11
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-110 b/cmds/installd/tests/corpus/seed-2024-08-29-110
new file mode 100644
index 0000000..a013ee8
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-110
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-111 b/cmds/installd/tests/corpus/seed-2024-08-29-111
new file mode 100644
index 0000000..1bb6185
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-111
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-112 b/cmds/installd/tests/corpus/seed-2024-08-29-112
new file mode 100644
index 0000000..83008e9
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-112
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-113 b/cmds/installd/tests/corpus/seed-2024-08-29-113
new file mode 100644
index 0000000..c9460cb
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-113
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-114 b/cmds/installd/tests/corpus/seed-2024-08-29-114
new file mode 100644
index 0000000..feb0384
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-114
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-115 b/cmds/installd/tests/corpus/seed-2024-08-29-115
new file mode 100644
index 0000000..cd28076
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-115
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-116 b/cmds/installd/tests/corpus/seed-2024-08-29-116
new file mode 100644
index 0000000..c48730e
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-116
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-117 b/cmds/installd/tests/corpus/seed-2024-08-29-117
new file mode 100644
index 0000000..bde1be0
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-117
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-118 b/cmds/installd/tests/corpus/seed-2024-08-29-118
new file mode 100644
index 0000000..0d86d18
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-118
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-119 b/cmds/installd/tests/corpus/seed-2024-08-29-119
new file mode 100644
index 0000000..de35894
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-119
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-12 b/cmds/installd/tests/corpus/seed-2024-08-29-12
new file mode 100644
index 0000000..5565f81
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-12
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-120 b/cmds/installd/tests/corpus/seed-2024-08-29-120
new file mode 100644
index 0000000..51c0526
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-120
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-121 b/cmds/installd/tests/corpus/seed-2024-08-29-121
new file mode 100644
index 0000000..2d84c76
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-121
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-122 b/cmds/installd/tests/corpus/seed-2024-08-29-122
new file mode 100644
index 0000000..f25a7c4
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-122
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-123 b/cmds/installd/tests/corpus/seed-2024-08-29-123
new file mode 100644
index 0000000..fe8eb34
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-123
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-124 b/cmds/installd/tests/corpus/seed-2024-08-29-124
new file mode 100644
index 0000000..170e8ec
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-124
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-125 b/cmds/installd/tests/corpus/seed-2024-08-29-125
new file mode 100644
index 0000000..24e8bb8
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-125
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-126 b/cmds/installd/tests/corpus/seed-2024-08-29-126
new file mode 100644
index 0000000..92536a3
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-126
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-127 b/cmds/installd/tests/corpus/seed-2024-08-29-127
new file mode 100644
index 0000000..3a5436a
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-127
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-128 b/cmds/installd/tests/corpus/seed-2024-08-29-128
new file mode 100644
index 0000000..93d131d
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-128
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-129 b/cmds/installd/tests/corpus/seed-2024-08-29-129
new file mode 100644
index 0000000..842dae4
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-129
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-13 b/cmds/installd/tests/corpus/seed-2024-08-29-13
new file mode 100644
index 0000000..bc0ec3d
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-13
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-130 b/cmds/installd/tests/corpus/seed-2024-08-29-130
new file mode 100644
index 0000000..9b6ed59
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-130
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-131 b/cmds/installd/tests/corpus/seed-2024-08-29-131
new file mode 100644
index 0000000..82a5d2f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-131
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-132 b/cmds/installd/tests/corpus/seed-2024-08-29-132
new file mode 100644
index 0000000..445fdc5
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-132
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-133 b/cmds/installd/tests/corpus/seed-2024-08-29-133
new file mode 100644
index 0000000..0a6e9ca
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-133
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-134 b/cmds/installd/tests/corpus/seed-2024-08-29-134
new file mode 100644
index 0000000..a359603
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-134
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-135 b/cmds/installd/tests/corpus/seed-2024-08-29-135
new file mode 100644
index 0000000..c16b303
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-135
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-136 b/cmds/installd/tests/corpus/seed-2024-08-29-136
new file mode 100644
index 0000000..f7a360f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-136
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-137 b/cmds/installd/tests/corpus/seed-2024-08-29-137
new file mode 100644
index 0000000..38a1134
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-137
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-138 b/cmds/installd/tests/corpus/seed-2024-08-29-138
new file mode 100644
index 0000000..b9db4a7
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-138
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-139 b/cmds/installd/tests/corpus/seed-2024-08-29-139
new file mode 100644
index 0000000..eb1cf93
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-139
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-14 b/cmds/installd/tests/corpus/seed-2024-08-29-14
new file mode 100644
index 0000000..74f9ad0
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-14
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-140 b/cmds/installd/tests/corpus/seed-2024-08-29-140
new file mode 100644
index 0000000..0cf217c
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-140
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-141 b/cmds/installd/tests/corpus/seed-2024-08-29-141
new file mode 100644
index 0000000..82763f0
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-141
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-142 b/cmds/installd/tests/corpus/seed-2024-08-29-142
new file mode 100644
index 0000000..fa1d656
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-142
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-15 b/cmds/installd/tests/corpus/seed-2024-08-29-15
new file mode 100644
index 0000000..729c604
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-15
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-16 b/cmds/installd/tests/corpus/seed-2024-08-29-16
new file mode 100644
index 0000000..4dc0879
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-16
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-17 b/cmds/installd/tests/corpus/seed-2024-08-29-17
new file mode 100644
index 0000000..ac7ff13
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-17
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-18 b/cmds/installd/tests/corpus/seed-2024-08-29-18
new file mode 100644
index 0000000..2b240f4
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-18
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-19 b/cmds/installd/tests/corpus/seed-2024-08-29-19
new file mode 100644
index 0000000..a0c881b
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-19
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-2 b/cmds/installd/tests/corpus/seed-2024-08-29-2
new file mode 100644
index 0000000..2593acb
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-2
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-20 b/cmds/installd/tests/corpus/seed-2024-08-29-20
new file mode 100644
index 0000000..c55dc7f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-20
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-21 b/cmds/installd/tests/corpus/seed-2024-08-29-21
new file mode 100644
index 0000000..63d7a14
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-21
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-22 b/cmds/installd/tests/corpus/seed-2024-08-29-22
new file mode 100644
index 0000000..209f426
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-22
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-23 b/cmds/installd/tests/corpus/seed-2024-08-29-23
new file mode 100644
index 0000000..8e1775f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-23
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-24 b/cmds/installd/tests/corpus/seed-2024-08-29-24
new file mode 100644
index 0000000..4c40f3c
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-24
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-25 b/cmds/installd/tests/corpus/seed-2024-08-29-25
new file mode 100644
index 0000000..d006b20
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-25
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-26 b/cmds/installd/tests/corpus/seed-2024-08-29-26
new file mode 100644
index 0000000..26893b0
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-26
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-27 b/cmds/installd/tests/corpus/seed-2024-08-29-27
new file mode 100644
index 0000000..ac81138
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-27
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-28 b/cmds/installd/tests/corpus/seed-2024-08-29-28
new file mode 100644
index 0000000..71f074b
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-28
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-29 b/cmds/installd/tests/corpus/seed-2024-08-29-29
new file mode 100644
index 0000000..65dbb6d
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-29
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-3 b/cmds/installd/tests/corpus/seed-2024-08-29-3
new file mode 100644
index 0000000..28ab83f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-3
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-30 b/cmds/installd/tests/corpus/seed-2024-08-29-30
new file mode 100644
index 0000000..3b96286
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-30
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-31 b/cmds/installd/tests/corpus/seed-2024-08-29-31
new file mode 100644
index 0000000..76101b3
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-31
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-32 b/cmds/installd/tests/corpus/seed-2024-08-29-32
new file mode 100644
index 0000000..79a4452
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-32
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-33 b/cmds/installd/tests/corpus/seed-2024-08-29-33
new file mode 100644
index 0000000..e6a1306
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-33
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-34 b/cmds/installd/tests/corpus/seed-2024-08-29-34
new file mode 100644
index 0000000..4a7247f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-34
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-35 b/cmds/installd/tests/corpus/seed-2024-08-29-35
new file mode 100644
index 0000000..f420b34
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-35
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-36 b/cmds/installd/tests/corpus/seed-2024-08-29-36
new file mode 100644
index 0000000..83a33ac
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-36
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-37 b/cmds/installd/tests/corpus/seed-2024-08-29-37
new file mode 100644
index 0000000..687bf06
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-37
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-38 b/cmds/installd/tests/corpus/seed-2024-08-29-38
new file mode 100644
index 0000000..40ab0ad
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-38
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-39 b/cmds/installd/tests/corpus/seed-2024-08-29-39
new file mode 100644
index 0000000..3e13978
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-39
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-4 b/cmds/installd/tests/corpus/seed-2024-08-29-4
new file mode 100644
index 0000000..8c47ea3
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-4
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-40 b/cmds/installd/tests/corpus/seed-2024-08-29-40
new file mode 100644
index 0000000..f717918
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-40
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-41 b/cmds/installd/tests/corpus/seed-2024-08-29-41
new file mode 100644
index 0000000..d9c51b9
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-41
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-42 b/cmds/installd/tests/corpus/seed-2024-08-29-42
new file mode 100644
index 0000000..d806e5e
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-42
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-43 b/cmds/installd/tests/corpus/seed-2024-08-29-43
new file mode 100644
index 0000000..3bc2708
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-43
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-44 b/cmds/installd/tests/corpus/seed-2024-08-29-44
new file mode 100644
index 0000000..230839a
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-44
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-45 b/cmds/installd/tests/corpus/seed-2024-08-29-45
new file mode 100644
index 0000000..40726b9
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-45
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-46 b/cmds/installd/tests/corpus/seed-2024-08-29-46
new file mode 100644
index 0000000..bf56bd4
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-46
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-47 b/cmds/installd/tests/corpus/seed-2024-08-29-47
new file mode 100644
index 0000000..80cabaf
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-47
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-48 b/cmds/installd/tests/corpus/seed-2024-08-29-48
new file mode 100644
index 0000000..8f2c5f5
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-48
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-49 b/cmds/installd/tests/corpus/seed-2024-08-29-49
new file mode 100644
index 0000000..f93fbcd
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-49
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-5 b/cmds/installd/tests/corpus/seed-2024-08-29-5
new file mode 100644
index 0000000..b3f49d1
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-5
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-50 b/cmds/installd/tests/corpus/seed-2024-08-29-50
new file mode 100644
index 0000000..68912ae
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-50
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-51 b/cmds/installd/tests/corpus/seed-2024-08-29-51
new file mode 100644
index 0000000..27b315d
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-51
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-52 b/cmds/installd/tests/corpus/seed-2024-08-29-52
new file mode 100644
index 0000000..159eee6
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-52
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-53 b/cmds/installd/tests/corpus/seed-2024-08-29-53
new file mode 100644
index 0000000..b07cb3c
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-53
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-54 b/cmds/installd/tests/corpus/seed-2024-08-29-54
new file mode 100644
index 0000000..a5e7f2c
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-54
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-55 b/cmds/installd/tests/corpus/seed-2024-08-29-55
new file mode 100644
index 0000000..bd038ad
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-55
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-56 b/cmds/installd/tests/corpus/seed-2024-08-29-56
new file mode 100644
index 0000000..8166cb8
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-56
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-57 b/cmds/installd/tests/corpus/seed-2024-08-29-57
new file mode 100644
index 0000000..fba1e2f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-57
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-58 b/cmds/installd/tests/corpus/seed-2024-08-29-58
new file mode 100644
index 0000000..f7af8f8
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-58
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-59 b/cmds/installd/tests/corpus/seed-2024-08-29-59
new file mode 100644
index 0000000..2fd68d7
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-59
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-6 b/cmds/installd/tests/corpus/seed-2024-08-29-6
new file mode 100644
index 0000000..9b02a47
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-6
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-60 b/cmds/installd/tests/corpus/seed-2024-08-29-60
new file mode 100644
index 0000000..b4c1129
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-60
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-61 b/cmds/installd/tests/corpus/seed-2024-08-29-61
new file mode 100644
index 0000000..46989aa
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-61
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-62 b/cmds/installd/tests/corpus/seed-2024-08-29-62
new file mode 100644
index 0000000..9298d0c
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-62
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-63 b/cmds/installd/tests/corpus/seed-2024-08-29-63
new file mode 100644
index 0000000..326098c
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-63
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-64 b/cmds/installd/tests/corpus/seed-2024-08-29-64
new file mode 100644
index 0000000..61daf4f
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-64
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-65 b/cmds/installd/tests/corpus/seed-2024-08-29-65
new file mode 100644
index 0000000..a993900
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-65
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-66 b/cmds/installd/tests/corpus/seed-2024-08-29-66
new file mode 100644
index 0000000..85e857b
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-66
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-67 b/cmds/installd/tests/corpus/seed-2024-08-29-67
new file mode 100644
index 0000000..b775483
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-67
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-68 b/cmds/installd/tests/corpus/seed-2024-08-29-68
new file mode 100644
index 0000000..161e7ab
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-68
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-69 b/cmds/installd/tests/corpus/seed-2024-08-29-69
new file mode 100644
index 0000000..6a45dfe
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-69
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-7 b/cmds/installd/tests/corpus/seed-2024-08-29-7
new file mode 100644
index 0000000..33f61b0
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-7
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-70 b/cmds/installd/tests/corpus/seed-2024-08-29-70
new file mode 100644
index 0000000..4c16b49
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-70
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-71 b/cmds/installd/tests/corpus/seed-2024-08-29-71
new file mode 100644
index 0000000..1534ce1
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-71
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-72 b/cmds/installd/tests/corpus/seed-2024-08-29-72
new file mode 100644
index 0000000..eaa5831
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-72
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-73 b/cmds/installd/tests/corpus/seed-2024-08-29-73
new file mode 100644
index 0000000..9df4a75
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-73
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-74 b/cmds/installd/tests/corpus/seed-2024-08-29-74
new file mode 100644
index 0000000..9558ac0
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-74
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-75 b/cmds/installd/tests/corpus/seed-2024-08-29-75
new file mode 100644
index 0000000..a399271
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-75
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-76 b/cmds/installd/tests/corpus/seed-2024-08-29-76
new file mode 100644
index 0000000..866541d
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-76
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-77 b/cmds/installd/tests/corpus/seed-2024-08-29-77
new file mode 100644
index 0000000..e3940d9
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-77
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-78 b/cmds/installd/tests/corpus/seed-2024-08-29-78
new file mode 100644
index 0000000..8122306
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-78
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-79 b/cmds/installd/tests/corpus/seed-2024-08-29-79
new file mode 100644
index 0000000..0f23dfd
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-79
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-8 b/cmds/installd/tests/corpus/seed-2024-08-29-8
new file mode 100644
index 0000000..7390735
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-8
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-80 b/cmds/installd/tests/corpus/seed-2024-08-29-80
new file mode 100644
index 0000000..e3c3640
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-80
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-81 b/cmds/installd/tests/corpus/seed-2024-08-29-81
new file mode 100644
index 0000000..6c42b9e
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-81
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-82 b/cmds/installd/tests/corpus/seed-2024-08-29-82
new file mode 100644
index 0000000..09184c9
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-82
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-83 b/cmds/installd/tests/corpus/seed-2024-08-29-83
new file mode 100644
index 0000000..734570a
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-83
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-84 b/cmds/installd/tests/corpus/seed-2024-08-29-84
new file mode 100644
index 0000000..1a32561
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-84
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-85 b/cmds/installd/tests/corpus/seed-2024-08-29-85
new file mode 100644
index 0000000..5315dfc
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-85
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-86 b/cmds/installd/tests/corpus/seed-2024-08-29-86
new file mode 100644
index 0000000..5f798b9
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-86
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-87 b/cmds/installd/tests/corpus/seed-2024-08-29-87
new file mode 100644
index 0000000..dd1ebe1
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-87
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-88 b/cmds/installd/tests/corpus/seed-2024-08-29-88
new file mode 100644
index 0000000..45cf713
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-88
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-89 b/cmds/installd/tests/corpus/seed-2024-08-29-89
new file mode 100644
index 0000000..1053b71
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-89
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-9 b/cmds/installd/tests/corpus/seed-2024-08-29-9
new file mode 100644
index 0000000..86d511d
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-9
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-90 b/cmds/installd/tests/corpus/seed-2024-08-29-90
new file mode 100644
index 0000000..7ce82a0
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-90
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-91 b/cmds/installd/tests/corpus/seed-2024-08-29-91
new file mode 100644
index 0000000..57c43d0
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-91
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-92 b/cmds/installd/tests/corpus/seed-2024-08-29-92
new file mode 100644
index 0000000..32a0f3a
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-92
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-93 b/cmds/installd/tests/corpus/seed-2024-08-29-93
new file mode 100644
index 0000000..56dcb66
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-93
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-94 b/cmds/installd/tests/corpus/seed-2024-08-29-94
new file mode 100644
index 0000000..17b5a65
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-94
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-95 b/cmds/installd/tests/corpus/seed-2024-08-29-95
new file mode 100644
index 0000000..0963039
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-95
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-96 b/cmds/installd/tests/corpus/seed-2024-08-29-96
new file mode 100644
index 0000000..1c95905
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-96
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-97 b/cmds/installd/tests/corpus/seed-2024-08-29-97
new file mode 100644
index 0000000..518910e
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-97
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-98 b/cmds/installd/tests/corpus/seed-2024-08-29-98
new file mode 100644
index 0000000..520feb2
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-98
Binary files differ
diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-99 b/cmds/installd/tests/corpus/seed-2024-08-29-99
new file mode 100644
index 0000000..c1da923
--- /dev/null
+++ b/cmds/installd/tests/corpus/seed-2024-08-29-99
Binary files differ
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index ee91d80..e89543e 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -1449,7 +1449,7 @@
class BootProfileTest : public ProfileTest {
public:
- std::vector<const std::string> extra_apps_;
+ std::vector<std::string> extra_apps_;
std::vector<int64_t> extra_ce_data_inodes_;
virtual void SetUp() {
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 910cd63..19201b2 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -101,6 +101,9 @@
EXPECT_EQ(0, validate_apk_path(path2))
<< path2 << " should be allowed as a valid path";
+ const char* path3 = TEST_APP_DIR "..example..com../example.apk";
+ EXPECT_EQ(0, validate_apk_path(path3)) << path3 << " should be allowed as a valid path";
+
const char *badint1 = TEST_APP_DIR "../example.apk";
EXPECT_EQ(-1, validate_apk_path(badint1))
<< badint1 << " should be rejected as a invalid path";
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index ffc082d..b05c655 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1040,25 +1040,30 @@
LOG(ERROR) << "Invalid directory " << dir;
return -1;
}
- if (path.find("..") != std::string::npos) {
- LOG(ERROR) << "Invalid path " << path;
- return -1;
- }
if (path.compare(0, dir.size(), dir) != 0) {
// Common case, path isn't under directory
return -1;
}
- // Count number of subdirectories
- auto pos = path.find('/', dir.size());
+ // Count number of subdirectories and invalidate ".." subdirectories
+ auto last = dir.size();
+ auto pos = path.find('/', last);
int count = 0;
while (pos != std::string::npos) {
- auto next = path.find('/', pos + 1);
- if (next > pos + 1) {
+ if (pos > last + 1) {
count++;
}
- pos = next;
+ if (path.substr(last, pos - last) == "..") {
+ LOG(ERROR) << "Invalid path " << path;
+ return -1;
+ }
+ last = pos + 1;
+ pos = path.find('/', last);
+ }
+ if (path.substr(last, path.size() - last) == "..") {
+ LOG(ERROR) << "Invalid path " << path;
+ return -1;
}
if (count > maxSubdirs) {
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-0 b/cmds/servicemanager/corpus/seed-2024-08-29-0
new file mode 100644
index 0000000..fe4942e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-0
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-1 b/cmds/servicemanager/corpus/seed-2024-08-29-1
new file mode 100644
index 0000000..05c8be2
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-1
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-10 b/cmds/servicemanager/corpus/seed-2024-08-29-10
new file mode 100644
index 0000000..427dc45
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-10
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-100 b/cmds/servicemanager/corpus/seed-2024-08-29-100
new file mode 100644
index 0000000..92584e3
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-100
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-101 b/cmds/servicemanager/corpus/seed-2024-08-29-101
new file mode 100644
index 0000000..4dd73ac
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-101
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-102 b/cmds/servicemanager/corpus/seed-2024-08-29-102
new file mode 100644
index 0000000..30c37a0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-102
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-103 b/cmds/servicemanager/corpus/seed-2024-08-29-103
new file mode 100644
index 0000000..76ae112
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-103
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-104 b/cmds/servicemanager/corpus/seed-2024-08-29-104
new file mode 100644
index 0000000..8ca2201
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-104
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-105 b/cmds/servicemanager/corpus/seed-2024-08-29-105
new file mode 100644
index 0000000..987fcc1
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-105
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-106 b/cmds/servicemanager/corpus/seed-2024-08-29-106
new file mode 100644
index 0000000..9f09e29
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-106
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-107 b/cmds/servicemanager/corpus/seed-2024-08-29-107
new file mode 100644
index 0000000..8f9518d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-107
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-108 b/cmds/servicemanager/corpus/seed-2024-08-29-108
new file mode 100644
index 0000000..decb38a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-108
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-109 b/cmds/servicemanager/corpus/seed-2024-08-29-109
new file mode 100644
index 0000000..e3b4426
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-109
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-11 b/cmds/servicemanager/corpus/seed-2024-08-29-11
new file mode 100644
index 0000000..177a1cd
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-11
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-110 b/cmds/servicemanager/corpus/seed-2024-08-29-110
new file mode 100644
index 0000000..35de9ca
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-110
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-111 b/cmds/servicemanager/corpus/seed-2024-08-29-111
new file mode 100644
index 0000000..ae6076f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-111
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-112 b/cmds/servicemanager/corpus/seed-2024-08-29-112
new file mode 100644
index 0000000..3d64f37
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-112
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-113 b/cmds/servicemanager/corpus/seed-2024-08-29-113
new file mode 100644
index 0000000..2b14f1d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-113
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-114 b/cmds/servicemanager/corpus/seed-2024-08-29-114
new file mode 100644
index 0000000..180831f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-114
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-115 b/cmds/servicemanager/corpus/seed-2024-08-29-115
new file mode 100644
index 0000000..71184d2
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-115
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-116 b/cmds/servicemanager/corpus/seed-2024-08-29-116
new file mode 100644
index 0000000..98c6163
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-116
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-117 b/cmds/servicemanager/corpus/seed-2024-08-29-117
new file mode 100644
index 0000000..e6dd7bb
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-117
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-118 b/cmds/servicemanager/corpus/seed-2024-08-29-118
new file mode 100644
index 0000000..dd181ae
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-118
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-119 b/cmds/servicemanager/corpus/seed-2024-08-29-119
new file mode 100644
index 0000000..25de1b2
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-119
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-12 b/cmds/servicemanager/corpus/seed-2024-08-29-12
new file mode 100644
index 0000000..1312d2c
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-12
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-120 b/cmds/servicemanager/corpus/seed-2024-08-29-120
new file mode 100644
index 0000000..cef973d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-120
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-121 b/cmds/servicemanager/corpus/seed-2024-08-29-121
new file mode 100644
index 0000000..7fd1df2
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-121
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-122 b/cmds/servicemanager/corpus/seed-2024-08-29-122
new file mode 100644
index 0000000..5fefc4b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-122
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-123 b/cmds/servicemanager/corpus/seed-2024-08-29-123
new file mode 100644
index 0000000..714b6b5
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-123
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-124 b/cmds/servicemanager/corpus/seed-2024-08-29-124
new file mode 100644
index 0000000..925bfcc
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-124
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-125 b/cmds/servicemanager/corpus/seed-2024-08-29-125
new file mode 100644
index 0000000..6dbec24
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-125
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-126 b/cmds/servicemanager/corpus/seed-2024-08-29-126
new file mode 100644
index 0000000..d5cdcaa
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-126
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-127 b/cmds/servicemanager/corpus/seed-2024-08-29-127
new file mode 100644
index 0000000..13d0eb5
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-127
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-128 b/cmds/servicemanager/corpus/seed-2024-08-29-128
new file mode 100644
index 0000000..471371c
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-128
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-129 b/cmds/servicemanager/corpus/seed-2024-08-29-129
new file mode 100644
index 0000000..2908795
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-129
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-13 b/cmds/servicemanager/corpus/seed-2024-08-29-13
new file mode 100644
index 0000000..6c8bd0a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-13
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-130 b/cmds/servicemanager/corpus/seed-2024-08-29-130
new file mode 100644
index 0000000..3a64ac5
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-130
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-131 b/cmds/servicemanager/corpus/seed-2024-08-29-131
new file mode 100644
index 0000000..d1da2ea
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-131
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-132 b/cmds/servicemanager/corpus/seed-2024-08-29-132
new file mode 100644
index 0000000..6de377e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-132
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-133 b/cmds/servicemanager/corpus/seed-2024-08-29-133
new file mode 100644
index 0000000..38ffcb9
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-133
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-134 b/cmds/servicemanager/corpus/seed-2024-08-29-134
new file mode 100644
index 0000000..6e828ae
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-134
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-135 b/cmds/servicemanager/corpus/seed-2024-08-29-135
new file mode 100644
index 0000000..c3eb827
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-135
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-136 b/cmds/servicemanager/corpus/seed-2024-08-29-136
new file mode 100644
index 0000000..9b1fafb
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-136
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-137 b/cmds/servicemanager/corpus/seed-2024-08-29-137
new file mode 100644
index 0000000..059b55b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-137
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-138 b/cmds/servicemanager/corpus/seed-2024-08-29-138
new file mode 100644
index 0000000..391bd8c
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-138
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-139 b/cmds/servicemanager/corpus/seed-2024-08-29-139
new file mode 100644
index 0000000..8ea28db
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-139
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-14 b/cmds/servicemanager/corpus/seed-2024-08-29-14
new file mode 100644
index 0000000..2c704b4
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-14
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-140 b/cmds/servicemanager/corpus/seed-2024-08-29-140
new file mode 100644
index 0000000..621c536
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-140
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-141 b/cmds/servicemanager/corpus/seed-2024-08-29-141
new file mode 100644
index 0000000..1d85324
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-141
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-142 b/cmds/servicemanager/corpus/seed-2024-08-29-142
new file mode 100644
index 0000000..1df0205
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-142
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-143 b/cmds/servicemanager/corpus/seed-2024-08-29-143
new file mode 100644
index 0000000..be5ddea
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-143
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-144 b/cmds/servicemanager/corpus/seed-2024-08-29-144
new file mode 100644
index 0000000..dd7eedf
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-144
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-145 b/cmds/servicemanager/corpus/seed-2024-08-29-145
new file mode 100644
index 0000000..a9c28f9
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-145
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-146 b/cmds/servicemanager/corpus/seed-2024-08-29-146
new file mode 100644
index 0000000..8e64a65
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-146
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-147 b/cmds/servicemanager/corpus/seed-2024-08-29-147
new file mode 100644
index 0000000..f65abe0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-147
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-148 b/cmds/servicemanager/corpus/seed-2024-08-29-148
new file mode 100644
index 0000000..174e50a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-148
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-149 b/cmds/servicemanager/corpus/seed-2024-08-29-149
new file mode 100644
index 0000000..3d58671
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-149
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-15 b/cmds/servicemanager/corpus/seed-2024-08-29-15
new file mode 100644
index 0000000..a1c47d3
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-15
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-150 b/cmds/servicemanager/corpus/seed-2024-08-29-150
new file mode 100644
index 0000000..a41c9c8
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-150
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-151 b/cmds/servicemanager/corpus/seed-2024-08-29-151
new file mode 100644
index 0000000..013f84d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-151
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-152 b/cmds/servicemanager/corpus/seed-2024-08-29-152
new file mode 100644
index 0000000..ada2ead
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-152
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-153 b/cmds/servicemanager/corpus/seed-2024-08-29-153
new file mode 100644
index 0000000..1b56561
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-153
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-154 b/cmds/servicemanager/corpus/seed-2024-08-29-154
new file mode 100644
index 0000000..8fea50f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-154
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-155 b/cmds/servicemanager/corpus/seed-2024-08-29-155
new file mode 100644
index 0000000..ddcd8f3
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-155
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-156 b/cmds/servicemanager/corpus/seed-2024-08-29-156
new file mode 100644
index 0000000..19ab7ae
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-156
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-157 b/cmds/servicemanager/corpus/seed-2024-08-29-157
new file mode 100644
index 0000000..bc89bf5
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-157
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-158 b/cmds/servicemanager/corpus/seed-2024-08-29-158
new file mode 100644
index 0000000..64867f1
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-158
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-159 b/cmds/servicemanager/corpus/seed-2024-08-29-159
new file mode 100644
index 0000000..fe77d0b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-159
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-16 b/cmds/servicemanager/corpus/seed-2024-08-29-16
new file mode 100644
index 0000000..f1002d7
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-16
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-160 b/cmds/servicemanager/corpus/seed-2024-08-29-160
new file mode 100644
index 0000000..9c2123f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-160
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-161 b/cmds/servicemanager/corpus/seed-2024-08-29-161
new file mode 100644
index 0000000..0fc8e86
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-161
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-162 b/cmds/servicemanager/corpus/seed-2024-08-29-162
new file mode 100644
index 0000000..a134085
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-162
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-163 b/cmds/servicemanager/corpus/seed-2024-08-29-163
new file mode 100644
index 0000000..c23e78c
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-163
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-164 b/cmds/servicemanager/corpus/seed-2024-08-29-164
new file mode 100644
index 0000000..d4feab0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-164
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-165 b/cmds/servicemanager/corpus/seed-2024-08-29-165
new file mode 100644
index 0000000..9cbdc4f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-165
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-166 b/cmds/servicemanager/corpus/seed-2024-08-29-166
new file mode 100644
index 0000000..d4cf647
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-166
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-167 b/cmds/servicemanager/corpus/seed-2024-08-29-167
new file mode 100644
index 0000000..5023909
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-167
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-168 b/cmds/servicemanager/corpus/seed-2024-08-29-168
new file mode 100644
index 0000000..846d0ec
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-168
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-169 b/cmds/servicemanager/corpus/seed-2024-08-29-169
new file mode 100644
index 0000000..cf6d882
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-169
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-17 b/cmds/servicemanager/corpus/seed-2024-08-29-17
new file mode 100644
index 0000000..6c21de8
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-17
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-170 b/cmds/servicemanager/corpus/seed-2024-08-29-170
new file mode 100644
index 0000000..d9707cb
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-170
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-171 b/cmds/servicemanager/corpus/seed-2024-08-29-171
new file mode 100644
index 0000000..ea947f6
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-171
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-172 b/cmds/servicemanager/corpus/seed-2024-08-29-172
new file mode 100644
index 0000000..2754437
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-172
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-173 b/cmds/servicemanager/corpus/seed-2024-08-29-173
new file mode 100644
index 0000000..96e8d56
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-173
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-174 b/cmds/servicemanager/corpus/seed-2024-08-29-174
new file mode 100644
index 0000000..aa6472e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-174
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-175 b/cmds/servicemanager/corpus/seed-2024-08-29-175
new file mode 100644
index 0000000..41e7894
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-175
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-176 b/cmds/servicemanager/corpus/seed-2024-08-29-176
new file mode 100644
index 0000000..b94712a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-176
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-177 b/cmds/servicemanager/corpus/seed-2024-08-29-177
new file mode 100644
index 0000000..4925e62
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-177
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-178 b/cmds/servicemanager/corpus/seed-2024-08-29-178
new file mode 100644
index 0000000..9ec943d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-178
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-179 b/cmds/servicemanager/corpus/seed-2024-08-29-179
new file mode 100644
index 0000000..e173bd3
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-179
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-18 b/cmds/servicemanager/corpus/seed-2024-08-29-18
new file mode 100644
index 0000000..aa0b101
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-18
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-180 b/cmds/servicemanager/corpus/seed-2024-08-29-180
new file mode 100644
index 0000000..f6f4ba7
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-180
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-181 b/cmds/servicemanager/corpus/seed-2024-08-29-181
new file mode 100644
index 0000000..2ca01e6
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-181
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-182 b/cmds/servicemanager/corpus/seed-2024-08-29-182
new file mode 100644
index 0000000..18966c0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-182
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-183 b/cmds/servicemanager/corpus/seed-2024-08-29-183
new file mode 100644
index 0000000..887de10
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-183
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-184 b/cmds/servicemanager/corpus/seed-2024-08-29-184
new file mode 100644
index 0000000..fee8cdb
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-184
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-185 b/cmds/servicemanager/corpus/seed-2024-08-29-185
new file mode 100644
index 0000000..10dd34d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-185
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-186 b/cmds/servicemanager/corpus/seed-2024-08-29-186
new file mode 100644
index 0000000..6ad247b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-186
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-187 b/cmds/servicemanager/corpus/seed-2024-08-29-187
new file mode 100644
index 0000000..613456d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-187
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-188 b/cmds/servicemanager/corpus/seed-2024-08-29-188
new file mode 100644
index 0000000..851b25f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-188
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-189 b/cmds/servicemanager/corpus/seed-2024-08-29-189
new file mode 100644
index 0000000..c4cebe9
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-189
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-19 b/cmds/servicemanager/corpus/seed-2024-08-29-19
new file mode 100644
index 0000000..c0792c0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-19
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-190 b/cmds/servicemanager/corpus/seed-2024-08-29-190
new file mode 100644
index 0000000..4370a31
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-190
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-191 b/cmds/servicemanager/corpus/seed-2024-08-29-191
new file mode 100644
index 0000000..0970428
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-191
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-192 b/cmds/servicemanager/corpus/seed-2024-08-29-192
new file mode 100644
index 0000000..6cec400
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-192
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-193 b/cmds/servicemanager/corpus/seed-2024-08-29-193
new file mode 100644
index 0000000..15a7661
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-193
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-194 b/cmds/servicemanager/corpus/seed-2024-08-29-194
new file mode 100644
index 0000000..3cabe77
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-194
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-195 b/cmds/servicemanager/corpus/seed-2024-08-29-195
new file mode 100644
index 0000000..4c5274b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-195
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-196 b/cmds/servicemanager/corpus/seed-2024-08-29-196
new file mode 100644
index 0000000..9d7a3d6
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-196
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-197 b/cmds/servicemanager/corpus/seed-2024-08-29-197
new file mode 100644
index 0000000..4e69238
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-197
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-198 b/cmds/servicemanager/corpus/seed-2024-08-29-198
new file mode 100644
index 0000000..5f6df99
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-198
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-199 b/cmds/servicemanager/corpus/seed-2024-08-29-199
new file mode 100644
index 0000000..a902bba
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-199
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-2 b/cmds/servicemanager/corpus/seed-2024-08-29-2
new file mode 100644
index 0000000..ffa9719
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-2
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-20 b/cmds/servicemanager/corpus/seed-2024-08-29-20
new file mode 100644
index 0000000..2090ef6
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-20
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-200 b/cmds/servicemanager/corpus/seed-2024-08-29-200
new file mode 100644
index 0000000..2c91da6
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-200
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-201 b/cmds/servicemanager/corpus/seed-2024-08-29-201
new file mode 100644
index 0000000..eb77655
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-201
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-202 b/cmds/servicemanager/corpus/seed-2024-08-29-202
new file mode 100644
index 0000000..bcbe3b7
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-202
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-203 b/cmds/servicemanager/corpus/seed-2024-08-29-203
new file mode 100644
index 0000000..7c3dc94
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-203
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-204 b/cmds/servicemanager/corpus/seed-2024-08-29-204
new file mode 100644
index 0000000..a4b660e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-204
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-205 b/cmds/servicemanager/corpus/seed-2024-08-29-205
new file mode 100644
index 0000000..aee1c21
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-205
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-206 b/cmds/servicemanager/corpus/seed-2024-08-29-206
new file mode 100644
index 0000000..6863c2e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-206
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-207 b/cmds/servicemanager/corpus/seed-2024-08-29-207
new file mode 100644
index 0000000..bf2c59f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-207
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-208 b/cmds/servicemanager/corpus/seed-2024-08-29-208
new file mode 100644
index 0000000..78081b9
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-208
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-209 b/cmds/servicemanager/corpus/seed-2024-08-29-209
new file mode 100644
index 0000000..76df969
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-209
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-21 b/cmds/servicemanager/corpus/seed-2024-08-29-21
new file mode 100644
index 0000000..510b9cf
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-21
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-210 b/cmds/servicemanager/corpus/seed-2024-08-29-210
new file mode 100644
index 0000000..b5174e0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-210
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-211 b/cmds/servicemanager/corpus/seed-2024-08-29-211
new file mode 100644
index 0000000..51af471
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-211
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-212 b/cmds/servicemanager/corpus/seed-2024-08-29-212
new file mode 100644
index 0000000..f260df4
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-212
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-213 b/cmds/servicemanager/corpus/seed-2024-08-29-213
new file mode 100644
index 0000000..2d322b9
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-213
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-214 b/cmds/servicemanager/corpus/seed-2024-08-29-214
new file mode 100644
index 0000000..8df3af4
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-214
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-215 b/cmds/servicemanager/corpus/seed-2024-08-29-215
new file mode 100644
index 0000000..b82d03b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-215
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-216 b/cmds/servicemanager/corpus/seed-2024-08-29-216
new file mode 100644
index 0000000..16f6d4d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-216
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-217 b/cmds/servicemanager/corpus/seed-2024-08-29-217
new file mode 100644
index 0000000..d4c2bb3
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-217
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-218 b/cmds/servicemanager/corpus/seed-2024-08-29-218
new file mode 100644
index 0000000..d0c1970
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-218
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-219 b/cmds/servicemanager/corpus/seed-2024-08-29-219
new file mode 100644
index 0000000..75edd86
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-219
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-22 b/cmds/servicemanager/corpus/seed-2024-08-29-22
new file mode 100644
index 0000000..aa87441
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-22
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-220 b/cmds/servicemanager/corpus/seed-2024-08-29-220
new file mode 100644
index 0000000..b3b6788
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-220
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-221 b/cmds/servicemanager/corpus/seed-2024-08-29-221
new file mode 100644
index 0000000..429da0e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-221
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-222 b/cmds/servicemanager/corpus/seed-2024-08-29-222
new file mode 100644
index 0000000..be8e3f3
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-222
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-223 b/cmds/servicemanager/corpus/seed-2024-08-29-223
new file mode 100644
index 0000000..a5a6d9c
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-223
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-224 b/cmds/servicemanager/corpus/seed-2024-08-29-224
new file mode 100644
index 0000000..9a7d07e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-224
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-225 b/cmds/servicemanager/corpus/seed-2024-08-29-225
new file mode 100644
index 0000000..39a5644
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-225
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-226 b/cmds/servicemanager/corpus/seed-2024-08-29-226
new file mode 100644
index 0000000..c32f26a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-226
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-227 b/cmds/servicemanager/corpus/seed-2024-08-29-227
new file mode 100644
index 0000000..5af105b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-227
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-23 b/cmds/servicemanager/corpus/seed-2024-08-29-23
new file mode 100644
index 0000000..4399c39
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-23
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-24 b/cmds/servicemanager/corpus/seed-2024-08-29-24
new file mode 100644
index 0000000..133c59a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-24
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-25 b/cmds/servicemanager/corpus/seed-2024-08-29-25
new file mode 100644
index 0000000..ec1ac02
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-25
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-26 b/cmds/servicemanager/corpus/seed-2024-08-29-26
new file mode 100644
index 0000000..55397b9
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-26
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-27 b/cmds/servicemanager/corpus/seed-2024-08-29-27
new file mode 100644
index 0000000..517af0b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-27
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-28 b/cmds/servicemanager/corpus/seed-2024-08-29-28
new file mode 100644
index 0000000..0401668
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-28
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-29 b/cmds/servicemanager/corpus/seed-2024-08-29-29
new file mode 100644
index 0000000..05ad4ec
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-29
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-3 b/cmds/servicemanager/corpus/seed-2024-08-29-3
new file mode 100644
index 0000000..14dcdd0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-3
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-30 b/cmds/servicemanager/corpus/seed-2024-08-29-30
new file mode 100644
index 0000000..d941024
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-30
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-31 b/cmds/servicemanager/corpus/seed-2024-08-29-31
new file mode 100644
index 0000000..e93a192
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-31
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-32 b/cmds/servicemanager/corpus/seed-2024-08-29-32
new file mode 100644
index 0000000..36f82dd
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-32
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-33 b/cmds/servicemanager/corpus/seed-2024-08-29-33
new file mode 100644
index 0000000..5f64227
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-33
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-34 b/cmds/servicemanager/corpus/seed-2024-08-29-34
new file mode 100644
index 0000000..13f7634
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-34
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-35 b/cmds/servicemanager/corpus/seed-2024-08-29-35
new file mode 100644
index 0000000..3a4476e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-35
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-36 b/cmds/servicemanager/corpus/seed-2024-08-29-36
new file mode 100644
index 0000000..da9c208
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-36
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-37 b/cmds/servicemanager/corpus/seed-2024-08-29-37
new file mode 100644
index 0000000..969a957
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-37
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-38 b/cmds/servicemanager/corpus/seed-2024-08-29-38
new file mode 100644
index 0000000..ab6f106
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-38
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-39 b/cmds/servicemanager/corpus/seed-2024-08-29-39
new file mode 100644
index 0000000..248a549
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-39
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-4 b/cmds/servicemanager/corpus/seed-2024-08-29-4
new file mode 100644
index 0000000..0bd7cd5
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-4
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-40 b/cmds/servicemanager/corpus/seed-2024-08-29-40
new file mode 100644
index 0000000..7031a91
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-40
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-41 b/cmds/servicemanager/corpus/seed-2024-08-29-41
new file mode 100644
index 0000000..8b8925c
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-41
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-42 b/cmds/servicemanager/corpus/seed-2024-08-29-42
new file mode 100644
index 0000000..c6e2167
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-42
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-43 b/cmds/servicemanager/corpus/seed-2024-08-29-43
new file mode 100644
index 0000000..671a821
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-43
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-44 b/cmds/servicemanager/corpus/seed-2024-08-29-44
new file mode 100644
index 0000000..7c365b0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-44
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-45 b/cmds/servicemanager/corpus/seed-2024-08-29-45
new file mode 100644
index 0000000..a38d138
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-45
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-46 b/cmds/servicemanager/corpus/seed-2024-08-29-46
new file mode 100644
index 0000000..62acb77
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-46
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-47 b/cmds/servicemanager/corpus/seed-2024-08-29-47
new file mode 100644
index 0000000..aea84c6
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-47
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-48 b/cmds/servicemanager/corpus/seed-2024-08-29-48
new file mode 100644
index 0000000..a5bab7c
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-48
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-49 b/cmds/servicemanager/corpus/seed-2024-08-29-49
new file mode 100644
index 0000000..4f19f09
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-49
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-5 b/cmds/servicemanager/corpus/seed-2024-08-29-5
new file mode 100644
index 0000000..4e8a853
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-5
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-50 b/cmds/servicemanager/corpus/seed-2024-08-29-50
new file mode 100644
index 0000000..2f1d78b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-50
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-51 b/cmds/servicemanager/corpus/seed-2024-08-29-51
new file mode 100644
index 0000000..7a44b4a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-51
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-52 b/cmds/servicemanager/corpus/seed-2024-08-29-52
new file mode 100644
index 0000000..3da177b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-52
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-53 b/cmds/servicemanager/corpus/seed-2024-08-29-53
new file mode 100644
index 0000000..c67df71
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-53
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-54 b/cmds/servicemanager/corpus/seed-2024-08-29-54
new file mode 100644
index 0000000..b1e8fec
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-54
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-55 b/cmds/servicemanager/corpus/seed-2024-08-29-55
new file mode 100644
index 0000000..20b268a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-55
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-56 b/cmds/servicemanager/corpus/seed-2024-08-29-56
new file mode 100644
index 0000000..1461926
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-56
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-57 b/cmds/servicemanager/corpus/seed-2024-08-29-57
new file mode 100644
index 0000000..fab8065
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-57
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-58 b/cmds/servicemanager/corpus/seed-2024-08-29-58
new file mode 100644
index 0000000..676f9e4
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-58
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-59 b/cmds/servicemanager/corpus/seed-2024-08-29-59
new file mode 100644
index 0000000..a8e2c72
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-59
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-6 b/cmds/servicemanager/corpus/seed-2024-08-29-6
new file mode 100644
index 0000000..585f1f0
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-6
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-60 b/cmds/servicemanager/corpus/seed-2024-08-29-60
new file mode 100644
index 0000000..ef4b098
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-60
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-61 b/cmds/servicemanager/corpus/seed-2024-08-29-61
new file mode 100644
index 0000000..5f45443
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-61
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-62 b/cmds/servicemanager/corpus/seed-2024-08-29-62
new file mode 100644
index 0000000..7ffd776
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-62
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-63 b/cmds/servicemanager/corpus/seed-2024-08-29-63
new file mode 100644
index 0000000..fa026cd
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-63
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-64 b/cmds/servicemanager/corpus/seed-2024-08-29-64
new file mode 100644
index 0000000..422c823
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-64
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-65 b/cmds/servicemanager/corpus/seed-2024-08-29-65
new file mode 100644
index 0000000..c811c44
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-65
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-66 b/cmds/servicemanager/corpus/seed-2024-08-29-66
new file mode 100644
index 0000000..8407da2
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-66
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-67 b/cmds/servicemanager/corpus/seed-2024-08-29-67
new file mode 100644
index 0000000..76dfdc3
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-67
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-68 b/cmds/servicemanager/corpus/seed-2024-08-29-68
new file mode 100644
index 0000000..d93e0e3
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-68
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-69 b/cmds/servicemanager/corpus/seed-2024-08-29-69
new file mode 100644
index 0000000..12b501b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-69
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-7 b/cmds/servicemanager/corpus/seed-2024-08-29-7
new file mode 100644
index 0000000..6478363
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-7
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-70 b/cmds/servicemanager/corpus/seed-2024-08-29-70
new file mode 100644
index 0000000..e620623
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-70
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-71 b/cmds/servicemanager/corpus/seed-2024-08-29-71
new file mode 100644
index 0000000..dc32a5f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-71
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-72 b/cmds/servicemanager/corpus/seed-2024-08-29-72
new file mode 100644
index 0000000..24217c6
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-72
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-73 b/cmds/servicemanager/corpus/seed-2024-08-29-73
new file mode 100644
index 0000000..a9a0b2b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-73
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-74 b/cmds/servicemanager/corpus/seed-2024-08-29-74
new file mode 100644
index 0000000..fd8a429
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-74
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-75 b/cmds/servicemanager/corpus/seed-2024-08-29-75
new file mode 100644
index 0000000..090b489
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-75
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-76 b/cmds/servicemanager/corpus/seed-2024-08-29-76
new file mode 100644
index 0000000..c92c45f
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-76
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-77 b/cmds/servicemanager/corpus/seed-2024-08-29-77
new file mode 100644
index 0000000..002a233
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-77
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-78 b/cmds/servicemanager/corpus/seed-2024-08-29-78
new file mode 100644
index 0000000..633f937
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-78
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-79 b/cmds/servicemanager/corpus/seed-2024-08-29-79
new file mode 100644
index 0000000..7778240
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-79
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-8 b/cmds/servicemanager/corpus/seed-2024-08-29-8
new file mode 100644
index 0000000..580e200
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-8
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-80 b/cmds/servicemanager/corpus/seed-2024-08-29-80
new file mode 100644
index 0000000..90d74e4
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-80
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-81 b/cmds/servicemanager/corpus/seed-2024-08-29-81
new file mode 100644
index 0000000..1fd7668
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-81
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-82 b/cmds/servicemanager/corpus/seed-2024-08-29-82
new file mode 100644
index 0000000..d771501
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-82
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-83 b/cmds/servicemanager/corpus/seed-2024-08-29-83
new file mode 100644
index 0000000..6a4a1ca
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-83
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-84 b/cmds/servicemanager/corpus/seed-2024-08-29-84
new file mode 100644
index 0000000..bf8459b
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-84
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-85 b/cmds/servicemanager/corpus/seed-2024-08-29-85
new file mode 100644
index 0000000..8c88cac
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-85
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-86 b/cmds/servicemanager/corpus/seed-2024-08-29-86
new file mode 100644
index 0000000..62f6765
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-86
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-87 b/cmds/servicemanager/corpus/seed-2024-08-29-87
new file mode 100644
index 0000000..eb54dcb
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-87
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-88 b/cmds/servicemanager/corpus/seed-2024-08-29-88
new file mode 100644
index 0000000..f38aaba
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-88
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-89 b/cmds/servicemanager/corpus/seed-2024-08-29-89
new file mode 100644
index 0000000..b4154ae
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-89
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-9 b/cmds/servicemanager/corpus/seed-2024-08-29-9
new file mode 100644
index 0000000..5dca38a
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-9
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-90 b/cmds/servicemanager/corpus/seed-2024-08-29-90
new file mode 100644
index 0000000..2725a79
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-90
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-91 b/cmds/servicemanager/corpus/seed-2024-08-29-91
new file mode 100644
index 0000000..9140e28
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-91
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-92 b/cmds/servicemanager/corpus/seed-2024-08-29-92
new file mode 100644
index 0000000..88dda1e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-92
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-93 b/cmds/servicemanager/corpus/seed-2024-08-29-93
new file mode 100644
index 0000000..6dd114e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-93
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-94 b/cmds/servicemanager/corpus/seed-2024-08-29-94
new file mode 100644
index 0000000..462c185
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-94
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-95 b/cmds/servicemanager/corpus/seed-2024-08-29-95
new file mode 100644
index 0000000..4472deb
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-95
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-96 b/cmds/servicemanager/corpus/seed-2024-08-29-96
new file mode 100644
index 0000000..875efc5
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-96
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-97 b/cmds/servicemanager/corpus/seed-2024-08-29-97
new file mode 100644
index 0000000..3f0277e
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-97
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-98 b/cmds/servicemanager/corpus/seed-2024-08-29-98
new file mode 100644
index 0000000..2c66436
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-98
Binary files differ
diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-99 b/cmds/servicemanager/corpus/seed-2024-08-29-99
new file mode 100644
index 0000000..9a6ff1d
--- /dev/null
+++ b/cmds/servicemanager/corpus/seed-2024-08-29-99
Binary files differ
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index 769670e..0b7e16b 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -27,7 +27,7 @@
namespace android {
// ----------------------------------------------------------------------------
-
+// TODO(b/309532236) replace this class with AIDL generated parcelable
class IAudioManager : public IInterface
{
public:
@@ -43,6 +43,7 @@
RELEASE_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 6,
PLAYER_SESSION_ID = IBinder::FIRST_CALL_TRANSACTION + 7,
PORT_EVENT = IBinder::FIRST_CALL_TRANSACTION + 8,
+ PERMISSION_UPDATE_BARRIER = IBinder::FIRST_CALL_TRANSACTION + 9,
};
DECLARE_META_INTERFACE(AudioManager)
@@ -63,6 +64,7 @@
/*oneway*/ virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) = 0;
/*oneway*/ virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,
const std::unique_ptr<os::PersistableBundle>& extras) = 0;
+ virtual status_t permissionUpdateBarrier() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index 43e9fac..3d5d52e 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -234,7 +234,7 @@
}
// Extracts the elements as std::vector.
- std::vector<T> promote() && {
+ std::vector<std::remove_const_t<T>> promote() && {
if (dynamic()) {
return std::get<Dynamic>(std::move(vector_)).promote();
} else {
@@ -290,11 +290,11 @@
class SmallVector<T, 0> final : details::ArrayTraits<T>,
details::ArrayComparators<SmallVector>,
details::ArrayIterators<SmallVector<T, 0>, T>,
- std::vector<T> {
+ std::vector<std::remove_const_t<T>> {
using details::ArrayTraits<T>::replace_at;
using Iter = details::ArrayIterators<SmallVector, T>;
- using Impl = std::vector<T>;
+ using Impl = std::vector<std::remove_const_t<T>>;
friend Iter;
@@ -394,12 +394,12 @@
pop_back();
}
- std::vector<T> promote() && { return std::move(*this); }
+ std::vector<std::remove_const_t<T>> promote() && { return std::move(*this); }
private:
template <typename U, std::size_t M>
static Impl convert(SmallVector<U, M>&& other) {
- if constexpr (std::is_constructible_v<Impl, std::vector<U>&&>) {
+ if constexpr (std::is_constructible_v<Impl, std::vector<std::remove_const_t<U>>&&>) {
return std::move(other).promote();
} else {
SmallVector vector(other.size());
diff --git a/include/input/Input.h b/include/input/Input.h
index 1a3cb6a..a8684bd 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -251,6 +251,8 @@
TOUCH_MODE = AINPUT_EVENT_TYPE_TOUCH_MODE,
ftl_first = KEY,
ftl_last = TOUCH_MODE,
+ // Used by LatencyTracker fuzzer
+ kMaxValue = ftl_last
};
std::string inputEventSourceToString(int32_t source);
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index 65c2914..358a191 100644
--- a/include/input/InputConsumerNoResampling.h
+++ b/include/input/InputConsumerNoResampling.h
@@ -17,6 +17,7 @@
#pragma once
#include <input/InputTransport.h>
+#include <input/LooperInterface.h>
#include <input/Resampler.h>
#include <utils/Looper.h>
@@ -66,6 +67,16 @@
class InputConsumerNoResampling final {
public:
/**
+ * This constructor is exclusively for test code. Any real use of InputConsumerNoResampling must
+ * use the constructor that takes an sp<Looper> parameter instead of
+ * std::shared_ptr<LooperInterface>.
+ */
+ explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
+ std::shared_ptr<LooperInterface> looper,
+ InputConsumerCallbacks& callbacks,
+ std::unique_ptr<Resampler> resampler);
+
+ /**
* @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever
* the event is ready to consume.
* @param looper needs to be sp and not shared_ptr because it inherits from
@@ -108,7 +119,7 @@
private:
std::shared_ptr<InputChannel> mChannel;
- sp<Looper> mLooper;
+ std::shared_ptr<LooperInterface> mLooper;
InputConsumerCallbacks& mCallbacks;
std::unique_ptr<Resampler> mResampler;
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 7d8c19e..1a48239 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -389,6 +389,7 @@
CONFIGURATION = 0, /* .idc file */
KEY_LAYOUT = 1, /* .kl file */
KEY_CHARACTER_MAP = 2, /* .kcm file */
+ ftl_last = KEY_CHARACTER_MAP,
};
/*
diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h
index 55e0583..5bd5070 100644
--- a/include/input/InputEventBuilders.h
+++ b/include/input/InputEventBuilders.h
@@ -19,6 +19,8 @@
#include <android/input.h>
#include <attestation/HmacKeyManager.h>
#include <input/Input.h>
+#include <input/InputTransport.h>
+#include <ui/LogicalDisplayId.h>
#include <utils/Timers.h> // for nsecs_t, systemTime
#include <vector>
@@ -44,6 +46,11 @@
PointerBuilder& y(float y) { return axis(AMOTION_EVENT_AXIS_Y, y); }
+ PointerBuilder& isResampled(bool isResampled) {
+ mCoords.isResampled = isResampled;
+ return *this;
+ }
+
PointerBuilder& axis(int32_t axis, float value) {
mCoords.setAxisValue(axis, value);
return *this;
@@ -58,6 +65,87 @@
PointerCoords mCoords;
};
+class InputMessageBuilder {
+public:
+ InputMessageBuilder(InputMessage::Type type, uint32_t seq) : mType{type}, mSeq{seq} {}
+
+ InputMessageBuilder& eventId(int32_t eventId) {
+ mEventId = eventId;
+ return *this;
+ }
+
+ InputMessageBuilder& eventTime(nsecs_t eventTime) {
+ mEventTime = eventTime;
+ return *this;
+ }
+
+ InputMessageBuilder& deviceId(DeviceId deviceId) {
+ mDeviceId = deviceId;
+ return *this;
+ }
+
+ InputMessageBuilder& source(int32_t source) {
+ mSource = source;
+ return *this;
+ }
+
+ InputMessageBuilder& displayId(ui::LogicalDisplayId displayId) {
+ mDisplayId = displayId;
+ return *this;
+ }
+
+ InputMessageBuilder& action(int32_t action) {
+ mAction = action;
+ return *this;
+ }
+
+ InputMessageBuilder& downTime(nsecs_t downTime) {
+ mDownTime = downTime;
+ return *this;
+ }
+
+ InputMessageBuilder& pointer(PointerBuilder pointerBuilder) {
+ mPointers.push_back(pointerBuilder);
+ return *this;
+ }
+
+ InputMessage build() const {
+ InputMessage message{};
+ // Header
+ message.header.type = mType;
+ message.header.seq = mSeq;
+ // Body
+ message.body.motion.eventId = mEventId;
+ message.body.motion.pointerCount = mPointers.size();
+ message.body.motion.eventTime = mEventTime;
+ message.body.motion.deviceId = mDeviceId;
+ message.body.motion.source = mSource;
+ message.body.motion.displayId = mDisplayId.val();
+ message.body.motion.action = mAction;
+ message.body.motion.downTime = mDownTime;
+
+ for (size_t i = 0; i < mPointers.size(); ++i) {
+ message.body.motion.pointers[i].properties = mPointers[i].buildProperties();
+ message.body.motion.pointers[i].coords = mPointers[i].buildCoords();
+ }
+ return message;
+ }
+
+private:
+ const InputMessage::Type mType;
+ const uint32_t mSeq;
+
+ int32_t mEventId{InputEvent::nextId()};
+ nsecs_t mEventTime{systemTime(SYSTEM_TIME_MONOTONIC)};
+ DeviceId mDeviceId{DEFAULT_DEVICE_ID};
+ int32_t mSource{AINPUT_SOURCE_TOUCHSCREEN};
+ ui::LogicalDisplayId mDisplayId{ui::LogicalDisplayId::DEFAULT};
+ int32_t mAction{AMOTION_EVENT_ACTION_MOVE};
+ nsecs_t mDownTime{mEventTime};
+
+ std::vector<PointerBuilder> mPointers;
+};
+
class MotionEventBuilder {
public:
MotionEventBuilder(int32_t action, int32_t source) {
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 7d11f76..0cd8720 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -263,7 +263,7 @@
* Return DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t sendMessage(const InputMessage* msg);
+ virtual status_t sendMessage(const InputMessage* msg);
/* Receive a message sent by the other endpoint.
*
@@ -275,14 +275,14 @@
* Return DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- android::base::Result<InputMessage> receiveMessage();
+ virtual android::base::Result<InputMessage> receiveMessage();
/* Tells whether there is a message in the channel available to be received.
*
* This is only a performance hint and may return false negative results. Clients should not
* rely on availability of the message based on the return value.
*/
- bool probablyHasInput() const;
+ virtual bool probablyHasInput() const;
/* Wait until there is a message in the channel.
*
@@ -323,11 +323,12 @@
*/
sp<IBinder> getConnectionToken() const;
+protected:
+ InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
+
private:
static std::unique_ptr<InputChannel> create(const std::string& name,
android::base::unique_fd fd, sp<IBinder> token);
-
- InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
};
/*
diff --git a/include/input/LooperInterface.h b/include/input/LooperInterface.h
new file mode 100644
index 0000000..2d6719c
--- /dev/null
+++ b/include/input/LooperInterface.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+/**
+ * LooperInterface allows the use of TestLooper in InputConsumerNoResampling without reassigning to
+ * Looper. LooperInterface is needed to control how InputConsumerNoResampling consumes and batches
+ * InputMessages.
+ */
+class LooperInterface {
+public:
+ virtual ~LooperInterface() = default;
+
+ virtual int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+ void* data) = 0;
+ virtual int removeFd(int fd) = 0;
+
+ virtual sp<Looper> getLooper() const = 0;
+};
+} // namespace android
diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h
index 8c356d0..e5eee34 100644
--- a/include/private/performance_hint_private.h
+++ b/include/private/performance_hint_private.h
@@ -108,6 +108,10 @@
const int32_t* threadIds, size_t size,
int64_t initialTargetWorkDurationNanos, SessionTag tag);
+/**
+ * Forces FMQ to be enabled or disabled, for testing only.
+ */
+void APerformanceHint_setUseFMQForTesting(bool enabled);
__END_DECLS
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index 78896ed..d31cb3d 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -390,13 +390,16 @@
}
}
- static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"};
+ static constexpr std::pair<const char*, bool> key_paths[] = {
+ {"/adb_keys", true /* follow symlinks */ },
+ {"/data/misc/adb/adb_keys", false /* don't follow symlinks */ },
+ };
void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
- for (const auto& path : key_paths) {
+ for (const auto& [path, follow_symlinks] : key_paths) {
if (access(path, R_OK) == 0) {
LOG(INFO) << "adbd_auth: loading keys from " << path;
std::string content;
- if (!android::base::ReadFileToString(path, &content)) {
+ if (!android::base::ReadFileToString(path, &content, follow_symlinks)) {
PLOG(ERROR) << "adbd_auth: couldn't read " << path;
continue;
}
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index de331b7..379b609 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -87,6 +87,11 @@
cc_cmake_snapshot {
name: "binder_sdk",
+ dist: {
+ targets: ["binder_sdk"],
+ dest: "binder_sdk.zip",
+ },
+
modules_host: [
"libbinder_sdk",
"libbinder_sdk_single_threaded",
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 54f687b..5680798 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -24,11 +24,111 @@
namespace android {
+#ifdef LIBBINDER_CLIENT_CACHE
+constexpr bool kUseCache = true;
+#else
+constexpr bool kUseCache = false;
+#endif
+
using AidlServiceManager = android::os::IServiceManager;
using IAccessor = android::os::IAccessor;
+static const char* kStaticCachableList[] = {
+ "activity",
+ "android.hardware.thermal.IThermal/default",
+ "android.hardware.power.IPower/default",
+ "android.frameworks.stats.IStats/default",
+ "android.system.suspend.ISystemSuspend/default",
+ "appops",
+ "audio",
+ "batterystats",
+ "carrier_config",
+ "connectivity",
+ "content_capture",
+ "device_policy",
+ "display",
+ "dropbox",
+ "econtroller",
+ "isub",
+ "legacy_permission",
+ "location",
+ "media.extractor",
+ "media.metrics",
+ "media.player",
+ "media.resource_manager",
+ "netd_listener",
+ "netstats",
+ "network_management",
+ "nfc",
+ "package_native",
+ "performance_hint",
+ "permission",
+ "permissionmgr",
+ "permission_checker",
+ "phone",
+ "platform_compat",
+ "power",
+ "role",
+ "sensorservice",
+ "statscompanion",
+ "telephony.registry",
+ "thermalservice",
+ "time_detector",
+ "trust",
+ "uimode",
+ "virtualdevice",
+ "virtualdevice_native",
+ "webviewupdate",
+};
+
+bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
+ if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) {
+ ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be "
+ "implemented. serviceName: %s",
+ serviceName.c_str());
+ return false;
+ }
+ for (const char* name : kStaticCachableList) {
+ if (name == serviceName) {
+ return true;
+ }
+ }
+ return false;
+}
+
+binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName,
+ const os::Service& service) {
+ if (!kUseCache) {
+ return binder::Status::ok();
+ }
+ if (service.getTag() == os::Service::Tag::binder) {
+ sp<IBinder> binder = service.get<os::Service::Tag::binder>();
+ if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) &&
+ binder->isBinderAlive()) {
+ return mCacheForGetService->setItem(serviceName, binder);
+ }
+ }
+ return binder::Status::ok();
+}
+
+bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName,
+ os::Service* _out) {
+ if (!kUseCache) {
+ return false;
+ }
+ sp<IBinder> item = mCacheForGetService->getItem(serviceName);
+ // TODO(b/363177618): Enable caching for binders which are always null.
+ if (item != nullptr && item->isBinderAlive()) {
+ *_out = os::Service::make<os::Service::Tag::binder>(item);
+ return true;
+ }
+ return false;
+}
+
BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceManager>& impl)
- : mTheRealServiceManager(impl) {}
+ : mTheRealServiceManager(impl) {
+ mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>();
+}
sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() {
return mTheRealServiceManager;
@@ -44,25 +144,64 @@
binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name,
os::Service* _out) {
+ if (returnIfCached(name, _out)) {
+ return binder::Status::ok();
+ }
os::Service service;
binder::Status status = mTheRealServiceManager->getService2(name, &service);
- toBinderService(service, _out);
+
+ if (status.isOk()) {
+ status = toBinderService(name, service, _out);
+ if (status.isOk()) {
+ return updateCache(name, service);
+ }
+ }
return status;
}
binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name,
os::Service* _out) {
os::Service service;
+ if (returnIfCached(name, _out)) {
+ return binder::Status::ok();
+ }
+
binder::Status status = mTheRealServiceManager->checkService(name, &service);
- toBinderService(service, _out);
+ if (status.isOk()) {
+ status = toBinderService(name, service, _out);
+ if (status.isOk()) {
+ return updateCache(name, service);
+ }
+ }
return status;
}
-void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Service* _out) {
+binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name,
+ const os::Service& in,
+ os::Service* _out) {
switch (in.getTag()) {
case os::Service::Tag::binder: {
+ if (in.get<os::Service::Tag::binder>() == nullptr) {
+ // failed to find a service. Check to see if we have any local
+ // injected Accessors for this service.
+ os::Service accessor;
+ binder::Status status = getInjectedAccessor(name, &accessor);
+ if (!status.isOk()) {
+ *_out = os::Service::make<os::Service::Tag::binder>(nullptr);
+ return status;
+ }
+ if (accessor.getTag() == os::Service::Tag::accessor &&
+ accessor.get<os::Service::Tag::accessor>() != nullptr) {
+ ALOGI("Found local injected service for %s, will attempt to create connection",
+ name.c_str());
+ // Call this again using the accessor Service to get the real
+ // service's binder into _out
+ return toBinderService(name, accessor, _out);
+ }
+ }
+
*_out = in;
- break;
+ return binder::Status::ok();
}
case os::Service::Tag::accessor: {
sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>();
@@ -70,7 +209,7 @@
if (accessor == nullptr) {
ALOGE("Service#accessor doesn't have accessor. VM is maybe starting...");
*_out = os::Service::make<os::Service::Tag::binder>(nullptr);
- break;
+ return binder::Status::ok();
}
auto request = [=] {
os::ParcelFileDescriptor fd;
@@ -83,10 +222,15 @@
}
};
auto session = RpcSession::make();
- session->setupPreconnectedClient(base::unique_fd{}, request);
+ status_t status = session->setupPreconnectedClient(base::unique_fd{}, request);
+ if (status != OK) {
+ ALOGE("Failed to set up preconnected binder RPC client: %s",
+ statusToString(status).c_str());
+ return binder::Status::fromStatusT(status);
+ }
session->setSessionSpecificRoot(accessorBinder);
*_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject());
- break;
+ return binder::Status::ok();
}
default: {
LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag());
@@ -177,4 +321,4 @@
return gUnifiedServiceManager;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index 8f3839f..47b2ec9 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -18,9 +18,87 @@
#include <android/os/BnServiceManager.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
+#include <map>
+#include <memory>
namespace android {
+class BinderCacheWithInvalidation
+ : public std::enable_shared_from_this<BinderCacheWithInvalidation> {
+ class BinderInvalidation : public IBinder::DeathRecipient {
+ public:
+ BinderInvalidation(std::weak_ptr<BinderCacheWithInvalidation> cache, const std::string& key)
+ : mCache(cache), mKey(key) {}
+
+ void binderDied(const wp<IBinder>& who) override {
+ sp<IBinder> binder = who.promote();
+ if (std::shared_ptr<BinderCacheWithInvalidation> cache = mCache.lock()) {
+ cache->removeItem(mKey, binder);
+ } else {
+ ALOGI("Binder Cache pointer expired: %s", mKey.c_str());
+ }
+ }
+
+ private:
+ std::weak_ptr<BinderCacheWithInvalidation> mCache;
+ std::string mKey;
+ };
+ struct Entry {
+ sp<IBinder> service;
+ sp<BinderInvalidation> deathRecipient;
+ };
+
+public:
+ sp<IBinder> getItem(const std::string& key) const {
+ std::lock_guard<std::mutex> lock(mCacheMutex);
+
+ if (auto it = mCache.find(key); it != mCache.end()) {
+ return it->second.service;
+ }
+ return nullptr;
+ }
+
+ bool removeItem(const std::string& key, const sp<IBinder>& who) {
+ std::lock_guard<std::mutex> lock(mCacheMutex);
+ if (auto it = mCache.find(key); it != mCache.end()) {
+ if (it->second.service == who) {
+ status_t result = who->unlinkToDeath(it->second.deathRecipient);
+ if (result != DEAD_OBJECT) {
+ ALOGW("Unlinking to dead binder resulted in: %d", result);
+ }
+ mCache.erase(key);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ binder::Status setItem(const std::string& key, const sp<IBinder>& item) {
+ sp<BinderInvalidation> deathRecipient =
+ sp<BinderInvalidation>::make(shared_from_this(), key);
+
+ // linkToDeath if binder is a remote binder.
+ if (item->localBinder() == nullptr) {
+ status_t status = item->linkToDeath(deathRecipient);
+ if (status != android::OK) {
+ ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(),
+ status);
+ return binder::Status::fromStatusT(status);
+ }
+ }
+ std::lock_guard<std::mutex> lock(mCacheMutex);
+ Entry entry = {.service = item, .deathRecipient = deathRecipient};
+ mCache[key] = entry;
+ return binder::Status::ok();
+ }
+
+ bool isClientSideCachingEnabled(const std::string& serviceName);
+
+private:
+ std::map<std::string, Entry> mCache;
+ mutable std::mutex mCacheMutex;
+};
+
class BackendUnifiedServiceManager : public android::os::BnServiceManager {
public:
explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl);
@@ -58,10 +136,16 @@
}
private:
+ std::shared_ptr<BinderCacheWithInvalidation> mCacheForGetService;
sp<os::IServiceManager> mTheRealServiceManager;
- void toBinderService(const os::Service& in, os::Service* _out);
+ binder::Status toBinderService(const ::std::string& name, const os::Service& in,
+ os::Service* _out);
+ binder::Status updateCache(const std::string& serviceName, const os::Service& service);
+ bool returnIfCached(const std::string& serviceName, os::Service* _out);
};
sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager();
-} // namespace android
\ No newline at end of file
+android::binder::Status getInjectedAccessor(const std::string& name, android::os::Service* service);
+
+} // namespace android
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index 455a433..f0aa801 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -82,7 +82,9 @@
int ret = TEMP_FAILURE_RETRY(poll(pfd, countof(pfd), -1));
if (ret < 0) {
- return -errno;
+ int saved_errno = errno;
+ ALOGE("FdTrigger poll returned error: %d, with error: %s", ret, strerror(saved_errno));
+ return -saved_errno;
}
LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get());
@@ -106,6 +108,7 @@
// POLLNVAL: invalid FD number, e.g. not opened.
if (pfd[0].revents & POLLNVAL) {
+ ALOGE("Invalid FD number (%d) in FdTrigger (POLLNVAL)", pfd[0].fd);
return BAD_VALUE;
}
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c55dd9d..88761d7 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+#include <sys/socket.h>
#define LOG_TAG "ServiceManagerCppClient"
#include <binder/IServiceManager.h>
+#include <binder/IServiceManagerUnitTestHelper.h>
#include "BackendUnifiedServiceManager.h"
#include <inttypes.h>
@@ -24,14 +26,19 @@
#include <chrono>
#include <condition_variable>
+#include <FdTrigger.h>
+#include <RpcSocketAddress.h>
#include <android-base/properties.h>
+#include <android/os/BnAccessor.h>
#include <android/os/BnServiceCallback.h>
+#include <android/os/BnServiceManager.h>
#include <android/os/IAccessor.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <binder/RpcSession.h>
#include <utils/String8.h>
-
+#include <variant>
#ifndef __ANDROID_VNDK__
#include <binder/IPermissionController.h>
#endif
@@ -148,8 +155,142 @@
}
};
+class AccessorProvider {
+public:
+ AccessorProvider(RpcAccessorProvider&& provider) : mProvider(std::move(provider)) {}
+ sp<IBinder> provide(const String16& name) { return mProvider(name); }
+
+private:
+ AccessorProvider() = delete;
+
+ RpcAccessorProvider mProvider;
+};
+
+class AccessorProviderEntry {
+public:
+ AccessorProviderEntry(std::shared_ptr<AccessorProvider>&& provider)
+ : mProvider(std::move(provider)) {}
+ std::shared_ptr<AccessorProvider> mProvider;
+
+private:
+ AccessorProviderEntry() = delete;
+};
+
[[clang::no_destroy]] static std::once_flag gSmOnce;
[[clang::no_destroy]] static sp<IServiceManager> gDefaultServiceManager;
+[[clang::no_destroy]] static std::mutex gAccessorProvidersMutex;
+[[clang::no_destroy]] static std::vector<AccessorProviderEntry> gAccessorProviders;
+
+class LocalAccessor : public android::os::BnAccessor {
+public:
+ LocalAccessor(const String16& instance, RpcSocketAddressProvider&& connectionInfoProvider)
+ : mInstance(instance), mConnectionInfoProvider(std::move(connectionInfoProvider)) {
+ LOG_ALWAYS_FATAL_IF(!mConnectionInfoProvider,
+ "LocalAccessor object needs a valid connection info provider");
+ }
+
+ ~LocalAccessor() {
+ if (mOnDelete) mOnDelete();
+ }
+
+ ::android::binder::Status addConnection(::android::os::ParcelFileDescriptor* outFd) {
+ using android::os::IAccessor;
+ sockaddr_storage addrStorage;
+ std::unique_ptr<FdTrigger> trigger = FdTrigger::make();
+ RpcTransportFd fd;
+ status_t status =
+ mConnectionInfoProvider(mInstance, reinterpret_cast<sockaddr*>(&addrStorage),
+ sizeof(addrStorage));
+ if (status != OK) {
+ const std::string error = "The connection info provider was unable to provide "
+ "connection info for instance " +
+ std::string(String8(mInstance).c_str()) +
+ " with status: " + statusToString(status);
+ ALOGE("%s", error.c_str());
+ return Status::fromServiceSpecificError(IAccessor::ERROR_CONNECTION_INFO_NOT_FOUND,
+ error.c_str());
+ }
+ if (addrStorage.ss_family == AF_VSOCK) {
+ sockaddr_vm* addr = reinterpret_cast<sockaddr_vm*>(&addrStorage);
+ status = singleSocketConnection(VsockSocketAddress(addr->svm_cid, addr->svm_port),
+ trigger, &fd);
+ } else if (addrStorage.ss_family == AF_UNIX) {
+ sockaddr_un* addr = reinterpret_cast<sockaddr_un*>(&addrStorage);
+ status = singleSocketConnection(UnixSocketAddress(addr->sun_path), trigger, &fd);
+ } else if (addrStorage.ss_family == AF_INET) {
+ sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&addrStorage);
+ status = singleSocketConnection(InetSocketAddress(reinterpret_cast<sockaddr*>(addr),
+ sizeof(sockaddr_in),
+ inet_ntoa(addr->sin_addr),
+ ntohs(addr->sin_port)),
+ trigger, &fd);
+ } else {
+ const std::string error =
+ "Unsupported socket family type or the ConnectionInfoProvider failed to find a "
+ "valid address. Family type: " +
+ std::to_string(addrStorage.ss_family);
+ ALOGE("%s", error.c_str());
+ return Status::fromServiceSpecificError(IAccessor::ERROR_UNSUPPORTED_SOCKET_FAMILY,
+ error.c_str());
+ }
+ if (status != OK) {
+ const std::string error = "Failed to connect to socket for " +
+ std::string(String8(mInstance).c_str()) +
+ " with status: " + statusToString(status);
+ ALOGE("%s", error.c_str());
+ int err = 0;
+ if (status == -EACCES) {
+ err = IAccessor::ERROR_FAILED_TO_CONNECT_EACCES;
+ } else {
+ err = IAccessor::ERROR_FAILED_TO_CONNECT_TO_SOCKET;
+ }
+ return Status::fromServiceSpecificError(err, error.c_str());
+ }
+ *outFd = os::ParcelFileDescriptor(std::move(fd.fd));
+ return Status::ok();
+ }
+
+ ::android::binder::Status getInstanceName(String16* instance) {
+ *instance = mInstance;
+ return Status::ok();
+ }
+
+private:
+ LocalAccessor() = delete;
+ String16 mInstance;
+ RpcSocketAddressProvider mConnectionInfoProvider;
+ std::function<void()> mOnDelete;
+};
+
+android::binder::Status getInjectedAccessor(const std::string& name,
+ android::os::Service* service) {
+ std::vector<AccessorProviderEntry> copiedProviders;
+ {
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ copiedProviders.insert(copiedProviders.begin(), gAccessorProviders.begin(),
+ gAccessorProviders.end());
+ }
+
+ // Unlocked to call the providers. This requires the providers to be
+ // threadsafe and not contain any references to objects that could be
+ // deleted.
+ for (const auto& provider : copiedProviders) {
+ sp<IBinder> binder = provider.mProvider->provide(String16(name.c_str()));
+ if (binder == nullptr) continue;
+ status_t status = validateAccessor(String16(name.c_str()), binder);
+ if (status != OK) {
+ ALOGE("A provider returned a binder that is not an IAccessor for instance %s. Status: "
+ "%s",
+ name.c_str(), statusToString(status).c_str());
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ *service = os::Service::make<os::Service::Tag::accessor>(binder);
+ return android::binder::Status::ok();
+ }
+
+ *service = os::Service::make<os::Service::Tag::accessor>(nullptr);
+ return android::binder::Status::ok();
+}
sp<IServiceManager> defaultServiceManager()
{
@@ -172,6 +313,81 @@
}
}
+sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
+ const sp<AidlServiceManager>& sm) {
+ return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm));
+}
+
+std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) {
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ std::shared_ptr<AccessorProvider> provider =
+ std::make_shared<AccessorProvider>(std::move(providerCallback));
+ std::weak_ptr<AccessorProvider> receipt = provider;
+ gAccessorProviders.push_back(AccessorProviderEntry(std::move(provider)));
+
+ return receipt;
+}
+
+status_t removeAccessorProvider(std::weak_ptr<AccessorProvider> wProvider) {
+ std::shared_ptr<AccessorProvider> provider = wProvider.lock();
+ if (provider == nullptr) {
+ ALOGE("The provider supplied to removeAccessorProvider has already been removed.");
+ return NAME_NOT_FOUND;
+ }
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ size_t sizeBefore = gAccessorProviders.size();
+ gAccessorProviders.erase(std::remove_if(gAccessorProviders.begin(), gAccessorProviders.end(),
+ [&](AccessorProviderEntry entry) {
+ return entry.mProvider == provider;
+ }),
+ gAccessorProviders.end());
+ if (sizeBefore == gAccessorProviders.size()) {
+ ALOGE("Failed to find an AccessorProvider for removeAccessorProvider");
+ return NAME_NOT_FOUND;
+ }
+
+ return OK;
+}
+
+status_t validateAccessor(const String16& instance, const sp<IBinder>& binder) {
+ if (binder == nullptr) {
+ ALOGE("Binder is null");
+ return BAD_VALUE;
+ }
+ sp<IAccessor> accessor = interface_cast<IAccessor>(binder);
+ if (accessor == nullptr) {
+ ALOGE("This binder for %s is not an IAccessor binder", String8(instance).c_str());
+ return BAD_TYPE;
+ }
+ String16 reportedInstance;
+ Status status = accessor->getInstanceName(&reportedInstance);
+ if (!status.isOk()) {
+ ALOGE("Failed to validate the binder being used to create a new ARpc_Accessor for %s with "
+ "status: %s",
+ String8(instance).c_str(), status.toString8().c_str());
+ return NAME_NOT_FOUND;
+ }
+ if (reportedInstance != instance) {
+ ALOGE("Instance %s doesn't match the Accessor's instance of %s", String8(instance).c_str(),
+ String8(reportedInstance).c_str());
+ return NAME_NOT_FOUND;
+ }
+ return OK;
+}
+
+sp<IBinder> createAccessor(const String16& instance,
+ RpcSocketAddressProvider&& connectionInfoProvider) {
+ // Try to create a new accessor
+ if (!connectionInfoProvider) {
+ ALOGE("Could not find an Accessor for %s and no ConnectionInfoProvider provided to "
+ "create a new one",
+ String8(instance).c_str());
+ return nullptr;
+ }
+ sp<IBinder> binder = sp<LocalAccessor>::make(instance, std::move(connectionInfoProvider));
+ return binder;
+}
+
#if !defined(__ANDROID_VNDK__)
// IPermissionController is not accessible to vendors
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index e8fe555..4b7af45 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1725,7 +1725,9 @@
}
}
}
- ::munmap(ptr, len);
+ if (::munmap(ptr, len) == -1) {
+ ALOGW("munmap() failed: %s", strerror(errno));
+ }
}
::close(fd);
return status;
@@ -3332,7 +3334,9 @@
void Parcel::Blob::release() {
if (mFd != -1 && mData) {
- ::munmap(mData, mSize);
+ if (::munmap(mData, mSize) == -1) {
+ ALOGW("munmap() failed: %s", strerror(errno));
+ }
}
clear();
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 49def82..cd21a91 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -589,6 +589,21 @@
status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
const std::vector<uint8_t>& sessionId,
bool incoming) {
+ RpcTransportFd transportFd;
+ status_t status = singleSocketConnection(addr, mShutdownTrigger, &transportFd);
+ if (status != OK) return status;
+
+ return initAndAddConnection(std::move(transportFd), sessionId, incoming);
+}
+
+status_t singleSocketConnection(const RpcSocketAddress& addr,
+ const std::unique_ptr<FdTrigger>& shutdownTrigger,
+ RpcTransportFd* outFd) {
+ LOG_ALWAYS_FATAL_IF(outFd == nullptr,
+ "There is no reason to call this function without an outFd");
+ LOG_ALWAYS_FATAL_IF(shutdownTrigger == nullptr,
+ "FdTrigger argument is required so we don't get stuck in the connect call "
+ "if the server process shuts down.");
for (size_t tries = 0; tries < 5; tries++) {
if (tries > 0) usleep(10000);
@@ -620,7 +635,7 @@
if (connErrno == EAGAIN || connErrno == EINPROGRESS) {
// For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
// EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
- status_t pollStatus = mShutdownTrigger->triggerablePoll(transportFd, POLLOUT);
+ status_t pollStatus = shutdownTrigger->triggerablePoll(transportFd, POLLOUT);
if (pollStatus != OK) {
ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
statusToString(pollStatus).c_str());
@@ -654,7 +669,8 @@
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(),
transportFd.fd.get());
- return initAndAddConnection(std::move(transportFd), sessionId, incoming);
+ *outFd = std::move(transportFd);
+ return OK;
}
ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h
index c7ba5d9..ee7d448 100644
--- a/libs/binder/RpcSocketAddress.h
+++ b/libs/binder/RpcSocketAddress.h
@@ -113,4 +113,11 @@
unsigned int mPort;
};
+/**
+ * Connects to a single socket and produces a RpcTransportFd.
+ */
+status_t singleSocketConnection(const RpcSocketAddress& address,
+ const std::unique_ptr<FdTrigger>& shutdownTrigger,
+ RpcTransportFd* outFd);
+
} // namespace android
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 1256173..95a5da2 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -133,6 +133,9 @@
{
"name": "binder_sdk_test",
"host": true
+ },
+ {
+ "name": "binderCacheUnitTest"
}
],
"imports": [
diff --git a/libs/binder/aidl/android/os/IAccessor.aidl b/libs/binder/aidl/android/os/IAccessor.aidl
index a3134a3..c06e05c 100644
--- a/libs/binder/aidl/android/os/IAccessor.aidl
+++ b/libs/binder/aidl/android/os/IAccessor.aidl
@@ -25,15 +25,56 @@
*/
interface IAccessor {
/**
+ * The connection info was not available for this service.
+ * This happens when the user-supplied callback fails to produce
+ * valid connection info.
+ * Depending on the implementation of the callback, it might be helpful
+ * to retry.
+ */
+ const int ERROR_CONNECTION_INFO_NOT_FOUND = 0;
+ /**
+ * Failed to create the socket. Often happens when the process trying to create
+ * the socket lacks the permissions to do so.
+ * This may be a temporary issue, so retrying the operation is OK.
+ */
+ const int ERROR_FAILED_TO_CREATE_SOCKET = 1;
+ /**
+ * Failed to connect to the socket. This can happen for many reasons, so be sure
+ * log the error message and check it.
+ * This may be a temporary issue, so retrying the operation is OK.
+ */
+ const int ERROR_FAILED_TO_CONNECT_TO_SOCKET = 2;
+ /**
+ * Failed to connect to the socket with EACCES because this process does not
+ * have perimssions to connect.
+ * There is no need to retry the connection as this access will not be granted
+ * upon retry.
+ */
+ const int ERROR_FAILED_TO_CONNECT_EACCES = 3;
+ /**
+ * Unsupported socket family type returned.
+ * There is no need to retry the connection as this socket family is not
+ * supported.
+ */
+ const int ERROR_UNSUPPORTED_SOCKET_FAMILY = 4;
+
+ /**
* Adds a connection to the RPC server of the service managed by the IAccessor.
*
* This method can be called multiple times to establish multiple distinct
* connections to the same RPC server.
*
+ * @throws ServiceSpecificError with message and one of the IAccessor::ERROR_ values.
+ *
* @return A file descriptor connected to the RPC session of the service managed
* by IAccessor.
*/
ParcelFileDescriptor addConnection();
- // TODO(b/350941051): Add API for debugging.
+ /**
+ * Get the instance name for the service this accessor is responsible for.
+ *
+ * This is used to verify the proxy binder is associated with the expected instance name.
+ */
+ String getInstanceName();
}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 5fb7307..879f319 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -17,14 +17,16 @@
#pragma once
#include <binder/Common.h>
#include <binder/IInterface.h>
-#include <utils/Vector.h>
+// Trusty has its own definition of socket APIs from trusty_ipc.h
+#ifndef __TRUSTY__
+#include <sys/socket.h>
+#endif // __TRUSTY__
#include <utils/String16.h>
+#include <utils/Vector.h>
#include <optional>
namespace android {
-// ----------------------------------------------------------------------
-
/**
* Service manager for C++ services.
*
@@ -216,6 +218,64 @@
LIBBINDER_EXPORTED bool checkPermission(const String16& permission, pid_t pid, uid_t uid,
bool logPermissionFailure = true);
+// ----------------------------------------------------------------------
+// Trusty's definition of the socket APIs does not include sockaddr types
+#ifndef __TRUSTY__
+typedef std::function<status_t(const String16& name, sockaddr* outAddr, socklen_t addrSize)>
+ RpcSocketAddressProvider;
+
+typedef std::function<sp<IBinder>(const String16& name)> RpcAccessorProvider;
+
+class AccessorProvider;
+
+/**
+ * Register an accessor provider for the service manager APIs.
+ *
+ * \param provider callback that generates Accessors.
+ *
+ * \return A pointer used as a recept for the successful addition of the
+ * AccessorProvider. This is needed to unregister it later.
+ */
+[[nodiscard]] LIBBINDER_EXPORTED std::weak_ptr<AccessorProvider> addAccessorProvider(
+ RpcAccessorProvider&& providerCallback);
+
+/**
+ * Remove an accessor provider using the pointer provided by addAccessorProvider
+ * along with the cookie pointer that was used.
+ *
+ * \param provider cookie that was returned by addAccessorProvider to keep track
+ * of this instance.
+ */
+[[nodiscard]] LIBBINDER_EXPORTED status_t
+removeAccessorProvider(std::weak_ptr<AccessorProvider> provider);
+
+/**
+ * Create an Accessor associated with a service that can create a socket connection based
+ * on the connection info from the supplied RpcSocketAddressProvider.
+ *
+ * \param instance name of the service that this Accessor is associated with
+ * \param connectionInfoProvider a callback that returns connection info for
+ * connecting to the service.
+ * \return the binder of the IAccessor implementation from libbinder
+ */
+LIBBINDER_EXPORTED sp<IBinder> createAccessor(const String16& instance,
+ RpcSocketAddressProvider&& connectionInfoProvider);
+
+/**
+ * Check to make sure this binder is the expected binder that is an IAccessor
+ * associated with a specific instance.
+ *
+ * This helper function exists to avoid adding the IAccessor type to
+ * libbinder_ndk.
+ *
+ * \param instance name of the service that this Accessor should be associated with
+ * \param binder to validate
+ *
+ * \return OK if the binder is an IAccessor for `instance`
+ */
+LIBBINDER_EXPORTED status_t validateAccessor(const String16& instance, const sp<IBinder>& binder);
+#endif // __TRUSTY__
+
#ifndef __ANDROID__
// Create an IServiceManager that delegates the service manager on the device via adb.
// This is can be set as the default service manager at program start, so that
diff --git a/libs/binder/include/binder/IServiceManagerUnitTestHelper.h b/libs/binder/include/binder/IServiceManagerUnitTestHelper.h
new file mode 100644
index 0000000..ff25163
--- /dev/null
+++ b/libs/binder/include/binder/IServiceManagerUnitTestHelper.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/os/IServiceManager.h>
+#include "IServiceManager.h"
+namespace android {
+
+/**
+ * Encapsulate an AidlServiceManager in a CppBackendShim. Only used for testing.
+ */
+LIBBINDER_EXPORTED sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
+ const sp<os::IServiceManager>& sm);
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 4e02ace..5f45cb2 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -230,12 +230,24 @@
},
apex_available: [
"//apex_available:platform",
+ "//apex_available:anyapex",
"com.android.media",
"com.android.media.swcodec",
],
min_sdk_version: "29",
}
+// TODO: if you try to export libbinder_headers_platform_shared from libbinder_ndk.ndk, it will
+// not select the NDK variant of libbinder_headers_platform_shared and instead, it will error
+// that the NDK can't depend on glibc C++.
+cc_library_headers {
+ name: "libbinder_headers_platform_shared_ndk",
+ export_include_dirs: ["include_cpp"],
+ sdk_version: "29",
+ min_sdk_version: "29",
+ visibility: [":__subpackages__"],
+}
+
ndk_headers {
name: "libbinder_ndk_headers",
from: "include_ndk/android",
@@ -246,26 +258,14 @@
license: "NOTICE",
}
-// TODO(b/160624671): package with the aidl compiler
-ndk_headers {
- name: "libbinder_ndk_helper_headers",
- from: "include_cpp/android",
- to: "android",
- srcs: [
- "include_cpp/android/*.h",
- ],
- license: "NOTICE",
- // These are intentionally not C. It's a mistake that they're in the NDK.
- // See the bug above.
- skip_verification: true,
-}
+// include_cpp are packaged in development/build/sdk.atree with the AIDL compiler
ndk_library {
name: "libbinder_ndk",
symbol_file: "libbinder_ndk.map.txt",
first_version: "29",
export_header_libs: [
- "libbinder_ndk_headers",
- "libbinder_ndk_helper_headers",
+ // used to be part of the NDK, platform things depend on it
+ "libbinder_headers_platform_shared_ndk",
],
}
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 6273804..af56bf0 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -225,6 +225,8 @@
SpAIBinder asBinder() override final;
+ const SpAIBinder& asBinderReference() { return mBinder; }
+
bool isRemote() override final { return AIBinder_isRemote(mBinder.get()); }
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 340014a..04f1517 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -195,7 +195,7 @@
impl PartialEq for SpIBinder {
fn eq(&self, other: &Self) -> bool {
- ptr::eq(self.0.as_ptr(), other.0.as_ptr())
+ self.cmp(other) == Ordering::Equal
}
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 21c32ac..0e653af 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -46,11 +46,35 @@
"libbinder",
],
test_suites: [
- "device-tests",
+ "general-tests",
"vts",
],
}
+cc_test {
+ name: "binderCacheUnitTest",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: [
+ "binderCacheUnitTest.cpp",
+ ],
+ shared_libs: [
+ "liblog",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+ static_libs: [
+ "libfakeservicemanager",
+ ],
+ defaults: ["libbinder_client_cache_flag"],
+ test_suites: ["general-tests"],
+ require_root: true,
+}
+
// unit test only, which can run on host and doesn't use /dev/binder
cc_test {
name: "binderUnitTest",
@@ -137,7 +161,7 @@
"libgmock",
],
test_suites: [
- "device-tests",
+ "general-tests",
"vts",
],
require_root: true,
@@ -705,7 +729,7 @@
"libutils",
],
test_suites: [
- "device-tests",
+ "general-tests",
"vts",
],
require_root: true,
@@ -762,7 +786,7 @@
],
test_suites: [
- "device-tests",
+ "general-tests",
"vts",
],
require_root: true,
@@ -888,6 +912,7 @@
enabled: false,
},
},
+ corpus: ["corpus/*"],
fuzz_config: {
cc: [
"smoreland@google.com",
diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp
new file mode 100644
index 0000000..92dab19
--- /dev/null
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ */
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include <android/os/IServiceManager.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IServiceManagerUnitTestHelper.h>
+#include "fakeservicemanager/FakeServiceManager.h"
+
+#include <sys/prctl.h>
+#include <thread>
+
+using namespace android;
+
+#ifdef LIBBINDER_CLIENT_CACHE
+constexpr bool kUseLibbinderCache = true;
+#else
+constexpr bool kUseLibbinderCache = false;
+#endif
+
+// A service name which is in the static list of cachable services
+const String16 kCachedServiceName = String16("isub");
+
+#define EXPECT_OK(status) \
+ do { \
+ binder::Status stat = (status); \
+ EXPECT_TRUE(stat.isOk()) << stat; \
+ } while (false)
+
+const String16 kServerName = String16("binderCacheUnitTest");
+
+class FooBar : public BBinder {
+public:
+ status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t) {
+ // exit the server
+ std::thread([] { exit(EXIT_FAILURE); }).detach();
+ return OK;
+ }
+ void killServer(sp<IBinder> binder) {
+ Parcel data, reply;
+ binder->transact(0, data, &reply, 0);
+ }
+};
+
+class MockAidlServiceManager : public os::IServiceManagerDefault {
+public:
+ MockAidlServiceManager() : innerSm() {}
+
+ binder::Status checkService(const ::std::string& name, os::Service* _out) override {
+ sp<IBinder> binder = innerSm.getService(String16(name.c_str()));
+ *_out = os::Service::make<os::Service::Tag::binder>(binder);
+ return binder::Status::ok();
+ }
+
+ binder::Status addService(const std::string& name, const sp<IBinder>& service,
+ bool allowIsolated, int32_t dumpPriority) override {
+ return binder::Status::fromStatusT(
+ innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority));
+ }
+
+ FakeServiceManager innerSm;
+};
+
+class LibbinderCacheTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ sp<MockAidlServiceManager> sm = sp<MockAidlServiceManager>::make();
+ mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(sm);
+ }
+
+ void TearDown() override {}
+
+public:
+ void cacheAndConfirmCacheHit(const sp<IBinder>& binder1, const sp<IBinder>& binder2) {
+ // Add a service
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
+ // Get the service. This caches it.
+ sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+ ASSERT_EQ(binder1, result);
+
+ // Add the different binder and replace the service.
+ // The cache should still hold the original binder.
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+ result = mServiceManager->checkService(kCachedServiceName);
+ if (kUseLibbinderCache) {
+ // If cache is enabled, we should get the binder to Service Manager.
+ EXPECT_EQ(binder1, result);
+ } else {
+ // If cache is disabled, then we should get the newer binder
+ EXPECT_EQ(binder2, result);
+ }
+ }
+
+ sp<android::IServiceManager> mServiceManager;
+};
+
+TEST_F(LibbinderCacheTest, AddLocalServiceAndConfirmCacheHit) {
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ cacheAndConfirmCacheHit(binder1, binder2);
+}
+
+TEST_F(LibbinderCacheTest, AddRemoteServiceAndConfirmCacheHit) {
+ sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+ ASSERT_NE(binder1, nullptr);
+ sp<IBinder> binder2 = IInterface::asBinder(mServiceManager);
+
+ cacheAndConfirmCacheHit(binder1, binder2);
+}
+
+TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) {
+ sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+ FooBar foo = FooBar();
+
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
+
+ // Check Service, this caches the binder
+ sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+ ASSERT_EQ(binder1, result);
+
+ // Kill the server, this should remove from cache.
+ foo.killServer(binder1);
+ pid_t pid;
+ ASSERT_EQ(OK, binder1->getDebugPid(&pid));
+ system(("kill -9 " + std::to_string(pid)).c_str());
+
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ // Add new service with the same name.
+ // This will replace the service in FakeServiceManager.
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+ // Confirm that new service is returned instead of old.
+ sp<IBinder> result2 = mServiceManager->checkService(kCachedServiceName);
+ ASSERT_EQ(binder2, result2);
+}
+
+TEST_F(LibbinderCacheTest, NullBinderNotCached) {
+ sp<IBinder> binder1 = nullptr;
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ // Check for a cacheble service which isn't registered.
+ // FakeServiceManager should return nullptr.
+ // This shouldn't be cached.
+ sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+ ASSERT_EQ(binder1, result);
+
+ // Add the same service
+ EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+ // This should return the newly added service.
+ result = mServiceManager->checkService(kCachedServiceName);
+ EXPECT_EQ(binder2, result);
+}
+
+TEST_F(LibbinderCacheTest, DoNotCacheServiceNotInList) {
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ sp<IBinder> binder2 = sp<BBinder>::make();
+ String16 serviceName = String16("NewLibbinderCacheTest");
+ // Add a service
+ EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder1));
+ // Get the service. This shouldn't caches it.
+ sp<IBinder> result = mServiceManager->checkService(serviceName);
+ ASSERT_EQ(binder1, result);
+
+ // Add the different binder and replace the service.
+ EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder2));
+
+ // Confirm that we get the new service
+ result = mServiceManager->checkService(serviceName);
+ EXPECT_EQ(binder2, result);
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+ // Start a FooBar service and add it to the servicemanager.
+ sp<IBinder> server = new FooBar();
+ defaultServiceManager()->addService(kServerName, server);
+
+ IPCThreadState::self()->joinThreadPool(true);
+ exit(1); // should not reach
+ }
+
+ status_t err = ProcessState::self()->setThreadPoolMaxThreadCount(3);
+ ProcessState::self()->startThreadPool();
+ CHECK_EQ(ProcessState::self()->isThreadPoolStarted(), true);
+ CHECK_GT(ProcessState::self()->getThreadPoolMaxTotalThreadCount(), 0);
+
+ auto binder = defaultServiceManager()->waitForService(kServerName);
+ CHECK_NE(nullptr, binder.get());
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3038de9..fbca35e 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -365,26 +365,57 @@
session->setMaxOutgoingConnections(options.numOutgoingConnections);
session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
+ sockaddr_storage addr{};
+ socklen_t addrLen = 0;
+
switch (socketType) {
- case SocketType::PRECONNECTED:
+ case SocketType::PRECONNECTED: {
+ sockaddr_un addr_un{};
+ addr_un.sun_family = AF_UNIX;
+ strcpy(addr_un.sun_path, serverConfig.addr.c_str());
+ addr = *reinterpret_cast<sockaddr_storage*>(&addr_un);
+ addrLen = sizeof(sockaddr_un);
+
status = session->setupPreconnectedClient({}, [=]() {
return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
});
- break;
+ } break;
case SocketType::UNIX_RAW:
- case SocketType::UNIX:
+ case SocketType::UNIX: {
+ sockaddr_un addr_un{};
+ addr_un.sun_family = AF_UNIX;
+ strcpy(addr_un.sun_path, serverConfig.addr.c_str());
+ addr = *reinterpret_cast<sockaddr_storage*>(&addr_un);
+ addrLen = sizeof(sockaddr_un);
+
status = session->setupUnixDomainClient(serverConfig.addr.c_str());
- break;
+ } break;
case SocketType::UNIX_BOOTSTRAP:
status = session->setupUnixDomainSocketBootstrapClient(
unique_fd(dup(bootstrapClientFd.get())));
break;
- case SocketType::VSOCK:
+ case SocketType::VSOCK: {
+ sockaddr_vm addr_vm{
+ .svm_family = AF_VSOCK,
+ .svm_port = static_cast<unsigned int>(serverInfo.port),
+ .svm_cid = VMADDR_CID_LOCAL,
+ };
+ addr = *reinterpret_cast<sockaddr_storage*>(&addr_vm);
+ addrLen = sizeof(sockaddr_vm);
+
status = session->setupVsockClient(VMADDR_CID_LOCAL, serverInfo.port);
- break;
- case SocketType::INET:
- status = session->setupInetClient("127.0.0.1", serverInfo.port);
- break;
+ } break;
+ case SocketType::INET: {
+ const std::string ip_addr = "127.0.0.1";
+ sockaddr_in addr_in{};
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = htons(serverInfo.port);
+ inet_aton(ip_addr.c_str(), &addr_in.sin_addr);
+ addr = *reinterpret_cast<sockaddr_storage*>(&addr_in);
+ addrLen = sizeof(sockaddr_in);
+
+ status = session->setupInetClient(ip_addr.c_str(), serverInfo.port);
+ } break;
case SocketType::TIPC:
status = session->setupPreconnectedClient({}, [=]() {
#ifdef BINDER_RPC_TO_TRUSTY_TEST
@@ -413,7 +444,7 @@
break;
}
LOG_ALWAYS_FATAL_IF(status != OK, "Could not connect: %s", statusToString(status).c_str());
- ret->sessions.push_back({session, session->getRootObject()});
+ ret->sessions.push_back({session, session->getRootObject(), addr, addrLen});
}
return ret;
}
@@ -1127,6 +1158,139 @@
ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
}
+// TODO need to add IServiceManager.cpp/.h to libbinder_no_kernel
+#ifdef BINDER_WITH_KERNEL_IPC
+
+class BinderRpcAccessor : public BinderRpc {
+ void SetUp() override {
+ if (serverSingleThreaded()) {
+ // This blocks on android::FdTrigger::triggerablePoll when attempting to set
+ // up the client RpcSession
+ GTEST_SKIP() << "Accessors are not supported for single threaded libbinder";
+ }
+ if (rpcSecurity() == RpcSecurity::TLS) {
+ GTEST_SKIP() << "Accessors are not supported with TLS";
+ // ... for now
+ }
+
+ if (socketType() == SocketType::UNIX_BOOTSTRAP) {
+ GTEST_SKIP() << "Accessors do not support UNIX_BOOTSTRAP because no connection "
+ "information is known";
+ }
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "Accessors do not support TIPC because the socket transport is not "
+ "known in libbinder";
+ }
+ BinderRpc::SetUp();
+ }
+};
+
+inline void waitForExtraSessionCleanup(const BinderRpcTestProcessSession& proc) {
+ // Need to give the server some time to delete its RpcSession after our last
+ // reference is dropped, closing the connection. Check for up to 1 second,
+ // every 10 ms.
+ for (size_t i = 0; i < 100; i++) {
+ std::vector<int32_t> remoteCounts;
+ EXPECT_OK(proc.rootIface->countBinders(&remoteCounts));
+ // We exect the original binder to still be alive, we just want to wait
+ // for this extra session to be cleaned up.
+ if (remoteCounts.size() == proc.proc->sessions.size()) break;
+ usleep(10000);
+ }
+}
+
+TEST_P(BinderRpcAccessor, InjectAndGetServiceHappyPath) {
+ constexpr size_t kNumThreads = 10;
+ const String16 kInstanceName("super.cool.service/better_than_default");
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
+ return createAccessor(name,
+ [&](const String16& name, sockaddr* outAddr,
+ socklen_t addrSize) -> status_t {
+ if (outAddr == nullptr ||
+ addrSize < proc.proc->sessions[0].addrLen) {
+ return BAD_VALUE;
+ }
+ if (name == kInstanceName) {
+ if (proc.proc->sessions[0].addr.ss_family == AF_UNIX) {
+ sockaddr_un* un = reinterpret_cast<sockaddr_un*>(
+ &proc.proc->sessions[0].addr);
+ ALOGE("inside callback: %s", un->sun_path);
+ }
+ std::memcpy(outAddr, &proc.proc->sessions[0].addr,
+ proc.proc->sessions[0].addrLen);
+ return OK;
+ }
+ return NAME_NOT_FOUND;
+ });
+ });
+
+ EXPECT_FALSE(receipt.expired());
+
+ sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+ sp<IBinderRpcTest> service = checked_interface_cast<IBinderRpcTest>(binder);
+ EXPECT_NE(service, nullptr);
+
+ sp<IBinder> out;
+ EXPECT_OK(service->repeatBinder(binder, &out));
+ EXPECT_EQ(binder, out);
+
+ out.clear();
+ binder.clear();
+ service.clear();
+
+ status_t status = removeAccessorProvider(receipt);
+ EXPECT_EQ(status, OK);
+
+ waitForExtraSessionCleanup(proc);
+}
+
+TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) {
+ const String16 kInstanceName("doesnt_matter_nothing_checks");
+
+ bool isProviderDeleted = false;
+
+ auto receipt = addAccessorProvider([&](const String16&) -> sp<IBinder> { return nullptr; });
+ EXPECT_FALSE(receipt.expired());
+
+ sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+ EXPECT_EQ(binder, nullptr);
+
+ status_t status = removeAccessorProvider(receipt);
+ EXPECT_EQ(status, OK);
+}
+
+TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) {
+ constexpr size_t kNumThreads = 10;
+ const String16 kInstanceName("super.cool.service/better_than_default");
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ bool isProviderDeleted = false;
+ bool isAccessorDeleted = false;
+
+ auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
+ return createAccessor(name, [&](const String16&, sockaddr*, socklen_t) -> status_t {
+ // don't fill in outAddr
+ return NAME_NOT_FOUND;
+ });
+ });
+
+ EXPECT_FALSE(receipt.expired());
+
+ sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+ EXPECT_EQ(binder, nullptr);
+
+ status_t status = removeAccessorProvider(receipt);
+ EXPECT_EQ(status, OK);
+}
+
+#endif // BINDER_WITH_KERNEL_IPC
+
#ifdef BINDER_RPC_TO_TRUSTY_TEST
static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() {
@@ -1315,6 +1479,11 @@
INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()),
BinderRpc::PrintParamInfo);
+#ifdef BINDER_WITH_KERNEL_IPC
+INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpcAccessor, ::testing::ValuesIn(getBinderRpcParams()),
+ BinderRpc::PrintParamInfo);
+#endif // BINDER_WITH_KERNEL_IPC
+
class BinderRpcServerRootObject
: public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index 2c9646b..c8a8acc 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -35,6 +35,12 @@
struct SessionInfo {
sp<RpcSession> session;
sp<IBinder> root;
+// Trusty defines its own socket APIs in trusty_ipc.h but doesn't include
+// sockaddr types.
+#ifndef __TRUSTY__
+ sockaddr_storage addr;
+ socklen_t addrLen;
+#endif
};
// client session objects associated with other process
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index fe44ea5..583ad01 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -42,7 +42,7 @@
// equivalent.
struct PortAcl {
uint32_t flags;
- std::vector<const uuid> uuids;
+ std::vector<uuid> uuids;
const void* extraData;
};
diff --git a/libs/bufferstreams/rust/src/stream_config.rs b/libs/bufferstreams/rust/src/stream_config.rs
index 454bdf1..8288f9f 100644
--- a/libs/bufferstreams/rust/src/stream_config.rs
+++ b/libs/bufferstreams/rust/src/stream_config.rs
@@ -32,10 +32,23 @@
pub stride: u32,
}
+impl From<StreamConfig> for HardwareBufferDescription {
+ fn from(config: StreamConfig) -> Self {
+ HardwareBufferDescription::new(
+ config.width,
+ config.height,
+ config.layers,
+ config.format,
+ config.usage,
+ config.stride,
+ )
+ }
+}
+
impl StreamConfig {
/// Tries to create a new HardwareBuffer from settings in a [StreamConfig].
pub fn create_hardware_buffer(&self) -> Option<HardwareBuffer> {
- HardwareBuffer::new(self.width, self.height, self.layers, self.format, self.usage)
+ HardwareBuffer::new(&(*self).into())
}
}
@@ -59,9 +72,10 @@
assert!(maybe_buffer.is_some());
let buffer = maybe_buffer.unwrap();
- assert_eq!(config.width, buffer.width());
- assert_eq!(config.height, buffer.height());
- assert_eq!(config.format, buffer.format());
- assert_eq!(config.usage, buffer.usage());
+ let description = buffer.description();
+ assert_eq!(config.width, description.width());
+ assert_eq!(config.height, description.height());
+ assert_eq!(config.format, description.format());
+ assert_eq!(config.usage, description.usage());
}
}
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 8337182..d9cdb59 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -28,14 +28,10 @@
],
static_libs: [
"libbase",
- "libcgrouprc",
- "libcgrouprc_format",
"libcutils",
"libgralloctypes",
"libhidlbase",
"liblog",
- "libprocessgroup",
- "libjsoncpp",
"libutils",
],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 4c3f4a6..d1a5663 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -401,18 +401,10 @@
switch (driver) {
case GpuStatsInfo::Driver::GL:
case GpuStatsInfo::Driver::GL_UPDATED:
- case GpuStatsInfo::Driver::ANGLE: {
- if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE ||
- mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) {
- mGpuStats.glDriverToLoad = driver;
- break;
- }
-
- if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) {
- mGpuStats.glDriverFallback = driver;
- }
+ case GpuStatsInfo::Driver::ANGLE:
+ mGpuStats.glDriverToLoad = driver;
break;
- }
+
case GpuStatsInfo::Driver::VULKAN:
case GpuStatsInfo::Driver::VULKAN_UPDATED: {
if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE ||
@@ -561,8 +553,7 @@
bool isIntendedDriverLoaded = false;
if (api == GpuStatsInfo::Api::API_GL) {
driver = mGpuStats.glDriverToLoad;
- isIntendedDriverLoaded =
- isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE);
+ isIntendedDriverLoaded = isDriverLoaded;
} else {
driver = mGpuStats.vkDriverToLoad;
isIntendedDriverLoaded =
diff --git a/libs/graphicsenv/OWNERS b/libs/graphicsenv/OWNERS
index 1db8cbe..4aa8fff 100644
--- a/libs/graphicsenv/OWNERS
+++ b/libs/graphicsenv/OWNERS
@@ -1,4 +1,11 @@
chrisforbes@google.com
-cnorthrop@google.com
ianelliott@google.com
-lpy@google.com
+
+abdolrashidi@google.com
+cclao@google.com
+cnorthrop@google.com
+hibrian@google.com
+mathias@google.com
+romanl@google.com
+solti@google.com
+yuxinhu@google.com
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index 7f45581..72f29c6 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -141,7 +141,6 @@
std::string appPackageName = "";
int32_t vulkanVersion = 0;
Driver glDriverToLoad = Driver::NONE;
- Driver glDriverFallback = Driver::NONE;
Driver vkDriverToLoad = Driver::NONE;
Driver vkDriverFallback = Driver::NONE;
bool glDriverToSend = false;
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index f065ffa..3c1971f 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -22,11 +22,14 @@
#include <com_android_graphics_libgui_flags.h>
#include <cutils/atomic.h>
+#include <ftl/fake_guard.h>
#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
#include <gui/FrameRateUtils.h>
#include <gui/GLConsumer.h>
@@ -74,6 +77,12 @@
std::unique_lock _lock{mutex}; \
base::ScopedLockAssertion assumeLocked(mutex);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK =
+ [](const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/,
+ std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {};
+#endif
+
void BLASTBufferItemConsumer::onDisconnect() {
Mutex::Autolock lock(mMutex);
mPreviouslyConnected = mCurrentlyConnected;
@@ -215,6 +224,12 @@
},
this);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> bufferReleaseConsumer;
+ gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer);
+ mBufferReleaseReader = std::make_shared<BufferReleaseReader>(std::move(bufferReleaseConsumer));
+#endif
+
BQA_LOGV("BLASTBufferQueue created");
}
@@ -244,6 +259,9 @@
void BLASTBufferQueue::onFirstRef() {
// safe default, most producers are expected to override this
mProducer->setMaxDequeuedBufferCount(2);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ mBufferReleaseThread.start(sp<BLASTBufferQueue>::fromExisting(this));
+#endif
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
@@ -269,6 +287,9 @@
if (surfaceControlChanged) {
t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
layer_state_t::eEnableBackpressure);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer);
+#endif
applyTransaction = true;
}
mTransformHint = mSurfaceControl->getTransformHint();
@@ -306,14 +327,12 @@
return std::nullopt;
}
-static void transactionCommittedCallbackThunk(void* context, nsecs_t latchTime,
- const sp<Fence>& presentFence,
- const std::vector<SurfaceControlStats>& stats) {
- if (context == nullptr) {
- return;
- }
- sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context);
- bq->transactionCommittedCallback(latchTime, presentFence, stats);
+TransactionCompletedCallbackTakesContext BLASTBufferQueue::makeTransactionCommittedCallbackThunk() {
+ return [bbq = sp<BLASTBufferQueue>::fromExisting(
+ this)](void* /*context*/, nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ bbq->transactionCommittedCallback(latchTime, presentFence, stats);
+ };
}
void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/,
@@ -346,18 +365,15 @@
BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
"empty.");
}
- decStrong((void*)transactionCommittedCallbackThunk);
}
}
-static void transactionCallbackThunk(void* context, nsecs_t latchTime,
- const sp<Fence>& presentFence,
- const std::vector<SurfaceControlStats>& stats) {
- if (context == nullptr) {
- return;
- }
- sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context);
- bq->transactionCallback(latchTime, presentFence, stats);
+TransactionCompletedCallbackTakesContext BLASTBufferQueue::makeTransactionCallbackThunk() {
+ return [bbq = sp<BLASTBufferQueue>::fromExisting(
+ this)](void* /*context*/, nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ bbq->transactionCallback(latchTime, presentFence, stats);
+ };
}
void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
@@ -391,6 +407,7 @@
stat.latchTime,
stat.frameEventStats.dequeueReadyTime);
}
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
auto currFrameNumber = stat.frameEventStats.frameNumber;
std::vector<ReleaseCallbackId> staleReleases;
for (const auto& [key, value]: mSubmitted) {
@@ -406,6 +423,7 @@
stat.currentMaxAcquiredBufferCount,
true /* fakeRelease */);
}
+#endif
} else {
BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
}
@@ -413,23 +431,6 @@
BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
"empty.");
}
-
- decStrong((void*)transactionCallbackThunk);
- }
-}
-
-// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
-// BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client.
-// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
-// Otherwise, this is a no-op.
-static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const ReleaseCallbackId& id,
- const sp<Fence>& releaseFence,
- std::optional<uint32_t> currentMaxAcquiredBufferCount) {
- sp<BLASTBufferQueue> blastBufferQueue = context.promote();
- if (blastBufferQueue) {
- blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
- } else {
- ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str());
}
}
@@ -442,6 +443,23 @@
}
}
+// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
+// BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client.
+// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
+// Otherwise, this is a no-op.
+ReleaseBufferCallback BLASTBufferQueue::makeReleaseBufferCallbackThunk() {
+ return [weakBbq = wp<BLASTBufferQueue>::fromExisting(
+ this)](const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount) {
+ sp<BLASTBufferQueue> bbq = weakBbq.promote();
+ if (!bbq) {
+ ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str());
+ return;
+ }
+ bbq->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
+ };
+}
+
void BLASTBufferQueue::releaseBufferCallback(
const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount) {
@@ -509,13 +527,7 @@
callbackId.to_string().c_str());
return;
}
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- if (!it->second.disconnectedAfterAcquired) {
- mNumAcquired--;
- }
-#else
mNumAcquired--;
-#endif
BBQ_TRACE("frame=%" PRIu64, callbackId.framenumber);
BQA_LOGV("released %s", callbackId.to_string().c_str());
mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
@@ -566,7 +578,7 @@
applyTransaction = false;
}
- BLASTBufferItem bufferItem;
+ BufferItem bufferItem;
status_t status =
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
@@ -610,9 +622,6 @@
t->notifyProducerDisconnect(mSurfaceControl);
}
- // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
- incStrong((void*)transactionCallbackThunk);
-
// Only update mSize for destination bounds if the incoming buffer matches the requested size.
// Otherwise, it could cause stretching since the destination bounds will update before the
// buffer with the new size is acquired.
@@ -625,9 +634,12 @@
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
bufferItem.mScalingMode, crop);
- auto releaseBufferCallback =
- std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
- std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ ReleaseBufferCallback releaseBufferCallback =
+ applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk();
+#else
+ auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
+#endif
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
nsecs_t dequeueTime = -1;
@@ -645,7 +657,7 @@
t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
- t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
+ t->addTransactionCompletedCallback(makeTransactionCallbackThunk(), nullptr);
mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
@@ -777,9 +789,6 @@
}
// add to shadow queue
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- mNumDequeued--;
-#endif
mNumFrameAvailable++;
if (waitForTransactionCallback && mNumFrameAvailable >= 2) {
acquireAndReleaseBuffer();
@@ -805,9 +814,9 @@
// Only need a commit callback when syncing to ensure the buffer that's synced has been
// sent to SF
- incStrong((void*)transactionCommittedCallbackThunk);
- mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
- static_cast<void*>(this));
+ mSyncTransaction
+ ->addTransactionCommittedCallback(makeTransactionCommittedCallbackThunk(),
+ nullptr);
if (mAcquireSingleBuffer) {
prevCallback = mTransactionReadyCallback;
prevTransaction = mSyncTransaction;
@@ -834,17 +843,8 @@
};
void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) {
- {
- std::lock_guard _lock{mTimestampMutex};
- mDequeueTimestamps.erase(bufferId);
- }
-
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- {
- std::lock_guard lock{mMutex};
- mNumDequeued--;
- }
-#endif
+ std::lock_guard _lock{mTimestampMutex};
+ mDequeueTimestamps.erase(bufferId);
}
bool BLASTBufferQueue::syncNextTransaction(
@@ -1144,116 +1144,6 @@
producerControlledByApp, output);
}
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- status_t disconnect(int api, DisconnectMode mode) override {
- sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
- if (!bbq) {
- return BufferQueueProducer::disconnect(api, mode);
- }
-
- std::lock_guard lock{bbq->mMutex};
- if (status_t status = BufferQueueProducer::disconnect(api, mode); status != OK) {
- return status;
- }
-
- // We need to reset dequeued and acquired counts because BufferQueueProducer::disconnect
- // calls BufferQueueCore::freeAllBuffersLocked which frees all dequeued and acquired
- // buffers. We don't reset mNumFrameAvailable because these buffers are still available
- // in BufferItemConsumer.
- bbq->mNumDequeued = 0;
- bbq->mNumAcquired = 0;
- // SurfaceFlinger sends release callbacks for buffers that have been acquired after a
- // disconnect. We set disconnectedAfterAcquired to true so that we can ignore any stale
- // releases that come in after the producer is disconnected. Otherwise, releaseBuffer will
- // decrement mNumAcquired for a buffer that was acquired before we reset mNumAcquired to
- // zero.
- for (auto& [releaseId, bufferItem] : bbq->mSubmitted) {
- bufferItem.disconnectedAfterAcquired = true;
- }
-
- return OK;
- }
-
- status_t setAsyncMode(bool asyncMode) override {
- if (status_t status = BufferQueueProducer::setAsyncMode(asyncMode); status != OK) {
- return status;
- }
-
- sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
- if (!bbq) {
- return OK;
- }
-
- {
- std::lock_guard lock{bbq->mMutex};
- bbq->mAsyncMode = asyncMode;
- }
-
- return OK;
- }
-
- status_t setSharedBufferMode(bool sharedBufferMode) override {
- if (status_t status = BufferQueueProducer::setSharedBufferMode(sharedBufferMode);
- status != OK) {
- return status;
- }
-
- sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
- if (!bbq) {
- return OK;
- }
-
- {
- std::lock_guard lock{bbq->mMutex};
- bbq->mSharedBufferMode = sharedBufferMode;
- }
-
- return OK;
- }
-
- status_t detachBuffer(int slot) override {
- if (status_t status = BufferQueueProducer::detachBuffer(slot); status != OK) {
- return status;
- }
-
- sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
- if (!bbq) {
- return OK;
- }
-
- {
- std::lock_guard lock{bbq->mMutex};
- bbq->mNumDequeued--;
- }
-
- return OK;
- }
-
- status_t dequeueBuffer(int* outSlot, sp<Fence>* outFence, uint32_t width, uint32_t height,
- PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
- FrameEventHistoryDelta* outTimestamps) override {
- sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
- if (!bbq) {
- return BufferQueueProducer::dequeueBuffer(outSlot, outFence, width, height, format,
- usage, outBufferAge, outTimestamps);
- }
-
- {
- std::lock_guard lock{bbq->mMutex};
- bbq->mNumDequeued++;
- }
-
- status_t status =
- BufferQueueProducer::dequeueBuffer(outSlot, outFence, width, height, format, usage,
- outBufferAge, outTimestamps);
- if (status < 0) {
- std::lock_guard lock{bbq->mMutex};
- bbq->mNumDequeued--;
- }
- return status;
- }
-#endif
-
// We want to resize the frame history when changing the size of the buffer queue
status_t setMaxDequeuedBufferCount(int maxDequeuedBufferCount) override {
int maxBufferCount;
@@ -1276,13 +1166,6 @@
bbq->resizeFrameEventHistory(newFrameHistorySize);
}
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- {
- std::lock_guard lock{bbq->mMutex};
- bbq->mMaxDequeuedBuffers = maxDequeuedBufferCount;
- }
-#endif
-
return OK;
}
@@ -1369,7 +1252,120 @@
void BLASTBufferQueue::setTransactionHangCallback(
std::function<void(const std::string&)> callback) {
std::lock_guard _lock{mMutex};
- mTransactionHangCallback = callback;
+ mTransactionHangCallback = std::move(callback);
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+
+BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(
+ std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> endpoint)
+ : mEndpoint{std::move(endpoint)} {
+ mEpollFd = android::base::unique_fd{epoll_create1(0)};
+ LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(),
+ "Failed to create buffer release epoll file descriptor. errno=%d "
+ "message='%s'",
+ errno, strerror(errno));
+
+ epoll_event registerEndpointFd{};
+ registerEndpointFd.events = EPOLLIN;
+ registerEndpointFd.data.fd = mEndpoint->getFd();
+ status_t status =
+ epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), ®isterEndpointFd);
+ LOG_ALWAYS_FATAL_IF(status == -1,
+ "Failed to register buffer release consumer file descriptor with epoll. "
+ "errno=%d message='%s'",
+ errno, strerror(errno));
+
+ mEventFd = android::base::unique_fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+ LOG_ALWAYS_FATAL_IF(!mEventFd.ok(),
+ "Failed to create buffer release event file descriptor. errno=%d "
+ "message='%s'",
+ errno, strerror(errno));
+
+ epoll_event registerEventFd{};
+ registerEventFd.events = EPOLLIN;
+ registerEventFd.data.fd = mEventFd.get();
+ status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEventFd.get(), ®isterEventFd);
+ LOG_ALWAYS_FATAL_IF(status == -1,
+ "Failed to register buffer release event file descriptor with epoll. "
+ "errno=%d message='%s'",
+ errno, strerror(errno));
+}
+
+BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=(
+ BufferReleaseReader&& other) {
+ if (this != &other) {
+ ftl::FakeGuard guard{mMutex};
+ ftl::FakeGuard otherGuard{other.mMutex};
+ mEndpoint = std::move(other.mEndpoint);
+ mEpollFd = std::move(other.mEpollFd);
+ mEventFd = std::move(other.mEventFd);
+ }
+ return *this;
+}
+
+status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId,
+ sp<Fence>& outFence,
+ uint32_t& outMaxAcquiredBufferCount) {
+ epoll_event event{};
+ while (true) {
+ int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */);
+ if (eventCount == 1) {
+ break;
+ }
+ if (eventCount == -1 && errno != EINTR) {
+ ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno,
+ strerror(errno));
+ }
+ }
+
+ if (event.data.fd == mEventFd.get()) {
+ uint64_t value;
+ if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) {
+ ALOGE("error while reading from eventfd. errno=%d message='%s'", errno,
+ strerror(errno));
+ }
+ return WOULD_BLOCK;
+ }
+
+ std::lock_guard lock{mMutex};
+ return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount);
+}
+
+void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() {
+ uint64_t value = 1;
+ if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) {
+ ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno));
+ }
+}
+
+void BLASTBufferQueue::BufferReleaseThread::start(const sp<BLASTBufferQueue>& bbq) {
+ mRunning = std::make_shared<std::atomic_bool>(true);
+ mReader = bbq->mBufferReleaseReader;
+ std::thread([running = mRunning, reader = mReader, weakBbq = wp<BLASTBufferQueue>(bbq)]() {
+ pthread_setname_np(pthread_self(), "BufferReleaseThread");
+ while (*running) {
+ ReleaseCallbackId id;
+ sp<Fence> fence;
+ uint32_t maxAcquiredBufferCount;
+ if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount);
+ status != OK) {
+ continue;
+ }
+ sp<BLASTBufferQueue> bbq = weakBbq.promote();
+ if (!bbq) {
+ return;
+ }
+ bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount);
+ }
+ }).detach();
+}
+
+BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() {
+ *mRunning = false;
+ mReader->interruptBlockingRead();
+}
+
+#endif
+
} // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index da3886c..66e7ddd 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -77,9 +77,28 @@
} // namespace
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+Surface::ProducerDeathListenerProxy::ProducerDeathListenerProxy(wp<SurfaceListener> surfaceListener)
+ : mSurfaceListener(surfaceListener) {}
+
+void Surface::ProducerDeathListenerProxy::binderDied(const wp<IBinder>&) {
+ sp<SurfaceListener> surfaceListener = mSurfaceListener.promote();
+ if (!surfaceListener) {
+ return;
+ }
+
+ if (surfaceListener->needsDeathNotify()) {
+ surfaceListener->onRemoteDied();
+ }
+}
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
const sp<IBinder>& surfaceControlHandle)
: mGraphicBufferProducer(bufferProducer),
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ mSurfaceDeathListener(nullptr),
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
mCrop(Rect::EMPTY_RECT),
mBufferAge(0),
mGenerationNumber(0),
@@ -134,6 +153,12 @@
if (mConnectedToCpu) {
Surface::disconnect(NATIVE_WINDOW_API_CPU);
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ if (mSurfaceDeathListener != nullptr) {
+ IInterface::asBinder(mGraphicBufferProducer)->unlinkToDeath(mSurfaceDeathListener);
+ mSurfaceDeathListener = nullptr;
+ }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
}
sp<ISurfaceComposer> Surface::composerService() const {
@@ -716,11 +741,12 @@
return res;
}
-status_t Surface::queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd) {
+status_t Surface::queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd,
+ SurfaceQueueBufferOutput* output) {
if (buffer == nullptr) {
return BAD_VALUE;
}
- return queueBuffer(buffer.get(), fd ? fd->get() : -1);
+ return queueBuffer(buffer.get(), fd ? fd->get() : -1, output);
}
status_t Surface::detachBuffer(const sp<GraphicBuffer>& buffer) {
@@ -1170,7 +1196,8 @@
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
-int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
+int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd,
+ SurfaceQueueBufferOutput* surfaceOutput) {
ATRACE_CALL();
ALOGV("Surface::queueBuffer");
@@ -1220,16 +1247,26 @@
onBufferQueuedLocked(slot, fence, output);
}
+ if (surfaceOutput != nullptr) {
+ *surfaceOutput = {.bufferReplaced = output.bufferReplaced};
+ }
+
return err;
}
-int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers,
+ std::vector<SurfaceQueueBufferOutput>* queueBufferOutputs)
+#else
+int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers)
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+{
ATRACE_CALL();
ALOGV("Surface::queueBuffers");
size_t numBuffers = buffers.size();
- std::vector<IGraphicBufferProducer::QueueBufferInput> queueBufferInputs(numBuffers);
- std::vector<IGraphicBufferProducer::QueueBufferOutput> queueBufferOutputs;
+ std::vector<IGraphicBufferProducer::QueueBufferInput> igbpQueueBufferInputs(numBuffers);
+ std::vector<IGraphicBufferProducer::QueueBufferOutput> igbpQueueBufferOutputs;
std::vector<int> bufferSlots(numBuffers, -1);
std::vector<sp<Fence>> bufferFences(numBuffers);
@@ -1255,12 +1292,13 @@
IGraphicBufferProducer::QueueBufferInput input;
getQueueBufferInputLocked(buffers[batchIdx].buffer, buffers[batchIdx].fenceFd,
buffers[batchIdx].timestamp, &input);
+ input.slot = i;
bufferFences[batchIdx] = input.fence;
- queueBufferInputs[batchIdx] = input;
+ igbpQueueBufferInputs[batchIdx] = input;
}
}
nsecs_t now = systemTime();
- err = mGraphicBufferProducer->queueBuffers(queueBufferInputs, &queueBufferOutputs);
+ err = mGraphicBufferProducer->queueBuffers(igbpQueueBufferInputs, &igbpQueueBufferOutputs);
{
Mutex::Autolock lock(mMutex);
mLastQueueDuration = systemTime() - now;
@@ -1270,10 +1308,21 @@
for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) {
onBufferQueuedLocked(bufferSlots[batchIdx], bufferFences[batchIdx],
- queueBufferOutputs[batchIdx]);
+ igbpQueueBufferOutputs[batchIdx]);
}
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ if (queueBufferOutputs != nullptr) {
+ queueBufferOutputs->clear();
+ queueBufferOutputs->resize(numBuffers);
+ for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) {
+ (*queueBufferOutputs)[batchIdx].bufferReplaced =
+ igbpQueueBufferOutputs[batchIdx].bufferReplaced;
+ }
+ }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
return err;
}
@@ -2033,6 +2082,7 @@
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput output;
mReportRemovedBuffers = reportBufferRemoval;
+
if (listener != nullptr) {
mListenerProxy = new ProducerListenerProxy(this, listener);
}
@@ -2053,6 +2103,13 @@
}
mConsumerRunningBehind = (output.numPendingBuffers >= 2);
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ if (listener && listener->needsDeathNotify()) {
+ mSurfaceDeathListener = sp<ProducerDeathListenerProxy>::make(listener);
+ IInterface::asBinder(mGraphicBufferProducer)->linkToDeath(mSurfaceDeathListener);
+ }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
}
if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = true;
@@ -2093,6 +2150,14 @@
mConnectedToCpu = false;
}
}
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ if (mSurfaceDeathListener != nullptr) {
+ IInterface::asBinder(mGraphicBufferProducer)->unlinkToDeath(mSurfaceDeathListener);
+ mSurfaceDeathListener = nullptr;
+ }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
return err;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7d3e5c1..df58df4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2051,8 +2051,9 @@
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext,
CallbackId::Type callbackType) {
- auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3);
+ auto callbackWithContext =
+ std::bind(std::move(callback), callbackContext, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3);
const auto& surfaceControls = mListenerCallbacks[mTransactionCompletedListener].surfaceControls;
CallbackId callbackId =
@@ -2066,13 +2067,15 @@
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
- return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMPLETE);
+ return addTransactionCallback(std::move(callback), callbackContext,
+ CallbackId::Type::ON_COMPLETE);
}
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCommittedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
- return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMMIT);
+ return addTransactionCallback(std::move(callback), callbackContext,
+ CallbackId::Type::ON_COMMIT);
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect(
diff --git a/libs/gui/aidl/android/gui/JankData.aidl b/libs/gui/aidl/android/gui/JankData.aidl
index 7ea9d22..ec13681 100644
--- a/libs/gui/aidl/android/gui/JankData.aidl
+++ b/libs/gui/aidl/android/gui/JankData.aidl
@@ -29,7 +29,17 @@
int jankType;
/**
- * Expected duration in nanoseconds of this frame.
+ * Time between frames in nanoseconds.
*/
long frameIntervalNs;
+
+ /**
+ * Time allocated to the application to render this frame.
+ */
+ long scheduledAppFrameTimeNs;
+
+ /**
+ * Time taken by the application to render this frame.
+ */
+ long actualAppFrameTimeNs;
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index c2dcd25..d787d6c 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -103,15 +103,21 @@
void onFrameDequeued(const uint64_t) override;
void onFrameCancelled(const uint64_t) override;
+ TransactionCompletedCallbackTakesContext makeTransactionCommittedCallbackThunk();
void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats);
+
+ TransactionCompletedCallbackTakesContext makeTransactionCallbackThunk();
virtual void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats);
+
+ ReleaseBufferCallback makeReleaseBufferCallbackThunk();
void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount);
void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount,
bool fakeRelease) REQUIRES(mMutex);
+
bool syncNextTransaction(std::function<void(SurfaceComposerClient::Transaction*)> callback,
bool acquireSingleBuffer = true);
void stopContinuousSyncTransaction();
@@ -181,15 +187,6 @@
// BufferQueue internally allows 1 more than
// the max to be acquired
int32_t mMaxAcquiredBuffers GUARDED_BY(mMutex) = 1;
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- int32_t mMaxDequeuedBuffers GUARDED_BY(mMutex) = 1;
- static constexpr int32_t kMaxBufferCount = BufferQueueDefs::NUM_BUFFER_SLOTS;
-
- bool mAsyncMode GUARDED_BY(mMutex) = false;
- bool mSharedBufferMode GUARDED_BY(mMutex) = false;
-
- int32_t mNumDequeued GUARDED_BY(mMutex) = 0;
-#endif
int32_t mNumFrameAvailable GUARDED_BY(mMutex) = 0;
int32_t mNumAcquired GUARDED_BY(mMutex) = 0;
@@ -198,16 +195,9 @@
// latch stale buffers and that we don't wait on barriers from an old producer.
uint32_t mProducerId = 0;
- class BLASTBufferItem : public BufferItem {
- public:
- // True if BBQBufferQueueProducer is disconnected after the buffer is acquried but
- // before it is released.
- bool disconnectedAfterAcquired{false};
- };
-
// Keep a reference to the submitted buffers so we can release when surfaceflinger drops the
// buffer or the buffer has been presented and a new buffer is ready to be presented.
- std::unordered_map<ReleaseCallbackId, BLASTBufferItem, ReleaseBufferCallbackIdHash> mSubmitted
+ std::unordered_map<ReleaseCallbackId, BufferItem, ReleaseBufferCallbackIdHash> mSubmitted
GUARDED_BY(mMutex);
// Keep a queue of the released buffers instead of immediately releasing
@@ -325,6 +315,51 @@
std::function<void(const std::string&)> mTransactionHangCallback;
std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex);
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ class BufferReleaseReader {
+ public:
+ BufferReleaseReader() = default;
+ BufferReleaseReader(std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint>);
+ BufferReleaseReader& operator=(BufferReleaseReader&&);
+
+ // Block until we can read a buffer release message.
+ //
+ // Returns:
+ // * OK if a ReleaseCallbackId and Fence were successfully read.
+ // * WOULD_BLOCK if the blocking read was interrupted by interruptBlockingRead.
+ // * UNKNOWN_ERROR if something went wrong.
+ status_t readBlocking(ReleaseCallbackId& outId, sp<Fence>& outReleaseFence,
+ uint32_t& outMaxAcquiredBufferCount);
+
+ // Signals the reader's eventfd to wake up any threads waiting on readBlocking.
+ void interruptBlockingRead();
+
+ private:
+ std::mutex mMutex;
+ std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mEndpoint GUARDED_BY(mMutex);
+ android::base::unique_fd mEpollFd;
+ android::base::unique_fd mEventFd;
+ };
+
+ // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to
+ // the client. See BBQBufferQueueProducer::dequeueBuffer for details.
+ std::shared_ptr<BufferReleaseReader> mBufferReleaseReader;
+ std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer;
+
+ class BufferReleaseThread {
+ public:
+ BufferReleaseThread() = default;
+ ~BufferReleaseThread();
+ void start(const sp<BLASTBufferQueue>&);
+
+ private:
+ std::shared_ptr<std::atomic_bool> mRunning;
+ std::shared_ptr<BufferReleaseReader> mReader;
+ };
+
+ BufferReleaseThread mBufferReleaseThread;
+#endif
};
} // namespace android
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 0f51f2d..e74f9ad 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -66,6 +66,16 @@
virtual void onBufferAttached() {}
virtual bool needsAttachNotify() { return false; }
#endif
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ // Called if this Surface is connected to a remote implementation and it
+ // dies or becomes unavailable.
+ virtual void onRemoteDied() {}
+
+ // Clients will overwrite this if they want to receive a notification
+ // via onRemoteDied. This should return a constant value.
+ virtual bool needsDeathNotify() { return false; }
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
};
class StubSurfaceListener : public SurfaceListener {
@@ -77,6 +87,15 @@
virtual void onBufferDetached(int /*slot*/) override {}
};
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+// Contains additional data from the queueBuffer operation.
+struct SurfaceQueueBufferOutput {
+ // True if this queueBuffer caused a buffer to be replaced in the queue
+ // (and therefore not will not be acquired)
+ bool bufferReplaced = false;
+};
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
/*
* An implementation of ANativeWindow that feeds graphics buffers into a
* BufferQueue.
@@ -353,7 +372,12 @@
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd,
+ SurfaceQueueBufferOutput* surfaceOutput = nullptr);
+#else
virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
virtual int perform(int operation, va_list args);
virtual int setSwapInterval(int interval);
@@ -412,7 +436,8 @@
// Queues a buffer, with an optional fd fence that captures pending work on the buffer. This
// buffer must have been returned by dequeueBuffer or associated with this Surface via an
// attachBuffer operation.
- status_t queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd = Fence::NO_FENCE);
+ status_t queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd = Fence::NO_FENCE,
+ SurfaceQueueBufferOutput* output = nullptr);
// Detaches this buffer, dissociating it from this Surface. This buffer must have been returned
// by queueBuffer or associated with this Surface via an attachBuffer operation.
@@ -433,8 +458,13 @@
int fenceFd = -1;
nsecs_t timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
};
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ virtual int queueBuffers(const std::vector<BatchQueuedBuffer>& buffers,
+ std::vector<SurfaceQueueBufferOutput>* queueBufferOutputs = nullptr);
+#else
virtual int queueBuffers(
const std::vector<BatchQueuedBuffer>& buffers);
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
protected:
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
@@ -471,6 +501,21 @@
sp<SurfaceListener> mSurfaceListener;
};
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ class ProducerDeathListenerProxy : public IBinder::DeathRecipient {
+ public:
+ ProducerDeathListenerProxy(wp<SurfaceListener> surfaceListener);
+ ProducerDeathListenerProxy(ProducerDeathListenerProxy&) = delete;
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>&) override;
+
+ private:
+ wp<SurfaceListener> mSurfaceListener;
+ };
+ friend class ProducerDeathListenerProxy;
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
void querySupportedTimestampsLocked() const;
void freeAllBuffers();
@@ -502,6 +547,13 @@
// TODO: rename to mBufferProducer
sp<IGraphicBufferProducer> mGraphicBufferProducer;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+ // mSurfaceDeathListener gets registered as mGraphicBufferProducer's
+ // DeathRecipient when SurfaceListener::needsDeathNotify returns true and
+ // gets notified when it dies.
+ sp<ProducerDeathListenerProxy> mSurfaceDeathListener;
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
+
// mSlots stores the buffers that have been allocated for each buffer slot.
// It is initialized to null pointers, and gets filled in with the result of
// IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index c367e75..df9b73b 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -91,3 +91,19 @@
bug: "342197847"
is_fixed_read_only: true
} # wb_ring_buffer
+
+flag {
+ name: "wb_camera3_and_processors"
+ namespace: "core_graphics"
+ description: "Remove usage of IGBPs in the *Processor and Camera3*"
+ bug: "342199002"
+ is_fixed_read_only: true
+} # wb_camera3_and_processors
+
+flag {
+ name: "wb_libcameraservice"
+ namespace: "core_graphics"
+ description: "Remove usage of IGBPs in the libcameraservice."
+ bug: "342197849"
+ is_fixed_read_only: true
+} # wb_libcameraservice
\ No newline at end of file
diff --git a/libs/gui/tests/Choreographer_test.cpp b/libs/gui/tests/Choreographer_test.cpp
index 2ac2550..8db48d2 100644
--- a/libs/gui/tests/Choreographer_test.cpp
+++ b/libs/gui/tests/Choreographer_test.cpp
@@ -52,25 +52,23 @@
sp<Looper> looper = Looper::prepare(0);
Choreographer* choreographer = Choreographer::getForThread();
VsyncCallback animationCb;
- VsyncCallback inputCb;
-
choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0,
CALLBACK_ANIMATION);
+ VsyncCallback inputCb;
choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &inputCb, 0,
CALLBACK_INPUT);
-
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
- nsecs_t currTime;
- int pollResult;
+ auto startTime = std::chrono::system_clock::now();
do {
- pollResult = looper->pollOnce(16);
- currTime = systemTime(SYSTEM_TIME_MONOTONIC);
- } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()) &&
- (pollResult != Looper::POLL_TIMEOUT && pollResult != Looper::POLL_ERROR) &&
- (currTime - startTime < 3000));
-
- ASSERT_TRUE(inputCb.callbackReceived()) << "did not receive input callback";
- ASSERT_TRUE(animationCb.callbackReceived()) << "did not receive animation callback";
+ static constexpr int32_t timeoutMs = 1000;
+ int pollResult = looper->pollOnce(timeoutMs);
+ ASSERT_TRUE((pollResult != Looper::POLL_TIMEOUT) && (pollResult != Looper::POLL_ERROR))
+ << "Failed to poll looper. Poll result = " << pollResult;
+ auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::system_clock::now() - startTime);
+ ASSERT_LE(elapsedMs.count(), timeoutMs)
+ << "Timed out waiting for callbacks. inputCb=" << inputCb.callbackReceived()
+ << " animationCb=" << animationCb.callbackReceived();
+ } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()));
ASSERT_EQ(inputCb.frameTime, animationCb.frameTime)
<< android::base::StringPrintf("input and animation callback frame times don't match. "
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ab09dfc..88893b6 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -50,7 +50,10 @@
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <chrono>
#include <cstddef>
+#include <cstdint>
+#include <future>
#include <limits>
#include <thread>
@@ -108,6 +111,18 @@
std::vector<sp<GraphicBuffer>> mDiscardedBuffers;
};
+class DeathWatcherListener : public StubSurfaceListener {
+public:
+ virtual void onRemoteDied() { mDiedPromise.set_value(true); }
+
+ virtual bool needsDeathNotify() { return true; }
+
+ std::future<bool> getDiedFuture() { return mDiedPromise.get_future(); }
+
+private:
+ std::promise<bool> mDiedPromise;
+};
+
class SurfaceTest : public ::testing::Test {
protected:
SurfaceTest() {
@@ -2374,6 +2389,134 @@
surface.name = String16("name");
EXPECT_EQ("name", surface.toString());
}
+
+TEST_F(SurfaceTest, TestRemoteSurfaceDied_CallbackCalled) {
+ sp<TestServerClient> testServer = TestServerClient::Create();
+ sp<IGraphicBufferProducer> producer = testServer->CreateProducer();
+ EXPECT_NE(nullptr, producer);
+
+ sp<Surface> surface = sp<Surface>::make(producer);
+ sp<DeathWatcherListener> deathWatcher = sp<DeathWatcherListener>::make();
+ EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, deathWatcher));
+
+ auto diedFuture = deathWatcher->getDiedFuture();
+ EXPECT_EQ(OK, testServer->Kill());
+
+ diedFuture.wait();
+ EXPECT_TRUE(diedFuture.get());
+}
+
+TEST_F(SurfaceTest, TestRemoteSurfaceDied_Disconnect_CallbackNotCalled) {
+ sp<TestServerClient> testServer = TestServerClient::Create();
+ sp<IGraphicBufferProducer> producer = testServer->CreateProducer();
+ EXPECT_NE(nullptr, producer);
+
+ sp<Surface> surface = sp<Surface>::make(producer);
+ sp<DeathWatcherListener> deathWatcher = sp<DeathWatcherListener>::make();
+ EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, deathWatcher));
+ EXPECT_EQ(OK, surface->disconnect(NATIVE_WINDOW_API_CPU));
+
+ auto watcherDiedFuture = deathWatcher->getDiedFuture();
+ EXPECT_EQ(OK, testServer->Kill());
+
+ std::future_status status = watcherDiedFuture.wait_for(std::chrono::seconds(1));
+ EXPECT_EQ(std::future_status::timeout, status);
+}
+
+TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements) {
+ sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(GRALLOC_USAGE_SW_READ_OFTEN);
+ ASSERT_EQ(OK, consumer->setMaxBufferCount(3));
+ ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(1));
+
+ sp<Surface> surface = consumer->getSurface();
+ sp<StubSurfaceListener> listener = sp<StubSurfaceListener>::make();
+
+ // Async mode sets up an extra buffer so the surface can queue it without waiting.
+ ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(1));
+ ASSERT_EQ(OK, surface->setAsyncMode(true));
+ ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener));
+
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ SurfaceQueueBufferOutput output;
+ BufferItem item;
+
+ // We can queue directly, without an output arg.
+ EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence));
+ EXPECT_EQ(OK, surface->queueBuffer(buffer, fence));
+ EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0));
+ EXPECT_EQ(OK, consumer->releaseBuffer(item));
+
+ // We can queue with an output arg, and that we don't expect to see a replacement.
+ EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence));
+ EXPECT_EQ(OK, surface->queueBuffer(buffer, fence, &output));
+ EXPECT_FALSE(output.bufferReplaced);
+
+ // We expect see a replacement when we queue a second buffer in async mode, and the consumer
+ // hasn't acquired the first one yet.
+ EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence));
+ EXPECT_EQ(OK, surface->queueBuffer(buffer, fence, &output));
+ EXPECT_TRUE(output.bufferReplaced);
+}
+
+TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements_Plural) {
+ sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(GRALLOC_USAGE_SW_READ_OFTEN);
+ ASSERT_EQ(OK, consumer->setMaxBufferCount(4));
+ ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(1));
+
+ sp<Surface> surface = consumer->getSurface();
+ consumer->setName(String8("TRPTest"));
+ sp<StubSurfaceListener> listener = sp<StubSurfaceListener>::make();
+
+ // Async mode sets up an extra buffer so the surface can queue it without waiting.
+ ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(2));
+ ASSERT_EQ(OK, surface->setAsyncMode(true));
+ ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener));
+
+ // dequeueBuffers requires a vector of a certain size:
+ std::vector<Surface::BatchBuffer> buffers(2);
+ std::vector<Surface::BatchQueuedBuffer> queuedBuffers;
+ std::vector<SurfaceQueueBufferOutput> outputs;
+ BufferItem item;
+
+ auto moveBuffersToQueuedBuffers = [&]() {
+ EXPECT_EQ(2u, buffers.size());
+ EXPECT_NE(nullptr, buffers[0].buffer);
+ EXPECT_NE(nullptr, buffers[1].buffer);
+
+ queuedBuffers.clear();
+ for (auto& buffer : buffers) {
+ auto& queuedBuffer = queuedBuffers.emplace_back();
+ queuedBuffer.buffer = buffer.buffer;
+ queuedBuffer.fenceFd = buffer.fenceFd;
+ queuedBuffer.timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+ }
+ buffers = {{}, {}};
+ };
+
+ // We can queue directly, without an output arg.
+ EXPECT_EQ(OK, surface->dequeueBuffers(&buffers));
+ moveBuffersToQueuedBuffers();
+ EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers));
+ EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0));
+ EXPECT_EQ(OK, consumer->releaseBuffer(item));
+
+ // We can queue with an output arg. Only the second one should be replaced.
+ EXPECT_EQ(OK, surface->dequeueBuffers(&buffers));
+ moveBuffersToQueuedBuffers();
+ EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs));
+ EXPECT_EQ(2u, outputs.size());
+ EXPECT_FALSE(outputs[0].bufferReplaced);
+ EXPECT_TRUE(outputs[1].bufferReplaced);
+
+ // Since we haven't acquired anything, both queued buffers will replace the original one.
+ EXPECT_EQ(OK, surface->dequeueBuffers(&buffers));
+ moveBuffersToQueuedBuffers();
+ EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs));
+ EXPECT_EQ(2u, outputs.size());
+ EXPECT_TRUE(outputs[0].bufferReplaced);
+ EXPECT_TRUE(outputs[1].bufferReplaced);
+}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
} // namespace android
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index 99ffa68..eb41918 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "InputTransport"
+#define LOG_TAG "InputConsumerNoResampling"
#define ATRACE_TAG ATRACE_TAG_INPUT
#include <chrono>
@@ -33,8 +33,6 @@
#include <input/PrintTools.h>
#include <input/TraceTools.h>
-namespace input_flags = com::android::input::flags;
-
namespace android {
namespace {
@@ -46,6 +44,27 @@
const bool DEBUG_TRANSPORT_CONSUMER =
__android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO);
+/**
+ * RealLooper is a wrapper of Looper. All the member functions exclusively call the internal looper.
+ * This class' behavior is the same as Looper.
+ */
+class RealLooper final : public LooperInterface {
+public:
+ RealLooper(sp<Looper> looper) : mLooper{looper} {}
+
+ int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+ void* data) override {
+ return mLooper->addFd(fd, ident, events, callback, data);
+ }
+
+ int removeFd(int fd) override { return mLooper->removeFd(fd); }
+
+ sp<Looper> getLooper() const override { return mLooper; }
+
+private:
+ sp<Looper> mLooper;
+};
+
std::unique_ptr<KeyEvent> createKeyEvent(const InputMessage& msg) {
std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>();
event->initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source,
@@ -173,22 +192,20 @@
bool isPointerEvent(const MotionEvent& motionEvent) {
return (motionEvent.getSource() & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
}
-
} // namespace
using android::base::Result;
-using android::base::StringPrintf;
// --- InputConsumerNoResampling ---
InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- sp<Looper> looper,
+ std::shared_ptr<LooperInterface> looper,
InputConsumerCallbacks& callbacks,
std::unique_ptr<Resampler> resampler)
- : mChannel(channel),
- mLooper(looper),
+ : mChannel{channel},
+ mLooper{looper},
mCallbacks(callbacks),
- mResampler(std::move(resampler)),
+ mResampler{std::move(resampler)},
mFdEvents(0) {
LOG_ALWAYS_FATAL_IF(mLooper == nullptr);
mCallback = sp<LooperEventCallback>::make(
@@ -199,6 +216,13 @@
setFdEvents(ALOOPER_EVENT_INPUT);
}
+InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
+ sp<Looper> looper,
+ InputConsumerCallbacks& callbacks,
+ std::unique_ptr<Resampler> resampler)
+ : InputConsumerNoResampling(channel, std::make_shared<RealLooper>(looper), callbacks,
+ std::move(resampler)) {}
+
InputConsumerNoResampling::~InputConsumerNoResampling() {
ensureCalledOnLooperThread(__func__);
consumeBatchedInputEvents(std::nullopt);
@@ -513,7 +537,7 @@
void InputConsumerNoResampling::ensureCalledOnLooperThread(const char* func) const {
sp<Looper> callingThreadLooper = Looper::getForThread();
- if (callingThreadLooper != mLooper) {
+ if (callingThreadLooper != mLooper->getLooper()) {
LOG(FATAL) << "The function " << func << " can only be called on the looper thread";
}
}
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 9333ab8..c903031 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -20,6 +20,7 @@
#include <unistd.h>
#include <ctype.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <ftl/enum.h>
@@ -31,6 +32,9 @@
namespace android {
+// Set to true to log detailed debugging messages about IDC file probing.
+static constexpr bool DEBUG_PROBE = false;
+
static const char* CONFIGURATION_FILE_DIR[] = {
"idc/",
"keylayout/",
@@ -114,15 +118,18 @@
for (const auto& prefix : pathPrefixes) {
path = prefix;
appendInputDeviceConfigurationFileRelativePath(path, name, type);
-#if DEBUG_PROBE
- ALOGD("Probing for system provided input device configuration file: path='%s'",
- path.c_str());
-#endif
if (!access(path.c_str(), R_OK)) {
-#if DEBUG_PROBE
- ALOGD("Found");
-#endif
+ LOG_IF(INFO, DEBUG_PROBE)
+ << "Found system-provided input device configuration file at " << path;
return path;
+ } else if (errno != ENOENT) {
+ LOG(WARNING) << "Couldn't find a system-provided input device configuration file at "
+ << path << " due to error " << errno << " (" << strerror(errno)
+ << "); there may be an IDC file there that cannot be loaded.";
+ } else {
+ LOG_IF(ERROR, DEBUG_PROBE)
+ << "Didn't find system-provided input device configuration file at " << path
+ << ": " << strerror(errno);
}
}
@@ -135,21 +142,22 @@
}
path += "/system/devices/";
appendInputDeviceConfigurationFileRelativePath(path, name, type);
-#if DEBUG_PROBE
- ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
-#endif
if (!access(path.c_str(), R_OK)) {
-#if DEBUG_PROBE
- ALOGD("Found");
-#endif
+ LOG_IF(INFO, DEBUG_PROBE) << "Found system user input device configuration file at "
+ << path;
return path;
+ } else if (errno != ENOENT) {
+ LOG(WARNING) << "Couldn't find a system user input device configuration file at " << path
+ << " due to error " << errno << " (" << strerror(errno)
+ << "); there may be an IDC file there that cannot be loaded.";
+ } else {
+ LOG_IF(ERROR, DEBUG_PROBE) << "Didn't find system user input device configuration file at "
+ << path << ": " << strerror(errno);
}
// Not found.
-#if DEBUG_PROBE
- ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
- name.c_str(), type);
-#endif
+ LOG_IF(INFO, DEBUG_PROBE) << "Probe failed to find input device configuration file with name '"
+ << name << "' and type " << ftl::enum_string(type);
return "";
}
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 500f7b4..f1c4aed 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -164,3 +164,31 @@
description: "Show touch and pointer indicators when mirroring a single task"
bug: "310179437"
}
+
+flag {
+ name: "include_relative_axis_values_for_captured_touchpads"
+ namespace: "input"
+ description: "Include AXIS_RELATIVE_X and AXIS_RELATIVE_Y values when reporting touches from captured touchpads."
+ bug: "330522990"
+}
+
+flag {
+ name: "enable_per_device_input_latency_metrics"
+ namespace: "input"
+ description: "Capture input latency metrics on a per device granular level using histograms."
+ bug: "270049345"
+}
+
+flag {
+ name: "collect_palm_rejection_quality_metrics"
+ namespace: "input"
+ description: "Collect quality metrics on framework palm rejection."
+ bug: "341717757"
+}
+
+flag {
+ name: "enable_touchpad_no_focus_change"
+ namespace: "input"
+ description: "Prevents touchpad gesture changing window focus."
+ bug: "364460018"
+}
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 008f675..4f4ea85 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -24,12 +24,14 @@
pub use data_store::{DataStore, DefaultFileReaderWriter};
pub use input::{
- DeviceClass, DeviceId, InputDevice, ModifierState, MotionAction, MotionFlags, Source,
+ DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionFlags,
+ Source,
};
pub use input_verifier::InputVerifier;
pub use keyboard_classifier::KeyboardClassifier;
#[cxx::bridge(namespace = "android::input")]
+#[allow(clippy::needless_maybe_sized)]
#[allow(unsafe_op_in_unsafe_fn)]
mod ffi {
#[namespace = "android"]
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 132866b..43bc894 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -16,6 +16,7 @@
"BlockingQueue_test.cpp",
"IdGenerator_test.cpp",
"InputChannel_test.cpp",
+ "InputConsumer_test.cpp",
"InputDevice_test.cpp",
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
@@ -25,6 +26,8 @@
"MotionPredictorMetricsManager_test.cpp",
"Resampler_test.cpp",
"RingBuffer_test.cpp",
+ "TestInputChannel.cpp",
+ "TestLooper.cpp",
"TfLiteMotionPredictor_test.cpp",
"TouchResampling_test.cpp",
"TouchVideoFrame_test.cpp",
diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp
new file mode 100644
index 0000000..c30f243
--- /dev/null
+++ b/libs/input/tests/InputConsumer_test.cpp
@@ -0,0 +1,123 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/InputConsumerNoResampling.h>
+
+#include <memory>
+#include <optional>
+#include <utility>
+
+#include <TestInputChannel.h>
+#include <TestLooper.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <input/BlockingQueue.h>
+#include <input/InputEventBuilders.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class InputConsumerTest : public testing::Test, public InputConsumerCallbacks {
+protected:
+ InputConsumerTest()
+ : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
+ mTestLooper{std::make_shared<TestLooper>()} {
+ Looper::setForThread(mTestLooper->getLooper());
+ mConsumer = std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper,
+ *this, /*resampler=*/nullptr);
+ }
+
+ void assertOnBatchedInputEventPendingWasCalled();
+
+ std::shared_ptr<TestInputChannel> mClientTestChannel;
+ std::shared_ptr<TestLooper> mTestLooper;
+ std::unique_ptr<InputConsumerNoResampling> mConsumer;
+
+ BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents;
+ BlockingQueue<std::unique_ptr<MotionEvent>> mMotionEvents;
+ BlockingQueue<std::unique_ptr<FocusEvent>> mFocusEvents;
+ BlockingQueue<std::unique_ptr<CaptureEvent>> mCaptureEvents;
+ BlockingQueue<std::unique_ptr<DragEvent>> mDragEvents;
+ BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
+
+private:
+ size_t onBatchedInputEventPendingInvocationCount{0};
+
+ // InputConsumerCallbacks interface
+ void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
+ mKeyEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ }
+ void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override {
+ mMotionEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ }
+ void onBatchedInputEventPending(int32_t pendingBatchSource) override {
+ if (!mConsumer->probablyHasInput()) {
+ ADD_FAILURE() << "should deterministically have input because there is a batch";
+ }
+ ++onBatchedInputEventPendingInvocationCount;
+ };
+ void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
+ mFocusEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ };
+ void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) override {
+ mCaptureEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ };
+ void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) override {
+ mDragEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ }
+ void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) override {
+ mTouchModeEvents.push(std::move(event));
+ mConsumer->finishInputEvent(seq, true);
+ };
+};
+
+void InputConsumerTest::assertOnBatchedInputEventPendingWasCalled() {
+ ASSERT_GT(onBatchedInputEventPendingInvocationCount, 0UL)
+ << "onBatchedInputEventPending has not been called.";
+ --onBatchedInputEventPendingInvocationCount;
+}
+
+TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {
+ mClientTestChannel->enqueueMessage(
+ InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}.build());
+ mClientTestChannel->enqueueMessage(
+ InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}.build());
+ mClientTestChannel->enqueueMessage(
+ InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}.build());
+
+ mClientTestChannel->assertNoSentMessages();
+
+ mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT);
+
+ assertOnBatchedInputEventPendingWasCalled();
+
+ mConsumer->consumeBatchedInputEvents(std::nullopt);
+
+ std::unique_ptr<MotionEvent> batchedMotionEvent = mMotionEvents.pop();
+ ASSERT_NE(batchedMotionEvent, nullptr);
+
+ mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+
+ EXPECT_EQ(batchedMotionEvent->getHistorySize() + 1, 3UL);
+}
+} // namespace android
diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp
index b372c0b..7ae9a28 100644
--- a/libs/input/tests/Resampler_test.cpp
+++ b/libs/input/tests/Resampler_test.cpp
@@ -70,22 +70,18 @@
};
InputSample::operator InputMessage() const {
- InputMessage message;
- message.header.type = InputMessage::Type::MOTION;
- message.body.motion.pointerCount = pointers.size();
- message.body.motion.eventTime = static_cast<std::chrono::nanoseconds>(eventTime).count();
- message.body.motion.source = AINPUT_SOURCE_CLASS_POINTER;
- message.body.motion.downTime = 0;
+ InputMessageBuilder messageBuilder =
+ InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}
+ .eventTime(std::chrono::nanoseconds{eventTime}.count())
+ .source(AINPUT_SOURCE_TOUCHSCREEN)
+ .downTime(0);
- const uint32_t pointerCount = message.body.motion.pointerCount;
- for (uint32_t i = 0; i < pointerCount; ++i) {
- message.body.motion.pointers[i].properties.id = pointers[i].id;
- message.body.motion.pointers[i].properties.toolType = pointers[i].toolType;
- message.body.motion.pointers[i].coords.setAxisValue(AMOTION_EVENT_AXIS_X, pointers[i].x);
- message.body.motion.pointers[i].coords.setAxisValue(AMOTION_EVENT_AXIS_Y, pointers[i].y);
- message.body.motion.pointers[i].coords.isResampled = pointers[i].isResampled;
+ for (const Pointer& pointer : pointers) {
+ messageBuilder.pointer(
+ PointerBuilder{pointer.id, pointer.toolType}.x(pointer.x).y(pointer.y).isResampled(
+ pointer.isResampled));
}
- return message;
+ return messageBuilder.build();
}
struct InputStream {
diff --git a/libs/input/tests/TestInputChannel.cpp b/libs/input/tests/TestInputChannel.cpp
new file mode 100644
index 0000000..d5f00b6
--- /dev/null
+++ b/libs/input/tests/TestInputChannel.cpp
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TestInputChannel"
+#define ATRACE_TAG ATRACE_TAG_INPUT
+
+#include <TestInputChannel.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace {
+constexpr int FAKE_FD{-1};
+} // namespace
+
+// --- TestInputChannel ---
+
+TestInputChannel::TestInputChannel(const std::string& name)
+ : InputChannel{name, base::unique_fd(FAKE_FD), sp<BBinder>::make()} {}
+
+void TestInputChannel::enqueueMessage(const InputMessage& message) {
+ mReceivedMessages.push(message);
+}
+
+status_t TestInputChannel::sendMessage(const InputMessage* message) {
+ LOG_IF(FATAL, message == nullptr)
+ << "TestInputChannel " << getName() << ". No message was passed to sendMessage.";
+
+ mSentMessages.push(*message);
+ return OK;
+}
+
+base::Result<InputMessage> TestInputChannel::receiveMessage() {
+ if (mReceivedMessages.empty()) {
+ return base::Error(WOULD_BLOCK);
+ }
+ InputMessage message = mReceivedMessages.front();
+ mReceivedMessages.pop();
+ return message;
+}
+
+bool TestInputChannel::probablyHasInput() const {
+ return !mReceivedMessages.empty();
+}
+
+void TestInputChannel::assertFinishMessage(uint32_t seq, bool handled) {
+ ASSERT_FALSE(mSentMessages.empty())
+ << "TestInputChannel " << getName() << ". Cannot assert. mSentMessages is empty.";
+
+ const InputMessage& finishMessage = mSentMessages.front();
+
+ EXPECT_EQ(finishMessage.header.seq, seq)
+ << "TestInputChannel " << getName()
+ << ". Sequence mismatch. Message seq: " << finishMessage.header.seq
+ << " Expected seq: " << seq;
+
+ EXPECT_EQ(finishMessage.body.finished.handled, handled)
+ << "TestInputChannel " << getName()
+ << ". Handled value mismatch. Message val: " << std::boolalpha
+ << finishMessage.body.finished.handled << "Expected val: " << handled
+ << std::noboolalpha;
+ mSentMessages.pop();
+}
+
+void TestInputChannel::assertNoSentMessages() const {
+ ASSERT_TRUE(mSentMessages.empty());
+}
+} // namespace android
\ No newline at end of file
diff --git a/libs/input/tests/TestInputChannel.h b/libs/input/tests/TestInputChannel.h
new file mode 100644
index 0000000..43253ec
--- /dev/null
+++ b/libs/input/tests/TestInputChannel.h
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <queue>
+#include <string>
+
+#include <android-base/result.h>
+#include <gtest/gtest.h>
+#include <input/InputTransport.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class TestInputChannel final : public InputChannel {
+public:
+ explicit TestInputChannel(const std::string& name);
+
+ /**
+ * Enqueues a message in mReceivedMessages.
+ */
+ void enqueueMessage(const InputMessage& message);
+
+ /**
+ * Pushes message to mSentMessages. In the default implementation, InputChannel sends messages
+ * through a file descriptor. TestInputChannel, on the contrary, stores sent messages in
+ * mSentMessages for assertion reasons.
+ */
+ status_t sendMessage(const InputMessage* message) override;
+
+ /**
+ * Returns an InputMessage from mReceivedMessages. This is done instead of retrieving data
+ * directly from fd.
+ */
+ base::Result<InputMessage> receiveMessage() override;
+
+ /**
+ * Returns if mReceivedMessages is not empty.
+ */
+ bool probablyHasInput() const override;
+
+ void assertFinishMessage(uint32_t seq, bool handled);
+
+ void assertNoSentMessages() const;
+
+private:
+ // InputMessages received by the endpoint.
+ std::queue<InputMessage> mReceivedMessages;
+ // InputMessages sent by the endpoint.
+ std::queue<InputMessage> mSentMessages;
+};
+} // namespace android
diff --git a/libs/input/tests/TestLooper.cpp b/libs/input/tests/TestLooper.cpp
new file mode 100644
index 0000000..e0f01ed
--- /dev/null
+++ b/libs/input/tests/TestLooper.cpp
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <TestLooper.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+
+TestLooper::TestLooper() : mLooper(sp<Looper>::make(/*allowNonCallbacks=*/false)) {}
+
+int TestLooper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+ void* data) {
+ mCallbacks[fd] = callback;
+ constexpr int SUCCESS{1};
+ return SUCCESS;
+}
+
+int TestLooper::removeFd(int fd) {
+ if (auto it = mCallbacks.find(fd); it != mCallbacks.cend()) {
+ mCallbacks.erase(fd);
+ constexpr int SUCCESS{1};
+ return SUCCESS;
+ }
+ constexpr int FAILURE{0};
+ return FAILURE;
+}
+
+void TestLooper::invokeCallback(int fd, int events) {
+ auto it = mCallbacks.find(fd);
+ LOG_IF(FATAL, it == mCallbacks.cend()) << "Fd does not exist in mCallbacks.";
+ mCallbacks[fd]->handleEvent(fd, events, /*data=*/nullptr);
+}
+
+sp<Looper> TestLooper::getLooper() const {
+ return mLooper;
+}
+} // namespace android
\ No newline at end of file
diff --git a/libs/input/tests/TestLooper.h b/libs/input/tests/TestLooper.h
new file mode 100644
index 0000000..3242bc7
--- /dev/null
+++ b/libs/input/tests/TestLooper.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <input/LooperInterface.h>
+
+namespace android {
+/**
+ * TestLooper provides a mechanism to directly trigger Looper's callback.
+ */
+class TestLooper final : public LooperInterface {
+public:
+ TestLooper();
+
+ /**
+ * Adds a file descriptor to mCallbacks. Ident, events, and data parameters are ignored. If
+ * addFd is called with an existent file descriptor and a different callback, the previous
+ * callback is overwritten.
+ */
+ int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+ void* data) override;
+
+ /**
+ * Removes a file descriptor from mCallbacks. If fd is not in mCallbacks, returns FAILURE.
+ */
+ int removeFd(int fd) override;
+
+ /**
+ * Calls handleEvent of the file descriptor. Fd must be in mCallbacks. Otherwise, invokeCallback
+ * fatally logs.
+ */
+ void invokeCallback(int fd, int events);
+
+ sp<Looper> getLooper() const override;
+
+private:
+ std::map<int /*fd*/, sp<LooperCallback>> mCallbacks;
+ sp<Looper> mLooper;
+};
+} // namespace android
\ No newline at end of file
diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
index 099f47d..f1453bd 100644
--- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
+++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
@@ -98,11 +98,25 @@
* is created in a detached state, and attachToContext must be called before
* calls to updateTexImage.
*/
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ SurfaceTexture(uint32_t tex, uint32_t textureTarget, bool useFenceSync, bool isControlledByApp);
+
+ SurfaceTexture(uint32_t textureTarget, bool useFenceSync, bool isControlledByApp);
+
+ SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t textureTarget,
+ bool useFenceSync, bool isControlledByApp)
+ __attribute((deprecated("Prefer ctors that create their own surface and consumer.")));
+
+ SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t textureTarget, bool useFenceSync,
+ bool isControlledByApp)
+ __attribute((deprecated("Prefer ctors that create their own surface and consumer.")));
+#else
SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t textureTarget,
bool useFenceSync, bool isControlledByApp);
SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t textureTarget, bool useFenceSync,
bool isControlledByApp);
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
/**
* updateTexImage acquires the most recently queued buffer, and sets the
@@ -499,6 +513,8 @@
friend class EGLConsumer;
private:
+ void initialize();
+
// Proxy listener to avoid having SurfaceTexture directly implement FrameAvailableListener as it
// is extending ConsumerBase which also implements FrameAvailableListener.
class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
index 3a09204..ce232cc 100644
--- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
+++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
@@ -35,6 +35,49 @@
static const mat4 mtxIdentity;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+SurfaceTexture::SurfaceTexture(uint32_t tex, uint32_t texTarget, bool useFenceSync,
+ bool isControlledByApp)
+ : ConsumerBase(isControlledByApp),
+ mCurrentCrop(Rect::EMPTY_RECT),
+ mCurrentTransform(0),
+ mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+ mCurrentFence(Fence::NO_FENCE),
+ mCurrentTimestamp(0),
+ mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
+ mCurrentFrameNumber(0),
+ mDefaultWidth(1),
+ mDefaultHeight(1),
+ mFilteringEnabled(true),
+ mTexName(tex),
+ mUseFenceSync(useFenceSync),
+ mTexTarget(texTarget),
+ mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
+ mOpMode(OpMode::attachedToGL) {
+ initialize();
+}
+
+SurfaceTexture::SurfaceTexture(uint32_t texTarget, bool useFenceSync, bool isControlledByApp)
+ : ConsumerBase(isControlledByApp),
+ mCurrentCrop(Rect::EMPTY_RECT),
+ mCurrentTransform(0),
+ mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+ mCurrentFence(Fence::NO_FENCE),
+ mCurrentTimestamp(0),
+ mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
+ mCurrentFrameNumber(0),
+ mDefaultWidth(1),
+ mDefaultHeight(1),
+ mFilteringEnabled(true),
+ mTexName(0),
+ mUseFenceSync(useFenceSync),
+ mTexTarget(texTarget),
+ mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
+ mOpMode(OpMode::detached) {
+ initialize();
+}
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+
SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
uint32_t texTarget, bool useFenceSync, bool isControlledByApp)
: ConsumerBase(bq, isControlledByApp),
@@ -53,11 +96,7 @@
mTexTarget(texTarget),
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
mOpMode(OpMode::attachedToGL) {
- SFT_LOGV("SurfaceTexture");
-
- memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
-
- mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
+ initialize();
}
SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
@@ -78,11 +117,7 @@
mTexTarget(texTarget),
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
mOpMode(OpMode::detached) {
- SFT_LOGV("SurfaceTexture");
-
- memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
-
- mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
+ initialize();
}
status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) {
@@ -531,4 +566,12 @@
}
#endif
+void SurfaceTexture::initialize() {
+ SFT_LOGV("SurfaceTexture");
+
+ memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
+
+ mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
+}
+
} // namespace android
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 8558074..a8a86ba 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -67,9 +67,6 @@
// Android O
first_version: "26",
- export_header_libs: [
- "libnativewindow_ndk_headers",
- ],
}
cc_library {
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
index 97740db..d68d6ba 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -29,6 +29,8 @@
"--bitfield-enum=AHardwareBuffer_UsageFlags",
"--allowlist-file=.*/nativewindow/include/.*\\.h",
+ "--allowlist-file=.*/include/cutils/.*\\.h",
+ "--allowlist-file=.*/include_outside_system/cutils/.*\\.h",
"--blocklist-type",
"AParcel",
"--raw-line",
@@ -39,6 +41,7 @@
],
shared_libs: [
"libbinder_ndk",
+ "libcutils",
"libnativewindow",
],
rustlibs: [
@@ -66,6 +69,7 @@
srcs: [":libnativewindow_bindgen_internal"],
shared_libs: [
"libbinder_ndk",
+ "libcutils",
"libnativewindow",
],
rustlibs: [
diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs
new file mode 100644
index 0000000..a3a9dc6
--- /dev/null
+++ b/libs/nativewindow/rust/src/handle.rs
@@ -0,0 +1,92 @@
+// 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.
+
+use std::{mem::forget, ptr::NonNull};
+
+/// Rust wrapper around `native_handle_t`.
+///
+/// This owns the `native_handle_t` and its file descriptors, and will close them and free it when
+/// it is dropped.
+#[derive(Debug)]
+pub struct NativeHandle(NonNull<ffi::native_handle_t>);
+
+impl NativeHandle {
+ /// Wraps a raw `native_handle_t` pointer, taking ownership of it.
+ ///
+ /// # Safety
+ ///
+ /// `native_handle` must be a valid pointer to a `native_handle_t`, and must not be used
+ /// anywhere else after calling this method.
+ pub unsafe fn from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self {
+ Self(native_handle)
+ }
+
+ /// Creates a new `NativeHandle` wrapping a clone of the given `native_handle_t` pointer.
+ ///
+ /// Unlike [`from_raw`](Self::from_raw) this doesn't take ownership of the pointer passed in, so
+ /// the caller remains responsible for closing and freeing it.
+ ///
+ /// # Safety
+ ///
+ /// `native_handle` must be a valid pointer to a `native_handle_t`.
+ pub unsafe fn clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self> {
+ // SAFETY: The caller promised that `native_handle` was valid.
+ let cloned = unsafe { ffi::native_handle_clone(native_handle.as_ptr()) };
+ NonNull::new(cloned).map(Self)
+ }
+
+ /// Returns a raw pointer to the wrapped `native_handle_t`.
+ ///
+ /// This is only valid as long as this `NativeHandle` exists, so shouldn't be stored. It mustn't
+ /// be closed or deleted.
+ pub fn as_raw(&self) -> NonNull<ffi::native_handle_t> {
+ self.0
+ }
+
+ /// Turns the `NativeHandle` into a raw `native_handle_t`.
+ ///
+ /// The caller takes ownership of the `native_handle_t` and its file descriptors, so is
+ /// responsible for closing and freeing it.
+ pub fn into_raw(self) -> NonNull<ffi::native_handle_t> {
+ let raw = self.0;
+ forget(self);
+ raw
+ }
+}
+
+impl Clone for NativeHandle {
+ fn clone(&self) -> Self {
+ // SAFETY: Our wrapped `native_handle_t` pointer is always valid.
+ unsafe { Self::clone_from_raw(self.0) }.expect("native_handle_clone returned null")
+ }
+}
+
+impl Drop for NativeHandle {
+ fn drop(&mut self) {
+ // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
+ // after this because we own it and are being dropped.
+ unsafe {
+ assert_eq!(ffi::native_handle_close(self.0.as_ptr()), 0);
+ assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
+ }
+ }
+}
+
+// SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file
+// descriptors, which aren't tied to any particular thread.
+unsafe impl Send for NativeHandle {}
+
+// SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just
+// integers and file descriptors.
+unsafe impl Sync for NativeHandle {}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index dc3f51f..931c311 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -16,7 +16,10 @@
extern crate nativewindow_bindgen as ffi;
+mod handle;
mod surface;
+
+pub use handle::NativeHandle;
pub use surface::Surface;
pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
@@ -27,11 +30,86 @@
unstable_api::{status_result, AsNative},
StatusCode,
};
-use ffi::{AHardwareBuffer, AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel};
+use ffi::{
+ AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_readFromParcel,
+ AHardwareBuffer_writeToParcel,
+};
use std::fmt::{self, Debug, Formatter};
use std::mem::ManuallyDrop;
use std::ptr::{self, null_mut, NonNull};
+/// Wrapper around a C `AHardwareBuffer_Desc`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct HardwareBufferDescription(AHardwareBuffer_Desc);
+
+impl HardwareBufferDescription {
+ /// Creates a new `HardwareBufferDescription` with the given parameters.
+ pub fn new(
+ width: u32,
+ height: u32,
+ layers: u32,
+ format: AHardwareBuffer_Format::Type,
+ usage: AHardwareBuffer_UsageFlags,
+ stride: u32,
+ ) -> Self {
+ Self(AHardwareBuffer_Desc {
+ width,
+ height,
+ layers,
+ format,
+ usage: usage.0,
+ stride,
+ rfu0: 0,
+ rfu1: 0,
+ })
+ }
+
+ /// Returns the width from the buffer description.
+ pub fn width(&self) -> u32 {
+ self.0.width
+ }
+
+ /// Returns the height from the buffer description.
+ pub fn height(&self) -> u32 {
+ self.0.height
+ }
+
+ /// Returns the number from layers from the buffer description.
+ pub fn layers(&self) -> u32 {
+ self.0.layers
+ }
+
+ /// Returns the format from the buffer description.
+ pub fn format(&self) -> AHardwareBuffer_Format::Type {
+ self.0.format
+ }
+
+ /// Returns the usage bitvector from the buffer description.
+ pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
+ AHardwareBuffer_UsageFlags(self.0.usage)
+ }
+
+ /// Returns the stride from the buffer description.
+ pub fn stride(&self) -> u32 {
+ self.0.stride
+ }
+}
+
+impl Default for HardwareBufferDescription {
+ fn default() -> Self {
+ Self(AHardwareBuffer_Desc {
+ width: 0,
+ height: 0,
+ layers: 0,
+ format: 0,
+ usage: 0,
+ stride: 0,
+ rfu0: 0,
+ rfu1: 0,
+ })
+ }
+}
+
/// Wrapper around an opaque C `AHardwareBuffer`.
#[derive(PartialEq, Eq)]
pub struct HardwareBuffer(NonNull<AHardwareBuffer>);
@@ -43,26 +121,9 @@
/// that the allocation of the given description will never succeed.
///
/// Available since API 29
- pub fn is_supported(
- width: u32,
- height: u32,
- layers: u32,
- format: AHardwareBuffer_Format::Type,
- usage: AHardwareBuffer_UsageFlags,
- stride: u32,
- ) -> bool {
- let buffer_desc = ffi::AHardwareBuffer_Desc {
- width,
- height,
- layers,
- format,
- usage: usage.0,
- stride,
- rfu0: 0,
- rfu1: 0,
- };
- // SAFETY: *buffer_desc will never be null.
- let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
+ pub fn is_supported(buffer_description: &HardwareBufferDescription) -> bool {
+ // SAFETY: The pointer comes from a reference so must be valid.
+ let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_description.0) };
status == 1
}
@@ -74,27 +135,11 @@
///
/// Available since API level 26.
#[inline]
- pub fn new(
- width: u32,
- height: u32,
- layers: u32,
- format: AHardwareBuffer_Format::Type,
- usage: AHardwareBuffer_UsageFlags,
- ) -> Option<Self> {
- let buffer_desc = ffi::AHardwareBuffer_Desc {
- width,
- height,
- layers,
- format,
- usage: usage.0,
- stride: 0,
- rfu0: 0,
- rfu1: 0,
- };
+ pub fn new(buffer_description: &HardwareBufferDescription) -> Option<Self> {
let mut ptr = ptr::null_mut();
// SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
// and return a status, but we check it later.
- let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) };
+ let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_description.0, &mut ptr) };
if status == 0 {
Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null")))
@@ -103,6 +148,50 @@
}
}
+ /// Creates a `HardwareBuffer` from a native handle.
+ ///
+ /// The native handle is cloned, so this doesn't take ownership of the original handle passed
+ /// in.
+ pub fn create_from_handle(
+ handle: &NativeHandle,
+ buffer_description: &HardwareBufferDescription,
+ ) -> Result<Self, StatusCode> {
+ let mut buffer = ptr::null_mut();
+ // SAFETY: The caller guarantees that `handle` is valid, and the buffer pointer is valid
+ // because it comes from a reference. The method we pass means that
+ // `AHardwareBuffer_createFromHandle` will clone the handle rather than taking ownership of
+ // it.
+ let status = unsafe {
+ ffi::AHardwareBuffer_createFromHandle(
+ &buffer_description.0,
+ handle.as_raw().as_ptr(),
+ ffi::CreateFromHandleMethod_AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE
+ .try_into()
+ .unwrap(),
+ &mut buffer,
+ )
+ };
+ status_result(status)?;
+ Ok(Self(NonNull::new(buffer).expect("Allocated AHardwareBuffer was null")))
+ }
+
+ /// Returns a clone of the native handle of the buffer.
+ ///
+ /// Returns `None` if the operation fails for any reason.
+ pub fn cloned_native_handle(&self) -> Option<NativeHandle> {
+ // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid
+ // because it must have been allocated by `AHardwareBuffer_allocate`,
+ // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet
+ // released it.
+ let native_handle = unsafe { ffi::AHardwareBuffer_getNativeHandle(self.0.as_ptr()) };
+ NonNull::new(native_handle.cast_mut()).and_then(|native_handle| {
+ // SAFETY: `AHardwareBuffer_getNativeHandle` should have returned a valid pointer which
+ // is valid at least as long as the buffer is, and `clone_from_raw` clones it rather
+ // than taking ownership of it so the original `native_handle` isn't stored.
+ unsafe { NativeHandle::clone_from_raw(native_handle) }
+ })
+ }
+
/// Adopts the given raw pointer and wraps it in a Rust HardwareBuffer.
///
/// # Safety
@@ -155,37 +244,8 @@
out_id
}
- /// Get the width of this buffer
- pub fn width(&self) -> u32 {
- self.description().width
- }
-
- /// Get the height of this buffer
- pub fn height(&self) -> u32 {
- self.description().height
- }
-
- /// Get the number of layers of this buffer
- pub fn layers(&self) -> u32 {
- self.description().layers
- }
-
- /// Get the format of this buffer
- pub fn format(&self) -> AHardwareBuffer_Format::Type {
- self.description().format
- }
-
- /// Get the usage bitvector of this buffer
- pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
- AHardwareBuffer_UsageFlags(self.description().usage)
- }
-
- /// Get the stride of this buffer
- pub fn stride(&self) -> u32 {
- self.description().stride
- }
-
- fn description(&self) -> ffi::AHardwareBuffer_Desc {
+ /// Returns the description of this buffer.
+ pub fn description(&self) -> HardwareBufferDescription {
let mut buffer_desc = ffi::AHardwareBuffer_Desc {
width: 0,
height: 0,
@@ -198,7 +258,7 @@
};
// SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) };
- buffer_desc
+ HardwareBufferDescription(buffer_desc)
}
}
@@ -281,19 +341,27 @@
#[test]
fn create_valid_buffer_returns_ok() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
512,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- );
+ 0,
+ ));
assert!(buffer.is_some());
}
#[test]
fn create_invalid_buffer_returns_err() {
- let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
+ 512,
+ 512,
+ 1,
+ 0,
+ AHardwareBuffer_UsageFlags(0),
+ 0,
+ ));
assert!(buffer.is_none());
}
@@ -319,39 +387,45 @@
// SAFETY: The pointer must be valid because it was just allocated successfully, and we
// don't use it after calling this.
let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) };
- assert_eq!(buffer.width(), 1024);
+ assert_eq!(buffer.description().width(), 1024);
}
#[test]
fn basic_getters() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
1024,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.expect("Buffer with some basic parameters was not created successfully");
- assert_eq!(buffer.width(), 1024);
- assert_eq!(buffer.height(), 512);
- assert_eq!(buffer.layers(), 1);
- assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
+ let description = buffer.description();
+ assert_eq!(description.width(), 1024);
+ assert_eq!(description.height(), 512);
+ assert_eq!(description.layers(), 1);
assert_eq!(
- buffer.usage(),
+ description.format(),
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
+ );
+ assert_eq!(
+ description.usage(),
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
);
}
#[test]
fn id_getter() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
1024,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.expect("Buffer with some basic parameters was not created successfully");
assert_ne!(0, buffer.id());
@@ -359,13 +433,14 @@
#[test]
fn clone() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
1024,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.expect("Buffer with some basic parameters was not created successfully");
let buffer2 = buffer.clone();
@@ -374,13 +449,14 @@
#[test]
fn into_raw() {
- let buffer = HardwareBuffer::new(
+ let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
1024,
512,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.expect("Buffer with some basic parameters was not created successfully");
let buffer2 = buffer.clone();
@@ -390,4 +466,26 @@
assert_eq!(remade_buffer, buffer2);
}
+
+ #[test]
+ fn native_handle_and_back() {
+ let buffer_description = HardwareBufferDescription::new(
+ 1024,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ 1024,
+ );
+ let buffer = HardwareBuffer::new(&buffer_description)
+ .expect("Buffer with some basic parameters was not created successfully");
+
+ let native_handle =
+ buffer.cloned_native_handle().expect("Failed to get native handle for buffer");
+ let buffer2 = HardwareBuffer::create_from_handle(&native_handle, &buffer_description)
+ .expect("Failed to create buffer from native handle");
+
+ assert_eq!(buffer.description(), buffer_description);
+ assert_eq!(buffer2.description(), buffer_description);
+ }
}
diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h
index 5689f7d..5046a80 100644
--- a/libs/nativewindow/rust/sys/nativewindow_bindings.h
+++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h
@@ -20,3 +20,5 @@
#include <android/hdr_metadata.h>
#include <android/native_window.h>
#include <android/native_window_aidl.h>
+#include <cutils/native_handle.h>
+#include <vndk/hardware_buffer.h>
diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp
index 6cf8291..937ff02 100644
--- a/libs/nativewindow/tests/ANativeWindowTest.cpp
+++ b/libs/nativewindow/tests/ANativeWindowTest.cpp
@@ -50,9 +50,14 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ mItemConsumer = new BufferItemConsumer(GRALLOC_USAGE_SW_READ_OFTEN);
+ mWindow = new TestableSurface(mItemConsumer->getSurface()->getIGraphicBufferProducer());
+#else
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN);
mWindow = new TestableSurface(mProducer);
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU);
EXPECT_EQ(0, success);
}
@@ -64,10 +69,12 @@
const int success = native_window_api_disconnect(mWindow.get(), NATIVE_WINDOW_API_CPU);
EXPECT_EQ(0, success);
}
+
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
sp<IGraphicBufferProducer> mProducer;
sp<IGraphicBufferConsumer> mConsumer;
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
sp<BufferItemConsumer> mItemConsumer;
-
sp<TestableSurface> mWindow;
};
diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
index 876f6c8..73a7e95 100644
--- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
@@ -22,13 +22,14 @@
#[inline]
fn create_720p_buffer() -> HardwareBuffer {
- HardwareBuffer::new(
+ HardwareBuffer::new(&HardwareBufferDescription::new(
1280,
720,
1,
AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
- )
+ 0,
+ ))
.unwrap()
}
@@ -51,7 +52,7 @@
// underlying call to AHardwareBuffer_describe.
c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| {
b.iter(|| {
- buffer.width();
+ buffer.description().width();
})
});
}
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 326d1ce..a9264b3 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -29,6 +29,16 @@
using namespace android;
using namespace android::renderengine;
+// To run tests:
+/**
+ * mmm frameworks/native/libs/renderengine/benchmark;\
+ * adb push $OUT/data/benchmarktest/librenderengine_bench/librenderengine_bench
+ * /data/benchmarktest/librenderengine_bench/librenderengine_bench;\
+ * adb shell /data/benchmarktest/librenderengine_bench/librenderengine_bench
+ *
+ * (64-bit devices: out directory contains benchmarktest64 instead of benchmarktest)
+ */
+
///////////////////////////////////////////////////////////////////////////////
// Helpers for calling drawLayers
///////////////////////////////////////////////////////////////////////////////
@@ -173,29 +183,67 @@
}
}
+/**
+ * Return a buffer with the image in the provided path, relative to the executable directory
+ */
+static std::shared_ptr<ExternalTexture> createTexture(RenderEngine& re, const char* relPathImg) {
+ // Initially use cpu access so we can decode into it with AImageDecoder.
+ auto [width, height] = getDisplaySize();
+ auto srcBuffer =
+ allocateBuffer(re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source");
+ std::string fileName = base::GetExecutableDirectory().append(relPathImg);
+ renderenginebench::decode(fileName.c_str(), srcBuffer->getBuffer());
+ // Now copy into GPU-only buffer for more realistic timing.
+ srcBuffer = copyBuffer(re, srcBuffer, 0, "source");
+ return srcBuffer;
+}
+
///////////////////////////////////////////////////////////////////////////////
// Benchmarks
///////////////////////////////////////////////////////////////////////////////
+constexpr char kHomescreenPath[] = "/resources/homescreen.png";
+
+/**
+ * Draw a layer with texture and no additional shaders as a baseline to evaluate a shader's impact
+ * on performance
+ */
template <class... Args>
-void BM_blur(benchmark::State& benchState, Args&&... args) {
+void BM_homescreen(benchmark::State& benchState, Args&&... args) {
auto args_tuple = std::make_tuple(std::move(args)...);
auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
- static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)),
- static_cast<RenderEngine::BlurAlgorithm>(std::get<2>(args_tuple)));
+ static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
- // Initially use cpu access so we can decode into it with AImageDecoder.
auto [width, height] = getDisplaySize();
- auto srcBuffer =
- allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source");
- {
- std::string srcImage = base::GetExecutableDirectory();
- srcImage.append("/resources/homescreen.png");
- renderenginebench::decode(srcImage.c_str(), srcBuffer->getBuffer());
+ auto srcBuffer = createTexture(*re, kHomescreenPath);
- // Now copy into GPU-only buffer for more realistic timing.
- srcBuffer = copyBuffer(*re, srcBuffer, 0, "source");
- }
+ const FloatRect layerRect(0, 0, width, height);
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .boundaries = layerRect,
+ },
+ .source =
+ PixelSource{
+ .buffer =
+ Buffer{
+ .buffer = srcBuffer,
+ },
+ },
+ .alpha = half(1.0f),
+ };
+ auto layers = std::vector<LayerSettings>{layer};
+ benchDrawLayers(*re, layers, benchState, "homescreen");
+}
+
+template <class... Args>
+void BM_homescreen_blur(benchmark::State& benchState, Args&&... args) {
+ auto args_tuple = std::make_tuple(std::move(args)...);
+ auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
+ static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
+
+ auto [width, height] = getDisplaySize();
+ auto srcBuffer = createTexture(*re, kHomescreenPath);
const FloatRect layerRect(0, 0, width, height);
LayerSettings layer{
@@ -223,14 +271,55 @@
};
auto layers = std::vector<LayerSettings>{layer, blurLayer};
- benchDrawLayers(*re, layers, benchState, "blurred");
+ benchDrawLayers(*re, layers, benchState, "homescreen_blurred");
}
-BENCHMARK_CAPTURE(BM_blur, gaussian, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL,
- RenderEngine::BlurAlgorithm::GAUSSIAN);
+template <class... Args>
+void BM_homescreen_edgeExtension(benchmark::State& benchState, Args&&... args) {
+ auto args_tuple = std::make_tuple(std::move(args)...);
+ auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
+ static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
-BENCHMARK_CAPTURE(BM_blur, kawase, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL,
- RenderEngine::BlurAlgorithm::KAWASE);
+ auto [width, height] = getDisplaySize();
+ auto srcBuffer = createTexture(*re, kHomescreenPath);
-BENCHMARK_CAPTURE(BM_blur, kawase_dual_filter, RenderEngine::Threaded::YES,
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .boundaries = FloatRect(0, 0, width, height),
+ },
+ .source =
+ PixelSource{
+ .buffer =
+ Buffer{
+ .buffer = srcBuffer,
+ // Part of the screen is not covered by the texture but
+ // will be filled in by the shader
+ .textureTransform =
+ mat4(mat3(),
+ vec3(width * 0.3f, height * 0.3f, 0.0f)),
+ },
+ },
+ .alpha = half(1.0f),
+ .edgeExtensionEffect =
+ EdgeExtensionEffect(/* left */ true,
+ /* right */ false, /* top */ true, /* bottom */ false),
+ };
+ auto layers = std::vector<LayerSettings>{layer};
+ benchDrawLayers(*re, layers, benchState, "homescreen_edge_extension");
+}
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, gaussian, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::GAUSSIAN);
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, kawase, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE);
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, kawase_dual_filter, RenderEngine::Threaded::YES,
RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER);
+
+BENCHMARK_CAPTURE(BM_homescreen, SkiaGLThreaded, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL);
+
+BENCHMARK_CAPTURE(BM_homescreen_edgeExtension, SkiaGLThreaded, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL);
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
index 74daf47..a570ad0 100644
--- a/libs/renderengine/skia/AutoBackendTexture.h
+++ b/libs/renderengine/skia/AutoBackendTexture.h
@@ -16,9 +16,9 @@
#pragma once
-#include <GrDirectContext.h>
#include <SkImage.h>
#include <SkSurface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <sys/types.h>
#include <ui/GraphicTypes.h>
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index af24600..4ef7d5b 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -21,16 +21,15 @@
#include "SkiaGLRenderEngine.h"
-#include "compat/SkiaGpuContext.h"
-
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <GrContextOptions.h>
-#include <GrTypes.h>
#include <android-base/stringprintf.h>
#include <common/trace.h>
-#include <gl/GrGLInterface.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
+#include <log/log_main.h>
#include <sync/sync.h>
#include <ui/DebugUtils.h>
@@ -40,7 +39,7 @@
#include <numeric>
#include "GLExtensions.h"
-#include "log/log_main.h"
+#include "compat/SkiaGpuContext.h"
namespace android {
namespace renderengine {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index bd177e6..7651038 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -20,9 +20,10 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
-#include <GrDirectContext.h>
#include <SkSurface.h>
#include <android-base/thread_annotations.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
#include <sys/types.h>
@@ -32,7 +33,6 @@
#include "AutoBackendTexture.h"
#include "EGL/egl.h"
-#include "GrContextOptions.h"
#include "SkImageInfo.h"
#include "SkiaRenderEngine.h"
#include "android-base/macros.h"
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 426ccd6..ec9d3ef 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -20,9 +20,6 @@
#include "SkiaRenderEngine.h"
-#include <GrBackendSemaphore.h>
-#include <GrContextOptions.h>
-#include <GrTypes.h>
#include <SkBlendMode.h>
#include <SkCanvas.h>
#include <SkColor.h>
@@ -56,6 +53,9 @@
#include <common/FlagManager.h>
#include <common/trace.h>
#include <gui/FenceMonitor.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <pthread.h>
#include <src/core/SkTraceEventCommon.h>
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index faa3fb5..b5f8898 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -18,11 +18,12 @@
#define SF_SKIARENDERENGINE_H_
#include <renderengine/RenderEngine.h>
-#include <sys/types.h>
-#include <GrBackendSemaphore.h>
-#include <SkSurface.h>
#include <android-base/thread_annotations.h>
+#include <include/core/SkImageInfo.h>
+#include <include/core/SkSurface.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
#include <sys/types.h>
@@ -32,8 +33,6 @@
#include <unordered_map>
#include "AutoBackendTexture.h"
-#include "GrContextOptions.h"
-#include "SkImageInfo.h"
#include "android-base/macros.h"
#include "compat/SkiaGpuContext.h"
#include "debug/SkiaCapture.h"
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index d89e818..677a2b6 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -24,12 +24,12 @@
#include "GaneshVkRenderEngine.h"
#include "compat/SkiaGpuContext.h"
-#include <GrBackendSemaphore.h>
-#include <GrContextOptions.h>
-#include <GrDirectContext.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
-#include <vk/GrVkTypes.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
#include <android-base/stringprintf.h>
#include <common/trace.h>
diff --git a/libs/renderengine/skia/compat/GaneshBackendTexture.cpp b/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
index 3fbc6ca..88282e7 100644
--- a/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
+++ b/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
@@ -21,12 +21,12 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <include/core/SkImage.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <include/gpu/ganesh/SkImageGanesh.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
#include <include/gpu/ganesh/vk/GrVkBackendSurface.h>
-#include <include/gpu/vk/GrVkTypes.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
#include "skia/ColorSpaces.h"
#include "skia/compat/SkiaBackendTexture.h"
diff --git a/libs/renderengine/skia/compat/GaneshBackendTexture.h b/libs/renderengine/skia/compat/GaneshBackendTexture.h
index 5cf8647..4337df1 100644
--- a/libs/renderengine/skia/compat/GaneshBackendTexture.h
+++ b/libs/renderengine/skia/compat/GaneshBackendTexture.h
@@ -21,7 +21,7 @@
#include <include/android/GrAHardwareBufferUtils.h>
#include <include/core/SkColorSpace.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <android-base/macros.h>
diff --git a/libs/renderengine/skia/compat/GaneshGpuContext.cpp b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
index b121fe8..931f843 100644
--- a/libs/renderengine/skia/compat/GaneshGpuContext.cpp
+++ b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
@@ -19,12 +19,12 @@
#include <include/core/SkImageInfo.h>
#include <include/core/SkSurface.h>
#include <include/core/SkTraceMemoryDump.h>
-#include <include/gpu/GrDirectContext.h>
-#include <include/gpu/GrTypes.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
-#include <include/gpu/gl/GrGLInterface.h>
#include <include/gpu/vk/VulkanBackendContext.h>
#include "../AutoBackendTexture.h"
diff --git a/libs/renderengine/skia/compat/SkiaBackendTexture.h b/libs/renderengine/skia/compat/SkiaBackendTexture.h
index 09877a5..fa12624 100644
--- a/libs/renderengine/skia/compat/SkiaBackendTexture.h
+++ b/libs/renderengine/skia/compat/SkiaBackendTexture.h
@@ -18,7 +18,7 @@
#include <include/android/GrAHardwareBufferUtils.h>
#include <include/core/SkColorSpace.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <android/hardware_buffer.h>
#include <ui/GraphicTypes.h>
diff --git a/libs/renderengine/skia/compat/SkiaGpuContext.h b/libs/renderengine/skia/compat/SkiaGpuContext.h
index 9fa6fb8..0bd8283 100644
--- a/libs/renderengine/skia/compat/SkiaGpuContext.h
+++ b/libs/renderengine/skia/compat/SkiaGpuContext.h
@@ -20,10 +20,10 @@
#define LOG_TAG "RenderEngine"
#include <include/core/SkSurface.h>
-#include <include/gpu/GrDirectContext.h>
-#include <include/gpu/gl/GrGLInterface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
#include <include/gpu/graphite/Context.h>
-#include "include/gpu/vk/VulkanBackendContext.h"
+#include <include/gpu/vk/VulkanBackendContext.h>
#include "SkiaBackendTexture.h"
diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp
index e5af740..8b13d78 100644
--- a/libs/ui/DisplayIdentification.cpp
+++ b/libs/ui/DisplayIdentification.cpp
@@ -26,6 +26,7 @@
#include <ftl/hash.h>
#include <log/log.h>
#include <ui/DisplayIdentification.h>
+#include <ui/Size.h>
namespace android {
namespace {
@@ -46,6 +47,10 @@
return view[3];
}
+bool isDetailedTimingDescriptor(const byte_view& view) {
+ return view[0] != 0 && view[1] != 0;
+}
+
std::string_view parseEdidText(const byte_view& view) {
std::string_view text(reinterpret_cast<const char*>(view.data()), view.size());
text = text.substr(0, text.find('\n'));
@@ -219,6 +224,8 @@
std::string_view displayName;
std::string_view serialNumber;
std::string_view asciiText;
+ ui::Size preferredDTDPixelSize;
+ ui::Size preferredDTDPhysicalSize;
constexpr size_t kDescriptorCount = 4;
constexpr size_t kDescriptorLength = 18;
@@ -243,6 +250,35 @@
serialNumber = parseEdidText(descriptor);
break;
}
+ } else if (isDetailedTimingDescriptor(view)) {
+ static constexpr size_t kHorizontalPhysicalLsbOffset = 12;
+ static constexpr size_t kHorizontalPhysicalMsbOffset = 14;
+ static constexpr size_t kVerticalPhysicalLsbOffset = 13;
+ static constexpr size_t kVerticalPhysicalMsbOffset = 14;
+ const uint32_t hSize =
+ static_cast<uint32_t>(view[kHorizontalPhysicalLsbOffset] |
+ ((view[kHorizontalPhysicalMsbOffset] >> 4) << 8));
+ const uint32_t vSize =
+ static_cast<uint32_t>(view[kVerticalPhysicalLsbOffset] |
+ ((view[kVerticalPhysicalMsbOffset] & 0b1111) << 8));
+
+ static constexpr size_t kHorizontalPixelLsbOffset = 2;
+ static constexpr size_t kHorizontalPixelMsbOffset = 4;
+ static constexpr size_t kVerticalPixelLsbOffset = 5;
+ static constexpr size_t kVerticalPixelMsbOffset = 7;
+
+ const uint8_t hLsb = view[kHorizontalPixelLsbOffset];
+ const uint8_t hMsb = view[kHorizontalPixelMsbOffset];
+ const int32_t hPixel = hLsb + ((hMsb & 0xF0) << 4);
+
+ const uint8_t vLsb = view[kVerticalPixelLsbOffset];
+ const uint8_t vMsb = view[kVerticalPixelMsbOffset];
+ const int32_t vPixel = vLsb + ((vMsb & 0xF0) << 4);
+
+ preferredDTDPixelSize.setWidth(hPixel);
+ preferredDTDPixelSize.setHeight(vPixel);
+ preferredDTDPhysicalSize.setWidth(hSize);
+ preferredDTDPhysicalSize.setHeight(vSize);
}
view = view.subspan(kDescriptorLength);
@@ -297,14 +333,22 @@
}
}
- return Edid{.manufacturerId = manufacturerId,
- .productId = productId,
- .pnpId = *pnpId,
- .modelHash = modelHash,
- .displayName = displayName,
- .manufactureOrModelYear = manufactureOrModelYear,
- .manufactureWeek = manufactureWeek,
- .cea861Block = cea861Block};
+ DetailedTimingDescriptor preferredDetailedTimingDescriptor{
+ .pixelSizeCount = preferredDTDPixelSize,
+ .physicalSizeInMm = preferredDTDPhysicalSize,
+ };
+
+ return Edid{
+ .manufacturerId = manufacturerId,
+ .productId = productId,
+ .pnpId = *pnpId,
+ .modelHash = modelHash,
+ .displayName = displayName,
+ .manufactureOrModelYear = manufactureOrModelYear,
+ .manufactureWeek = manufactureWeek,
+ .cea861Block = cea861Block,
+ .preferredDetailedTimingDescriptor = preferredDetailedTimingDescriptor,
+ };
}
std::optional<PnpId> getPnpId(uint16_t manufacturerId) {
@@ -336,9 +380,12 @@
}
const auto displayId = PhysicalDisplayId::fromEdid(port, edid->manufacturerId, edid->modelHash);
- return DisplayIdentificationInfo{.id = displayId,
- .name = std::string(edid->displayName),
- .deviceProductInfo = buildDeviceProductInfo(*edid)};
+ return DisplayIdentificationInfo{
+ .id = displayId,
+ .name = std::string(edid->displayName),
+ .deviceProductInfo = buildDeviceProductInfo(*edid),
+ .preferredDetailedTimingDescriptor = edid->preferredDetailedTimingDescriptor,
+ };
}
PhysicalDisplayId getVirtualDisplayId(uint32_t id) {
diff --git a/libs/ui/include/ui/DisplayIdentification.h b/libs/ui/include/ui/DisplayIdentification.h
index 8bc2017..648e024 100644
--- a/libs/ui/include/ui/DisplayIdentification.h
+++ b/libs/ui/include/ui/DisplayIdentification.h
@@ -25,6 +25,7 @@
#include <ui/DeviceProductInfo.h>
#include <ui/DisplayId.h>
+#include <ui/Size.h>
#define LEGACY_DISPLAY_TYPE_PRIMARY 0
#define LEGACY_DISPLAY_TYPE_EXTERNAL 1
@@ -33,10 +34,16 @@
using DisplayIdentificationData = std::vector<uint8_t>;
+struct DetailedTimingDescriptor {
+ ui::Size pixelSizeCount;
+ ui::Size physicalSizeInMm;
+};
+
struct DisplayIdentificationInfo {
PhysicalDisplayId id;
std::string name;
std::optional<DeviceProductInfo> deviceProductInfo;
+ std::optional<DetailedTimingDescriptor> preferredDetailedTimingDescriptor;
};
struct ExtensionBlock {
@@ -68,6 +75,7 @@
uint8_t manufactureOrModelYear;
uint8_t manufactureWeek;
std::optional<Cea861ExtensionBlock> cea861Block;
+ std::optional<DetailedTimingDescriptor> preferredDetailedTimingDescriptor;
};
bool isEdid(const DisplayIdentificationData&);
diff --git a/libs/ui/tests/DisplayIdentification_test.cpp b/libs/ui/tests/DisplayIdentification_test.cpp
index 721b466..76e3f66 100644
--- a/libs/ui/tests/DisplayIdentification_test.cpp
+++ b/libs/ui/tests/DisplayIdentification_test.cpp
@@ -194,6 +194,10 @@
EXPECT_EQ(21, edid->manufactureOrModelYear);
EXPECT_EQ(0, edid->manufactureWeek);
EXPECT_FALSE(edid->cea861Block);
+ EXPECT_EQ(1280, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width);
+ EXPECT_EQ(800, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height);
+ EXPECT_EQ(261, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width);
+ EXPECT_EQ(163, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height);
edid = parseEdid(getExternalEdid());
ASSERT_TRUE(edid);
@@ -206,6 +210,10 @@
EXPECT_EQ(22, edid->manufactureOrModelYear);
EXPECT_EQ(2, edid->manufactureWeek);
EXPECT_FALSE(edid->cea861Block);
+ EXPECT_EQ(1280, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width);
+ EXPECT_EQ(800, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height);
+ EXPECT_EQ(641, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width);
+ EXPECT_EQ(400, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height);
edid = parseEdid(getExternalEedid());
ASSERT_TRUE(edid);
@@ -224,6 +232,10 @@
EXPECT_EQ(0, physicalAddress.b);
EXPECT_EQ(0, physicalAddress.c);
EXPECT_EQ(0, physicalAddress.d);
+ EXPECT_EQ(1366, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width);
+ EXPECT_EQ(768, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height);
+ EXPECT_EQ(160, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width);
+ EXPECT_EQ(90, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height);
edid = parseEdid(getPanasonicTvEdid());
ASSERT_TRUE(edid);
@@ -242,6 +254,10 @@
EXPECT_EQ(0, physicalAddress.b);
EXPECT_EQ(0, physicalAddress.c);
EXPECT_EQ(0, physicalAddress.d);
+ EXPECT_EQ(1920, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width);
+ EXPECT_EQ(1080, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height);
+ EXPECT_EQ(698, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width);
+ EXPECT_EQ(392, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height);
edid = parseEdid(getHisenseTvEdid());
ASSERT_TRUE(edid);
@@ -260,6 +276,10 @@
EXPECT_EQ(2, physicalAddress.b);
EXPECT_EQ(3, physicalAddress.c);
EXPECT_EQ(4, physicalAddress.d);
+ EXPECT_EQ(1920, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width);
+ EXPECT_EQ(1080, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height);
+ EXPECT_EQ(575, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width);
+ EXPECT_EQ(323, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height);
edid = parseEdid(getCtlDisplayEdid());
ASSERT_TRUE(edid);
@@ -273,6 +293,10 @@
EXPECT_EQ(0xff, edid->manufactureWeek);
ASSERT_TRUE(edid->cea861Block);
EXPECT_FALSE(edid->cea861Block->hdmiVendorDataBlock);
+ EXPECT_EQ(1360, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width);
+ EXPECT_EQ(768, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height);
+ EXPECT_EQ(521, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width);
+ EXPECT_EQ(293, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height);
}
TEST(DisplayIdentificationTest, parseInvalidEdid) {
diff --git a/opengl/OWNERS b/opengl/OWNERS
index 3d60a1d..645a578 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -2,5 +2,4 @@
cnorthrop@google.com
ianelliott@google.com
jessehall@google.com
-lpy@google.com
-vantablack@google.com
+tomnom@google.com
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 16de390..5159ffe 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -40,9 +40,6 @@
symbol_file: "libEGL.map.txt",
first_version: "9",
unversioned_until: "current",
- export_header_libs: [
- "libEGL_headers",
- ],
}
ndk_library {
@@ -50,9 +47,6 @@
symbol_file: "libGLESv1_CM.map.txt",
first_version: "9",
unversioned_until: "current",
- export_header_libs: [
- "libGLESv1_CM_headers",
- ],
}
ndk_library {
@@ -60,9 +54,6 @@
symbol_file: "libGLESv2.map.txt",
first_version: "9",
unversioned_until: "current",
- export_header_libs: [
- "libGLESv2_headers",
- ],
}
ndk_library {
@@ -70,9 +61,6 @@
symbol_file: "libGLESv3.map.txt",
first_version: "18",
unversioned_until: "current",
- export_header_libs: [
- "libGLESv3_headers",
- ],
}
cc_defaults {
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index 3ef5049..da1aae2 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -152,6 +152,12 @@
data.writeNullableParcelable(extras);
return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual status_t permissionUpdateBarrier() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
+ return remote()->transact(PERMISSION_UPDATE_BARRIER, data, &reply, 0);
+ }
};
IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
index 1a744ab..7628745 100644
--- a/services/gpuservice/gpuwork/GpuWork.cpp
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -44,7 +44,7 @@
#include "gpuwork/gpuWork.h"
-#define ONE_MS_IN_NS (10000000)
+#define MSEC_PER_NSEC (1000LU * 1000LU)
namespace android {
namespace gpuwork {
@@ -118,6 +118,9 @@
}
void GpuWork::initialize() {
+ // Workaround b/347947040 by allowing time for statsd / bpf setup.
+ std::this_thread::sleep_for(std::chrono::seconds(30));
+
// Make sure BPF programs are loaded.
bpf::waitForProgsLoaded();
@@ -382,10 +385,11 @@
ALOGI("pullWorkAtoms: after random selection: uids.size() == %zu", uids.size());
auto now = std::chrono::steady_clock::now();
- long long duration =
- std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint)
- .count();
- if (duration > std::numeric_limits<int32_t>::max() || duration < 0) {
+ int32_t duration =
+ static_cast<int32_t>(
+ std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint)
+ .count());
+ if (duration < 0) {
// This is essentially impossible. If it does somehow happen, give up,
// but still clear the map.
clearMap();
@@ -401,13 +405,14 @@
}
const UidTrackingInfo& info = it->second;
- uint64_t total_active_duration_ms = info.total_active_duration_ns / ONE_MS_IN_NS;
- uint64_t total_inactive_duration_ms = info.total_inactive_duration_ns / ONE_MS_IN_NS;
+ int32_t total_active_duration_ms =
+ static_cast<int32_t>(info.total_active_duration_ns / MSEC_PER_NSEC);
+ int32_t total_inactive_duration_ms =
+ static_cast<int32_t>(info.total_inactive_duration_ns / MSEC_PER_NSEC);
// Skip this atom if any numbers are out of range. |duration| is
// already checked above.
- if (total_active_duration_ms > std::numeric_limits<int32_t>::max() ||
- total_inactive_duration_ms > std::numeric_limits<int32_t>::max()) {
+ if (total_active_duration_ms < 0 || total_inactive_duration_ms < 0) {
continue;
}
@@ -418,11 +423,11 @@
// gpu_id
bitcast_int32(gpuId),
// time_duration_seconds
- static_cast<int32_t>(duration),
+ duration,
// total_active_duration_millis
- static_cast<int32_t>(total_active_duration_ms),
+ total_active_duration_ms,
// total_inactive_duration_millis
- static_cast<int32_t>(total_inactive_duration_ms));
+ total_inactive_duration_ms);
}
}
clearMap();
diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
index e70da54..60cd2c7 100644
--- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
+++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
@@ -125,7 +125,7 @@
static constexpr size_t kNumGpusHardLimit = 32;
// The minimum GPU time needed to actually log stats for a UID.
- static constexpr uint64_t kMinGpuTimeNanoseconds = 30U * 1000000000U; // 30 seconds.
+ static constexpr uint64_t kMinGpuTimeNanoseconds = 10LLU * 1000000000LLU; // 10 seconds.
// The previous time point at which |mGpuWorkMap| was cleared.
std::chrono::steady_clock::time_point mPreviousMapClearTimePoint GUARDED_BY(mMutex);
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-0 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-0
new file mode 100644
index 0000000..120a34d
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-0
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-1 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-1
new file mode 100644
index 0000000..92d5bdf
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-1
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-10 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-10
new file mode 100644
index 0000000..c044c84
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-10
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-11 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-11
new file mode 100644
index 0000000..430552e
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-11
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-12 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-12
new file mode 100644
index 0000000..f7849bb
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-12
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-13 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-13
new file mode 100644
index 0000000..2f0a655
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-13
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-14 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-14
new file mode 100644
index 0000000..bd8fb01
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-14
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-15 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-15
new file mode 100644
index 0000000..29aa2b1
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-15
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-16 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-16
new file mode 100644
index 0000000..e00100f
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-16
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-17 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-17
new file mode 100644
index 0000000..db281e1
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-17
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-18 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-18
new file mode 100644
index 0000000..5592c32
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-18
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-2 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-2
new file mode 100644
index 0000000..5bd2b99
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-2
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-3 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-3
new file mode 100644
index 0000000..2d89289
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-3
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-4 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-4
new file mode 100644
index 0000000..8f3f1c2
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-4
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-5 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-5
new file mode 100644
index 0000000..95b05e7
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-5
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-6 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-6
new file mode 100644
index 0000000..497a501
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-6
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-7 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-7
new file mode 100644
index 0000000..9902bde
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-7
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-8 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-8
new file mode 100644
index 0000000..fdaaf31
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-8
Binary files differ
diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-9 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-9
new file mode 100644
index 0000000..a197c6a
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-9
Binary files differ
diff --git a/services/inputflinger/InputFilter.cpp b/services/inputflinger/InputFilter.cpp
index e4d73fc..2ef94fb 100644
--- a/services/inputflinger/InputFilter.cpp
+++ b/services/inputflinger/InputFilter.cpp
@@ -60,6 +60,7 @@
AidlDeviceInfo& aidlInfo = mDeviceInfos.emplace_back();
aidlInfo.deviceId = info.getId();
aidlInfo.external = info.isExternal();
+ aidlInfo.keyboardType = info.getKeyboardType();
}
if (isFilterEnabled()) {
LOG_ALWAYS_FATAL_IF(!mInputFilterRust->notifyInputDevicesChanged(mDeviceInfos).isOk());
@@ -145,6 +146,12 @@
void InputFilter::dump(std::string& dump) {
dump += "InputFilter:\n";
+ if (isFilterEnabled()) {
+ std::string result;
+ LOG_ALWAYS_FATAL_IF(!mInputFilterRust->dumpFilter(&result).isOk());
+ dump += result;
+ dump += "\n";
+ }
}
} // namespace android
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 41e5247..b155122 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -250,6 +250,10 @@
mCollector->dump(dump);
dump += '\n';
}
+ if (ENABLE_INPUT_FILTER_RUST) {
+ mInputFilter->dump(dump);
+ dump += '\n';
+ }
mDispatcher->dump(dump);
dump += '\n';
}
diff --git a/services/inputflinger/aidl/com/android/server/inputflinger/DeviceInfo.aidl b/services/inputflinger/aidl/com/android/server/inputflinger/DeviceInfo.aidl
index b9e6a03..5b0b9ac 100644
--- a/services/inputflinger/aidl/com/android/server/inputflinger/DeviceInfo.aidl
+++ b/services/inputflinger/aidl/com/android/server/inputflinger/DeviceInfo.aidl
@@ -23,4 +23,5 @@
parcelable DeviceInfo {
int deviceId;
boolean external;
+ int keyboardType;
}
\ No newline at end of file
diff --git a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
index 994d1c4..31b7231 100644
--- a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
+++ b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
@@ -54,5 +54,7 @@
/** Notifies when configuration changes */
void notifyConfigurationChanged(in InputFilterConfiguration config);
+
+ String dumpFilter();
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index bcef350..250e72c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -52,6 +52,7 @@
#include "Connection.h"
#include "DebugConfig.h"
#include "InputDispatcher.h"
+#include "InputEventTimeline.h"
#include "trace/InputTracer.h"
#include "trace/InputTracingPerfettoBackend.h"
#include "trace/ThreadedBackend.h"
@@ -4642,10 +4643,9 @@
if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER &&
!mInputFilterEnabled) {
- const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN;
std::set<InputDeviceUsageSource> sources = getUsageSourcesForMotionArgs(args);
- mLatencyTracker.trackListener(args.id, isDown, args.eventTime, args.readTime,
- args.deviceId, sources);
+ mLatencyTracker.trackListener(args.id, args.eventTime, args.readTime, args.deviceId,
+ sources, args.action, InputEventType::MOTION);
}
needWake = enqueueInboundEventLocked(std::move(newEntry));
diff --git a/services/inputflinger/dispatcher/InputEventTimeline.cpp b/services/inputflinger/dispatcher/InputEventTimeline.cpp
index a365003..6881964 100644
--- a/services/inputflinger/dispatcher/InputEventTimeline.cpp
+++ b/services/inputflinger/dispatcher/InputEventTimeline.cpp
@@ -66,15 +66,16 @@
return !operator==(rhs);
}
-InputEventTimeline::InputEventTimeline(bool isDown, nsecs_t eventTime, nsecs_t readTime,
- uint16_t vendorId, uint16_t productId,
- const std::set<InputDeviceUsageSource>& sources)
- : isDown(isDown),
- eventTime(eventTime),
+InputEventTimeline::InputEventTimeline(nsecs_t eventTime, nsecs_t readTime, uint16_t vendorId,
+ uint16_t productId,
+ const std::set<InputDeviceUsageSource>& sources,
+ InputEventActionType inputEventActionType)
+ : eventTime(eventTime),
readTime(readTime),
vendorId(vendorId),
productId(productId),
- sources(sources) {}
+ sources(sources),
+ inputEventActionType(inputEventActionType) {}
bool InputEventTimeline::operator==(const InputEventTimeline& rhs) const {
if (connectionTimelines.size() != rhs.connectionTimelines.size()) {
@@ -89,8 +90,9 @@
return false;
}
}
- return isDown == rhs.isDown && eventTime == rhs.eventTime && readTime == rhs.readTime &&
- vendorId == rhs.vendorId && productId == rhs.productId && sources == rhs.sources;
+ return eventTime == rhs.eventTime && readTime == rhs.readTime && vendorId == rhs.vendorId &&
+ productId == rhs.productId && sources == rhs.sources &&
+ inputEventActionType == rhs.inputEventActionType;
}
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputEventTimeline.h b/services/inputflinger/dispatcher/InputEventTimeline.h
index 1756944..951fcc8 100644
--- a/services/inputflinger/dispatcher/InputEventTimeline.h
+++ b/services/inputflinger/dispatcher/InputEventTimeline.h
@@ -74,15 +74,38 @@
bool mHasGraphicsTimeline = false;
};
+enum class InputEventActionType : int32_t {
+ UNKNOWN_INPUT_EVENT = 0,
+ MOTION_ACTION_DOWN = 1,
+ // Motion events for ACTION_MOVE (characterizes scrolling motion)
+ MOTION_ACTION_MOVE = 2,
+ // Motion events for ACTION_UP (when the pointer first goes up)
+ MOTION_ACTION_UP = 3,
+ // Motion events for ACTION_HOVER_MOVE (pointer position on screen changes but pointer is not
+ // down)
+ MOTION_ACTION_HOVER_MOVE = 4,
+ // Motion events for ACTION_SCROLL (moving the mouse wheel)
+ MOTION_ACTION_SCROLL = 5,
+ // Key events for both ACTION_DOWN and ACTION_UP (key press and key release)
+ KEY = 6,
+
+ ftl_first = UNKNOWN_INPUT_EVENT,
+ ftl_last = KEY,
+ // Used by latency fuzzer
+ kMaxValue = ftl_last
+
+};
+
struct InputEventTimeline {
- InputEventTimeline(bool isDown, nsecs_t eventTime, nsecs_t readTime, uint16_t vendorId,
- uint16_t productId, const std::set<InputDeviceUsageSource>& sources);
- const bool isDown; // True if this is an ACTION_DOWN event
+ InputEventTimeline(nsecs_t eventTime, nsecs_t readTime, uint16_t vendorId, uint16_t productId,
+ const std::set<InputDeviceUsageSource>& sources,
+ InputEventActionType inputEventActionType);
const nsecs_t eventTime;
const nsecs_t readTime;
const uint16_t vendorId;
const uint16_t productId;
const std::set<InputDeviceUsageSource> sources;
+ const InputEventActionType inputEventActionType;
struct IBinderHash {
std::size_t operator()(const sp<IBinder>& b) const {
diff --git a/services/inputflinger/dispatcher/LatencyAggregator.cpp b/services/inputflinger/dispatcher/LatencyAggregator.cpp
index e09d97a..4ddd2e9 100644
--- a/services/inputflinger/dispatcher/LatencyAggregator.cpp
+++ b/services/inputflinger/dispatcher/LatencyAggregator.cpp
@@ -134,7 +134,9 @@
mNumSketchEventsProcessed++;
std::array<std::unique_ptr<KllQuantile>, SketchIndex::SIZE>& sketches =
- timeline.isDown ? mDownSketches : mMoveSketches;
+ timeline.inputEventActionType == InputEventActionType::MOTION_ACTION_DOWN
+ ? mDownSketches
+ : mMoveSketches;
// Process common ones first
const nsecs_t eventToRead = timeline.readTime - timeline.eventTime;
@@ -242,7 +244,9 @@
const nsecs_t consumeToGpuComplete = gpuCompletedTime - connectionTimeline.consumeTime;
const nsecs_t gpuCompleteToPresent = presentTime - gpuCompletedTime;
- android::util::stats_write(android::util::SLOW_INPUT_EVENT_REPORTED, timeline.isDown,
+ android::util::stats_write(android::util::SLOW_INPUT_EVENT_REPORTED,
+ timeline.inputEventActionType ==
+ InputEventActionType::MOTION_ACTION_DOWN,
static_cast<int32_t>(ns2us(eventToRead)),
static_cast<int32_t>(ns2us(readToDeliver)),
static_cast<int32_t>(ns2us(deliverToConsume)),
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index 698bd9f..69024b3 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -67,9 +67,10 @@
LOG_ALWAYS_FATAL_IF(processor == nullptr);
}
-void LatencyTracker::trackListener(int32_t inputEventId, bool isDown, nsecs_t eventTime,
- nsecs_t readTime, DeviceId deviceId,
- const std::set<InputDeviceUsageSource>& sources) {
+void LatencyTracker::trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime,
+ DeviceId deviceId,
+ const std::set<InputDeviceUsageSource>& sources,
+ int32_t inputEventAction, InputEventType inputEventType) {
reportAndPruneMatureRecords(eventTime);
const auto it = mTimelines.find(inputEventId);
if (it != mTimelines.end()) {
@@ -101,9 +102,41 @@
return;
}
+ const InputEventActionType inputEventActionType = [&]() {
+ switch (inputEventType) {
+ case InputEventType::MOTION: {
+ switch (MotionEvent::getActionMasked(inputEventAction)) {
+ case AMOTION_EVENT_ACTION_DOWN:
+ return InputEventActionType::MOTION_ACTION_DOWN;
+ case AMOTION_EVENT_ACTION_MOVE:
+ return InputEventActionType::MOTION_ACTION_MOVE;
+ case AMOTION_EVENT_ACTION_UP:
+ return InputEventActionType::MOTION_ACTION_UP;
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ return InputEventActionType::MOTION_ACTION_HOVER_MOVE;
+ case AMOTION_EVENT_ACTION_SCROLL:
+ return InputEventActionType::MOTION_ACTION_SCROLL;
+ default:
+ return InputEventActionType::UNKNOWN_INPUT_EVENT;
+ }
+ }
+ case InputEventType::KEY: {
+ switch (inputEventAction) {
+ case AKEY_EVENT_ACTION_DOWN:
+ case AKEY_EVENT_ACTION_UP:
+ return InputEventActionType::KEY;
+ default:
+ return InputEventActionType::UNKNOWN_INPUT_EVENT;
+ }
+ }
+ default:
+ return InputEventActionType::UNKNOWN_INPUT_EVENT;
+ }
+ }();
+
mTimelines.emplace(inputEventId,
- InputEventTimeline(isDown, eventTime, readTime, identifier->vendor,
- identifier->product, sources));
+ InputEventTimeline(eventTime, readTime, identifier->vendor,
+ identifier->product, sources, inputEventActionType));
mEventTimes.emplace(eventTime, inputEventId);
}
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index 890d61d..b4053ba 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -52,8 +52,9 @@
* duplicate events that happen to have the same eventTime and inputEventId. Therefore, we
* must drop all duplicate data.
*/
- void trackListener(int32_t inputEventId, bool isDown, nsecs_t eventTime, nsecs_t readTime,
- DeviceId deviceId, const std::set<InputDeviceUsageSource>& sources);
+ void trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime, DeviceId deviceId,
+ const std::set<InputDeviceUsageSource>& sources, int32_t inputEventAction,
+ InputEventType inputEventType);
void trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& connectionToken,
nsecs_t deliveryTime, nsecs_t consumeTime, nsecs_t finishTime);
void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index dbc2872..b17e79a 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -425,7 +425,7 @@
std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent);
if (state) {
if (mTouchpadHardwareStateNotificationsEnabled) {
- getPolicy()->notifyTouchpadHardwareState(*state, rawEvent.deviceId);
+ getPolicy()->notifyTouchpadHardwareState(*state, getDeviceId());
}
updatePalmDetectionMetrics();
return sendHardwareState(rawEvent.when, rawEvent.readTime, *state);
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 9924d0d..da2c683 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -60,6 +60,21 @@
}
}
+bool isGestureNoFocusChange(MotionClassification classification) {
+ switch (classification) {
+ case MotionClassification::TWO_FINGER_SWIPE:
+ case MotionClassification::MULTI_FINGER_SWIPE:
+ case MotionClassification::PINCH:
+ // Most gestures can be performed on an unfocused window, so they should not
+ // not affect window focus.
+ return true;
+ case MotionClassification::NONE:
+ case MotionClassification::AMBIGUOUS_GESTURE:
+ case MotionClassification::DEEP_PRESS:
+ return false;
+ }
+}
+
} // namespace
GestureConverter::GestureConverter(InputReaderContext& readerContext,
@@ -67,6 +82,7 @@
: mDeviceId(deviceId),
mReaderContext(readerContext),
mEnableFlingStop(input_flags::enable_touchpad_fling_stop()),
+ mEnableNoFocusChange(input_flags::enable_touchpad_no_focus_change()),
// We can safely assume that ABS_MT_POSITION_X and _Y axes will be available, as EventHub
// won't classify a device as a touchpad if they're not present.
mXAxisInfo(deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_X).value()),
@@ -338,7 +354,6 @@
NotifyMotionArgs args =
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN, /* actionButton= */ 0,
mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data());
- args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
out.push_back(args);
}
float deltaX = gesture.details.scroll.dx;
@@ -353,7 +368,6 @@
NotifyMotionArgs args =
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /* actionButton= */ 0,
mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data());
- args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
out.push_back(args);
return out;
}
@@ -427,7 +441,6 @@
NotifyMotionArgs args =
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0,
mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data());
- args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
out.push_back(args);
mCurrentClassification = MotionClassification::NONE;
out += enterHover(when, readTime);
@@ -624,6 +637,18 @@
int32_t actionButton, int32_t buttonState,
uint32_t pointerCount,
const PointerCoords* pointerCoords) {
+ int32_t flags = 0;
+ if (action == AMOTION_EVENT_ACTION_CANCEL) {
+ flags |= AMOTION_EVENT_FLAG_CANCELED;
+ }
+ if (mEnableNoFocusChange && isGestureNoFocusChange(mCurrentClassification)) {
+ flags |= AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
+ }
+ if (mCurrentClassification == MotionClassification::TWO_FINGER_SWIPE) {
+ // This helps to make GestureDetector responsive.
+ flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
+ }
+
return {mReaderContext.getNextId(),
when,
readTime,
@@ -633,7 +658,7 @@
/* policyFlags= */ POLICY_FLAG_WAKE,
action,
/* actionButton= */ actionButton,
- /* flags= */ action == AMOTION_EVENT_ACTION_CANCEL ? AMOTION_EVENT_FLAG_CANCELED : 0,
+ flags,
mReaderContext.getGlobalMetaState(),
buttonState,
mCurrentClassification,
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index 829fb92..c9a35c1 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -99,6 +99,7 @@
const int32_t mDeviceId;
InputReaderContext& mReaderContext;
const bool mEnableFlingStop;
+ const bool mEnableNoFocusChange;
std::optional<ui::LogicalDisplayId> mDisplayId;
FloatRect mBoundsInLogicalDisplay{};
diff --git a/services/inputflinger/rust/bounce_keys_filter.rs b/services/inputflinger/rust/bounce_keys_filter.rs
index 2d5039a..e05e8e5 100644
--- a/services/inputflinger/rust/bounce_keys_filter.rs
+++ b/services/inputflinger/rust/bounce_keys_filter.rs
@@ -17,12 +17,13 @@
//! Bounce keys input filter implementation.
//! Bounce keys is an accessibility feature to aid users who have physical disabilities, that
//! allows the user to configure the device to ignore rapid, repeated key presses of the same key.
-use crate::input_filter::Filter;
+use crate::input_filter::{Filter, VIRTUAL_KEYBOARD_DEVICE_ID};
use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
};
+use input::KeyboardType;
use log::debug;
use std::collections::{HashMap, HashSet};
@@ -42,7 +43,7 @@
next: Box<dyn Filter + Send + Sync>,
key_event_map: HashMap<i32, LastUpKeyEvent>,
blocked_events: Vec<BlockedEvent>,
- external_devices: HashSet<i32>,
+ supported_devices: HashSet<i32>,
bounce_key_threshold_ns: i64,
}
@@ -56,7 +57,7 @@
next,
key_event_map: HashMap::new(),
blocked_events: Vec::new(),
- external_devices: HashSet::new(),
+ supported_devices: HashSet::new(),
bounce_key_threshold_ns,
}
}
@@ -64,7 +65,10 @@
impl Filter for BounceKeysFilter {
fn notify_key(&mut self, event: &KeyEvent) {
- if !(self.external_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) {
+ // Check if it is a supported device and event source contains Source::KEYBOARD
+ if !(self.supported_devices.contains(&event.deviceId)
+ && event.source.0 & Source::KEYBOARD.0 != 0)
+ {
self.next.notify_key(event);
return;
}
@@ -110,10 +114,17 @@
self.blocked_events.retain(|blocked_event| {
device_infos.iter().any(|x| blocked_event.device_id == x.deviceId)
});
- self.external_devices.clear();
+ self.supported_devices.clear();
for device_info in device_infos {
- if device_info.external {
- self.external_devices.insert(device_info.deviceId);
+ if device_info.deviceId == VIRTUAL_KEYBOARD_DEVICE_ID {
+ continue;
+ }
+ if device_info.keyboardType == KeyboardType::None as i32 {
+ continue;
+ }
+ // Support Alphabetic keyboards and Non-alphabetic external keyboards
+ if device_info.external || device_info.keyboardType == KeyboardType::Alphabetic as i32 {
+ self.supported_devices.insert(device_info.deviceId);
}
}
self.next.notify_devices_changed(device_infos);
@@ -122,16 +133,26 @@
fn destroy(&mut self) {
self.next.destroy();
}
+
+ fn dump(&mut self, dump_str: String) -> String {
+ let mut result = "Bounce Keys filter: \n".to_string();
+ result += &format!("\tthreshold = {:?}ns\n", self.bounce_key_threshold_ns);
+ result += &format!("\tkey_event_map = {:?}\n", self.key_event_map);
+ result += &format!("\tblocked_events = {:?}\n", self.blocked_events);
+ result += &format!("\tsupported_devices = {:?}\n", self.supported_devices);
+ self.next.dump(dump_str + &result)
+ }
}
#[cfg(test)]
mod tests {
use crate::bounce_keys_filter::BounceKeysFilter;
- use crate::input_filter::{test_filter::TestFilter, Filter};
+ use crate::input_filter::{test_filter::TestFilter, Filter, VIRTUAL_KEYBOARD_DEVICE_ID};
use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
};
+ use input::KeyboardType;
static BASE_KEY_EVENT: KeyEvent = KeyEvent {
id: 1,
@@ -156,6 +177,7 @@
Box::new(next.clone()),
1, /* device_id */
100, /* threshold */
+ KeyboardType::Alphabetic,
);
let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
@@ -181,12 +203,103 @@
}
#[test]
- fn test_is_notify_key_doesnt_block_for_internal_keyboard() {
+ fn test_is_notify_key_for_tv_remote() {
+ let mut next = TestFilter::new();
+ let mut filter = setup_filter_with_external_device(
+ Box::new(next.clone()),
+ 1, /* device_id */
+ 100, /* threshold */
+ KeyboardType::NonAlphabetic,
+ );
+
+ let source = Source(Source::KEYBOARD.0 | Source::DPAD.0);
+ let event = KeyEvent { action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ let event = KeyEvent { action: KeyEventAction::UP, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ next.clear();
+ let event = KeyEvent { action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert!(next.last_event().is_none());
+
+ let event =
+ KeyEvent { eventTime: 100, action: KeyEventAction::UP, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert!(next.last_event().is_none());
+
+ let event =
+ KeyEvent { eventTime: 200, action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+ }
+
+ #[test]
+ fn test_is_notify_key_blocks_for_internal_keyboard() {
+ let mut next = TestFilter::new();
+ let mut filter = setup_filter_with_internal_device(
+ Box::new(next.clone()),
+ 1, /* device_id */
+ 100, /* threshold */
+ KeyboardType::Alphabetic,
+ );
+
+ let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ let event = KeyEvent { action: KeyEventAction::UP, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ next.clear();
+ let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert!(next.last_event().is_none());
+
+ let event = KeyEvent { eventTime: 100, action: KeyEventAction::UP, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert!(next.last_event().is_none());
+
+ let event = KeyEvent { eventTime: 200, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+ }
+
+ #[test]
+ fn test_is_notify_key_doesnt_block_for_internal_non_alphabetic_keyboard() {
let next = TestFilter::new();
let mut filter = setup_filter_with_internal_device(
Box::new(next.clone()),
1, /* device_id */
100, /* threshold */
+ KeyboardType::NonAlphabetic,
+ );
+
+ let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ let event = KeyEvent { action: KeyEventAction::UP, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+ }
+
+ #[test]
+ fn test_is_notify_key_doesnt_block_for_virtual_keyboard() {
+ let next = TestFilter::new();
+ let mut filter = setup_filter_with_internal_device(
+ Box::new(next.clone()),
+ VIRTUAL_KEYBOARD_DEVICE_ID, /* device_id */
+ 100, /* threshold */
+ KeyboardType::Alphabetic,
);
let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
@@ -209,6 +322,7 @@
Box::new(next.clone()),
1, /* device_id */
100, /* threshold */
+ KeyboardType::NonAlphabetic,
);
let event =
@@ -233,12 +347,60 @@
let mut filter = setup_filter_with_devices(
Box::new(next.clone()),
&[
- DeviceInfo { deviceId: 1, external: true },
- DeviceInfo { deviceId: 2, external: true },
+ DeviceInfo {
+ deviceId: 1,
+ external: true,
+ keyboardType: KeyboardType::Alphabetic as i32,
+ },
+ DeviceInfo {
+ deviceId: 2,
+ external: true,
+ keyboardType: KeyboardType::Alphabetic as i32,
+ },
],
100, /* threshold */
);
+ // Bounce key scenario on the external keyboard
+ let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ let event = KeyEvent { deviceId: 1, action: KeyEventAction::UP, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+
+ next.clear();
+ let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert!(next.last_event().is_none());
+
+ let event = KeyEvent { deviceId: 2, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+ filter.notify_key(&event);
+ assert_eq!(next.last_event().unwrap(), event);
+ }
+
+ #[test]
+ fn test_is_notify_key_for_external_and_internal_alphabetic_keyboards() {
+ let mut next = TestFilter::new();
+ let mut filter = setup_filter_with_devices(
+ Box::new(next.clone()),
+ &[
+ DeviceInfo {
+ deviceId: 1,
+ external: false,
+ keyboardType: KeyboardType::Alphabetic as i32,
+ },
+ DeviceInfo {
+ deviceId: 2,
+ external: true,
+ keyboardType: KeyboardType::Alphabetic as i32,
+ },
+ ],
+ 100, /* threshold */
+ );
+
+ // Bounce key scenario on the internal keyboard
let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
filter.notify_key(&event);
assert_eq!(next.last_event().unwrap(), event);
@@ -261,10 +423,15 @@
next: Box<dyn Filter + Send + Sync>,
device_id: i32,
threshold: i64,
+ keyboard_type: KeyboardType,
) -> BounceKeysFilter {
setup_filter_with_devices(
next,
- &[DeviceInfo { deviceId: device_id, external: true }],
+ &[DeviceInfo {
+ deviceId: device_id,
+ external: true,
+ keyboardType: keyboard_type as i32,
+ }],
threshold,
)
}
@@ -273,10 +440,15 @@
next: Box<dyn Filter + Send + Sync>,
device_id: i32,
threshold: i64,
+ keyboard_type: KeyboardType,
) -> BounceKeysFilter {
setup_filter_with_devices(
next,
- &[DeviceInfo { deviceId: device_id, external: false }],
+ &[DeviceInfo {
+ deviceId: device_id,
+ external: false,
+ keyboardType: keyboard_type as i32,
+ }],
threshold,
)
}
diff --git a/services/inputflinger/rust/input_filter.rs b/services/inputflinger/rust/input_filter.rs
index 8b44af3..e221244 100644
--- a/services/inputflinger/rust/input_filter.rs
+++ b/services/inputflinger/rust/input_filter.rs
@@ -35,11 +35,15 @@
use log::{error, info};
use std::sync::{Arc, Mutex, RwLock};
+/// Virtual keyboard device ID
+pub const VIRTUAL_KEYBOARD_DEVICE_ID: i32 = -1;
+
/// Interface for all the sub input filters
pub trait Filter {
fn notify_key(&mut self, event: &KeyEvent);
fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]);
fn destroy(&mut self);
+ fn dump(&mut self, dump_str: String) -> String;
}
struct InputFilterState {
@@ -119,18 +123,30 @@
self.input_filter_thread.clone(),
));
state.enabled = true;
- info!("Slow keys filter is installed");
+ info!(
+ "Slow keys filter is installed, threshold = {:?}ns",
+ config.slowKeysThresholdNs
+ );
}
if config.bounceKeysThresholdNs > 0 {
first_filter =
Box::new(BounceKeysFilter::new(first_filter, config.bounceKeysThresholdNs));
state.enabled = true;
- info!("Bounce keys filter is installed");
+ info!(
+ "Bounce keys filter is installed, threshold = {:?}ns",
+ config.bounceKeysThresholdNs
+ );
}
state.first_filter = first_filter;
}
Result::Ok(())
}
+
+ fn dumpFilter(&self) -> binder::Result<String> {
+ let first_filter = &mut self.state.lock().unwrap().first_filter;
+ let dump_str = first_filter.dump(String::new());
+ Result::Ok(dump_str)
+ }
}
struct BaseFilter {
@@ -158,6 +174,11 @@
fn destroy(&mut self) {
// do nothing
}
+
+ fn dump(&mut self, dump_str: String) -> String {
+ // do nothing
+ dump_str
+ }
}
/// This struct wraps around IInputFilterCallbacks restricting access to only
@@ -214,6 +235,7 @@
InputFilterConfiguration::InputFilterConfiguration, KeyEvent::KeyEvent,
KeyEventAction::KeyEventAction,
};
+ use input::KeyboardType;
use std::sync::{Arc, RwLock};
#[test]
@@ -256,7 +278,11 @@
Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks)))),
);
assert!(input_filter
- .notifyInputDevicesChanged(&[DeviceInfo { deviceId: 0, external: true }])
+ .notifyInputDevicesChanged(&[DeviceInfo {
+ deviceId: 0,
+ external: true,
+ keyboardType: KeyboardType::None as i32
+ }])
.is_ok());
assert!(test_filter.is_device_changed_called());
}
@@ -389,6 +415,10 @@
fn destroy(&mut self) {
self.inner().is_destroy_called = true;
}
+ fn dump(&mut self, dump_str: String) -> String {
+ // do nothing
+ dump_str
+ }
}
}
diff --git a/services/inputflinger/rust/slow_keys_filter.rs b/services/inputflinger/rust/slow_keys_filter.rs
index 0f18a2f..8830aac 100644
--- a/services/inputflinger/rust/slow_keys_filter.rs
+++ b/services/inputflinger/rust/slow_keys_filter.rs
@@ -18,12 +18,13 @@
//! Slow keys is an accessibility feature to aid users who have physical disabilities, that allows
//! the user to specify the duration for which one must press-and-hold a key before the system
//! accepts the keypress.
-use crate::input_filter::Filter;
+use crate::input_filter::{Filter, VIRTUAL_KEYBOARD_DEVICE_ID};
use crate::input_filter_thread::{InputFilterThread, ThreadCallback};
use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
};
+use input::KeyboardType;
use log::debug;
use std::collections::HashSet;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
@@ -41,7 +42,7 @@
struct SlowKeysFilterInner {
next: Box<dyn Filter + Send + Sync>,
slow_key_threshold_ns: i64,
- external_devices: HashSet<i32>,
+ supported_devices: HashSet<i32>,
// This tracks KeyEvents that are blocked by Slow keys filter and will be passed through if the
// press duration exceeds the slow keys threshold.
pending_down_events: Vec<KeyEvent>,
@@ -65,7 +66,7 @@
let filter = Self(Arc::new(RwLock::new(SlowKeysFilterInner {
next,
slow_key_threshold_ns,
- external_devices: HashSet::new(),
+ supported_devices: HashSet::new(),
pending_down_events: Vec::new(),
ongoing_down_events: Vec::new(),
input_filter_thread: input_filter_thread.clone(),
@@ -98,8 +99,8 @@
{
// acquire write lock
let mut slow_filter = self.write_inner();
- if !(slow_filter.external_devices.contains(&event.deviceId)
- && event.source == Source::KEYBOARD)
+ if !(slow_filter.supported_devices.contains(&event.deviceId)
+ && event.source.0 & Source::KEYBOARD.0 != 0)
{
slow_filter.next.notify_key(event);
return;
@@ -164,10 +165,17 @@
slow_filter
.ongoing_down_events
.retain(|event| device_infos.iter().any(|x| event.device_id == x.deviceId));
- slow_filter.external_devices.clear();
+ slow_filter.supported_devices.clear();
for device_info in device_infos {
- if device_info.external {
- slow_filter.external_devices.insert(device_info.deviceId);
+ if device_info.deviceId == VIRTUAL_KEYBOARD_DEVICE_ID {
+ continue;
+ }
+ if device_info.keyboardType == KeyboardType::None as i32 {
+ continue;
+ }
+ // Support Alphabetic keyboards and Non-alphabetic external keyboards
+ if device_info.external || device_info.keyboardType == KeyboardType::Alphabetic as i32 {
+ slow_filter.supported_devices.insert(device_info.deviceId);
}
}
slow_filter.next.notify_devices_changed(device_infos);
@@ -178,6 +186,16 @@
slow_filter.input_filter_thread.unregister_thread_callback(Box::new(self.clone()));
slow_filter.next.destroy();
}
+
+ fn dump(&mut self, dump_str: String) -> String {
+ let mut slow_filter = self.write_inner();
+ let mut result = "Slow Keys filter: \n".to_string();
+ result += &format!("\tthreshold = {:?}ns\n", slow_filter.slow_key_threshold_ns);
+ result += &format!("\tongoing_down_events = {:?}\n", slow_filter.ongoing_down_events);
+ result += &format!("\tpending_down_events = {:?}\n", slow_filter.pending_down_events);
+ result += &format!("\tsupported_devices = {:?}\n", slow_filter.supported_devices);
+ slow_filter.next.dump(dump_str + &result)
+ }
}
impl ThreadCallback for SlowKeysFilter {
@@ -217,6 +235,7 @@
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
};
+ use input::KeyboardType;
use nix::{sys::time::TimeValLike, time::clock_gettime, time::ClockId};
use std::sync::{Arc, RwLock};
use std::time::Duration;
@@ -240,7 +259,7 @@
static SLOW_KEYS_THRESHOLD_NS: i64 = 100 * 1000000; // 100 ms
#[test]
- fn test_is_notify_key_for_internal_keyboard_not_blocked() {
+ fn test_is_notify_key_for_internal_non_alphabetic_keyboard_not_blocked() {
let test_callbacks = TestCallbacks::new();
let test_thread = get_thread(test_callbacks.clone());
let next = TestFilter::new();
@@ -249,6 +268,7 @@
test_thread.clone(),
1, /* device_id */
SLOW_KEYS_THRESHOLD_NS,
+ KeyboardType::NonAlphabetic,
);
let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
@@ -266,6 +286,7 @@
test_thread.clone(),
1, /* device_id */
SLOW_KEYS_THRESHOLD_NS,
+ KeyboardType::NonAlphabetic,
);
let event =
@@ -275,6 +296,115 @@
}
#[test]
+ fn test_notify_key_for_tv_remote_when_key_pressed_for_threshold_time() {
+ let test_callbacks = TestCallbacks::new();
+ let test_thread = get_thread(test_callbacks.clone());
+ let next = TestFilter::new();
+ let mut filter = setup_filter_with_external_device(
+ Box::new(next.clone()),
+ test_thread.clone(),
+ 1, /* device_id */
+ SLOW_KEYS_THRESHOLD_NS,
+ KeyboardType::NonAlphabetic,
+ );
+ let down_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
+ let source = Source(Source::KEYBOARD.0 | Source::DPAD.0);
+ filter.notify_key(&KeyEvent {
+ action: KeyEventAction::DOWN,
+ downTime: down_time,
+ eventTime: down_time,
+ source,
+ ..BASE_KEY_EVENT
+ });
+ assert!(next.last_event().is_none());
+
+ std::thread::sleep(Duration::from_nanos(2 * SLOW_KEYS_THRESHOLD_NS as u64));
+ assert_eq!(
+ next.last_event().unwrap(),
+ KeyEvent {
+ action: KeyEventAction::DOWN,
+ downTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ eventTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ source,
+ policyFlags: POLICY_FLAG_DISABLE_KEY_REPEAT,
+ ..BASE_KEY_EVENT
+ }
+ );
+
+ let up_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
+ filter.notify_key(&KeyEvent {
+ action: KeyEventAction::UP,
+ downTime: down_time,
+ eventTime: up_time,
+ source,
+ ..BASE_KEY_EVENT
+ });
+
+ assert_eq!(
+ next.last_event().unwrap(),
+ KeyEvent {
+ action: KeyEventAction::UP,
+ downTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ eventTime: up_time,
+ source,
+ ..BASE_KEY_EVENT
+ }
+ );
+ }
+
+ #[test]
+ fn test_notify_key_for_internal_alphabetic_keyboard_when_key_pressed_for_threshold_time() {
+ let test_callbacks = TestCallbacks::new();
+ let test_thread = get_thread(test_callbacks.clone());
+ let next = TestFilter::new();
+ let mut filter = setup_filter_with_internal_device(
+ Box::new(next.clone()),
+ test_thread.clone(),
+ 1, /* device_id */
+ SLOW_KEYS_THRESHOLD_NS,
+ KeyboardType::Alphabetic,
+ );
+ let down_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
+ filter.notify_key(&KeyEvent {
+ action: KeyEventAction::DOWN,
+ downTime: down_time,
+ eventTime: down_time,
+ ..BASE_KEY_EVENT
+ });
+ assert!(next.last_event().is_none());
+
+ std::thread::sleep(Duration::from_nanos(2 * SLOW_KEYS_THRESHOLD_NS as u64));
+ assert_eq!(
+ next.last_event().unwrap(),
+ KeyEvent {
+ action: KeyEventAction::DOWN,
+ downTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ eventTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ policyFlags: POLICY_FLAG_DISABLE_KEY_REPEAT,
+ ..BASE_KEY_EVENT
+ }
+ );
+
+ let up_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
+ filter.notify_key(&KeyEvent {
+ action: KeyEventAction::UP,
+ downTime: down_time,
+ eventTime: up_time,
+ ..BASE_KEY_EVENT
+ });
+
+ assert_eq!(
+ next.last_event().unwrap(),
+ KeyEvent {
+ action: KeyEventAction::UP,
+ downTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+ eventTime: up_time,
+ ..BASE_KEY_EVENT
+ }
+ );
+ }
+
+ #[test]
fn test_notify_key_for_external_keyboard_when_key_pressed_for_threshold_time() {
let test_callbacks = TestCallbacks::new();
let test_thread = get_thread(test_callbacks.clone());
@@ -284,6 +414,7 @@
test_thread.clone(),
1, /* device_id */
SLOW_KEYS_THRESHOLD_NS,
+ KeyboardType::Alphabetic,
);
let down_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
filter.notify_key(&KeyEvent {
@@ -335,6 +466,7 @@
test_thread.clone(),
1, /* device_id */
SLOW_KEYS_THRESHOLD_NS,
+ KeyboardType::Alphabetic,
);
let mut now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
filter.notify_key(&KeyEvent {
@@ -367,6 +499,7 @@
test_thread.clone(),
1, /* device_id */
SLOW_KEYS_THRESHOLD_NS,
+ KeyboardType::Alphabetic,
);
let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
@@ -388,11 +521,16 @@
test_thread: InputFilterThread,
device_id: i32,
threshold: i64,
+ keyboard_type: KeyboardType,
) -> SlowKeysFilter {
setup_filter_with_devices(
next,
test_thread,
- &[DeviceInfo { deviceId: device_id, external: true }],
+ &[DeviceInfo {
+ deviceId: device_id,
+ external: true,
+ keyboardType: keyboard_type as i32,
+ }],
threshold,
)
}
@@ -402,11 +540,16 @@
test_thread: InputFilterThread,
device_id: i32,
threshold: i64,
+ keyboard_type: KeyboardType,
) -> SlowKeysFilter {
setup_filter_with_devices(
next,
test_thread,
- &[DeviceInfo { deviceId: device_id, external: false }],
+ &[DeviceInfo {
+ deviceId: device_id,
+ external: false,
+ keyboardType: keyboard_type as i32,
+ }],
threshold,
)
}
diff --git a/services/inputflinger/rust/sticky_keys_filter.rs b/services/inputflinger/rust/sticky_keys_filter.rs
index 6c7c7fb..161a5fc 100644
--- a/services/inputflinger/rust/sticky_keys_filter.rs
+++ b/services/inputflinger/rust/sticky_keys_filter.rs
@@ -134,6 +134,14 @@
fn destroy(&mut self) {
self.next.destroy();
}
+
+ fn dump(&mut self, dump_str: String) -> String {
+ let mut result = "Sticky Keys filter: \n".to_string();
+ result += &format!("\tmodifier_state = {:?}\n", self.modifier_state);
+ result += &format!("\tlocked_modifier_state = {:?}\n", self.locked_modifier_state);
+ result += &format!("\tcontributing_devices = {:?}\n", self.contributing_devices);
+ self.next.dump(dump_str + &result)
+ }
}
fn is_modifier_key(keycode: i32) -> bool {
@@ -235,6 +243,7 @@
DeviceInfo::DeviceInfo, IInputFilter::IInputFilterCallbacks::IInputFilterCallbacks,
KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
};
+ use input::KeyboardType;
use input::ModifierState;
use std::sync::{Arc, RwLock};
@@ -496,7 +505,11 @@
..BASE_KEY_UP
});
- sticky_keys_filter.notify_devices_changed(&[DeviceInfo { deviceId: 2, external: true }]);
+ sticky_keys_filter.notify_devices_changed(&[DeviceInfo {
+ deviceId: 2,
+ external: true,
+ keyboardType: KeyboardType::Alphabetic as i32,
+ }]);
assert_eq!(
test_callbacks.get_last_modifier_state(),
ModifierState::CtrlLeftOn | ModifierState::CtrlOn
diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
index b738abf..f20c43c 100644
--- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
+++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
@@ -35,6 +35,9 @@
namespace android {
using testing::AllOf;
+using testing::Each;
+using testing::ElementsAre;
+using testing::VariantWith;
class CapturedTouchpadEventConverterTest : public testing::Test {
public:
@@ -246,14 +249,14 @@
processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(52, 99), WithToolType(ToolType::FINGER)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithPointerCount(1u),
- WithCoords(52, 99), WithToolType(ToolType::FINGER)));
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_UP))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(52, 99), WithPointerCount(1u),
+ WithToolType(ToolType::FINGER)))));
}
TEST_F(CapturedTouchpadEventConverterTest, OneFinger_touchDimensionsPassedThrough) {
@@ -572,17 +575,17 @@
processAxis(conv, EV_KEY, BTN_TOUCH, 1);
processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
- std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithToolType(ToolType::FINGER)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCount(2u), WithPointerToolType(0, ToolType::FINGER),
- WithPointerToolType(1, ToolType::FINGER)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithPointerCount(1u), WithToolType(ToolType::FINGER))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerCount(2u),
+ WithPointerToolType(0, ToolType::FINGER),
+ WithPointerToolType(1, ToolType::FINGER)))));
processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);
@@ -591,15 +594,16 @@
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 251);
processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
- args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithFlags(AMOTION_EVENT_FLAG_CANCELED), WithPointerCount(2u)));
+ std::list<NotifyArgs> args = processSync(conv);
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithFlags(AMOTION_EVENT_FLAG_CANCELED)))));
+ EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithPointerCount(2u))));
}
TEST_F(CapturedTouchpadEventConverterTest, FingerAndPalmTurningIntoFinger_reported) {
@@ -632,15 +636,15 @@
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 251);
processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
- std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCount(2u)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
+ WithPointerCount(1u))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerCount(2u)))));
}
TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) {
@@ -670,18 +674,19 @@
processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
- std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(52, 99), WithToolType(ToolType::FINGER)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCount(2u), WithPointerCoords(0, 52, 99),
- WithPointerCoords(1, 250, 200), WithPointerToolType(0, ToolType::FINGER),
- WithPointerToolType(1, ToolType::FINGER)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
+ WithPointerCount(1u), WithCoords(52, 99),
+ WithToolType(ToolType::FINGER))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerCount(2u), WithPointerCoords(0, 52, 99),
+ WithPointerCoords(1, 250, 200),
+ WithPointerToolType(0, ToolType::FINGER),
+ WithPointerToolType(1, ToolType::FINGER)))));
processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
@@ -692,34 +697,33 @@
processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
- args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u),
- WithPointerCoords(0, 52, 99), WithPointerCoords(1, 255, 202),
- WithPointerToolType(1, ToolType::FINGER),
- WithPointerToolType(0, ToolType::FINGER)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP |
- 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCount(2u), WithPointerCoords(0, 52, 99),
- WithPointerCoords(1, 255, 202), WithPointerToolType(0, ToolType::FINGER),
- WithPointerToolType(1, ToolType::FINGER)));
+ std::list<NotifyArgs> args = processSync(conv);
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithPointerCount(2u), WithPointerCoords(0, 52, 99),
+ WithPointerCoords(1, 255, 202),
+ WithPointerToolType(1, ToolType::FINGER),
+ WithPointerToolType(0, ToolType::FINGER)))));
processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
processAxis(conv, EV_KEY, BTN_TOUCH, 0);
args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(255, 202), WithToolType(ToolType::FINGER)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithPointerCount(1u),
- WithCoords(255, 202), WithToolType(ToolType::FINGER)));
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_UP))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithPointerCount(1u), WithCoords(255, 202),
+ WithToolType(ToolType::FINGER)))));
}
// Pointer IDs max out at 31, and so must be reused once a touch is lifted to avoid running out.
@@ -737,17 +741,18 @@
processAxis(conv, EV_KEY, BTN_TOUCH, 1);
processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
- std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithPointerId(/*index=*/0, /*id=*/0)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCount(2u), WithPointerId(/*index=*/0, /*id=*/0),
- WithPointerId(/*index=*/1, /*id=*/1)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithPointerCount(1u),
+ WithPointerId(/*index=*/0, /*id=*/0))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerCount(2u),
+ WithPointerId(/*index=*/0, /*id=*/0),
+ WithPointerId(/*index=*/1, /*id=*/1)))));
// Lift the finger in slot 0, freeing up pointer ID 0...
processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
@@ -758,27 +763,30 @@
processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 3);
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 30);
- args = processSync(conv);
- ASSERT_EQ(3u, args.size());
+ std::list<NotifyArgs> args = processSync(conv);
// Slot 1 being present will result in a MOVE event, even though it hasn't actually moved (see
// comments in CapturedTouchpadEventConverter::sync).
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u),
- WithPointerId(/*index=*/0, /*id=*/0), WithPointerId(/*index=*/1, /*id=*/1)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP |
- 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCount(2u), WithPointerId(/*index=*/0, /*id=*/0),
- WithPointerId(/*index=*/1, /*id=*/1)));
- args.pop_front();
- // Slot 0 being lifted causes the finger from slot 1 to move up to index 0, but keep its
- // previous ID. The new finger in slot 2 should take ID 0, which was just freed up.
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCount(2u), WithPointerId(/*index=*/0, /*id=*/1),
- WithPointerId(/*index=*/1, /*id=*/0)));
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
+ WithPointerId(/*index=*/0, /*id=*/0),
+ WithPointerId(/*index=*/1, /*id=*/1))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerId(/*index=*/0, /*id=*/0),
+ WithPointerId(/*index=*/1, /*id=*/1))),
+ // Slot 0 being lifted causes the finger from slot 1 to move up to index
+ // 0, but keep its previous ID. The new finger in slot 2 should take ID
+ // 0, which was just freed up.
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerId(/*index=*/0, /*id=*/1),
+ WithPointerId(/*index=*/1, /*id=*/0)))));
+ EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithPointerCount(2u))));
}
// Motion events without any pointers are invalid, so when a button press is reported in the same
@@ -797,33 +805,30 @@
processAxis(conv, EV_KEY, BTN_LEFT, 1);
- std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u),
- WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ WithPointerCount(1u), WithCoords(50, 100),
+ WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))));
processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
processAxis(conv, EV_KEY, BTN_TOUCH, 0);
processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
processAxis(conv, EV_KEY, BTN_LEFT, 0);
- args = processSync(conv);
- ASSERT_EQ(3u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u),
- WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(0)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_UP));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
+ WithPointerCount(1u), WithCoords(50, 100),
+ WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(0))),
+ VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_UP))));
}
// Some touchpads sometimes report a button press before they report the finger touching the pad. In
@@ -841,15 +846,14 @@
processAxis(conv, EV_KEY, BTN_TOUCH, 1);
processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
- std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u),
- WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ WithPointerCount(1u), WithCoords(50, 100),
+ WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))));
}
// When all fingers are lifted from a touchpad, we should release any buttons that are down, since
@@ -866,29 +870,25 @@
processAxis(conv, EV_KEY, BTN_LEFT, 1);
- std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)),
+ VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS))));
processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
processAxis(conv, EV_KEY, BTN_TOUCH, 0);
processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
- args = processSync(conv);
- ASSERT_EQ(3u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u),
- WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(0)));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_UP));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
+ WithPointerCount(1u), WithCoords(50, 100),
+ WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(0))),
+ VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_UP))));
processAxis(conv, EV_KEY, BTN_LEFT, 0);
ASSERT_EQ(0u, processSync(conv).size());
@@ -908,48 +908,41 @@
WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
processAxis(conv, EV_KEY, BTN_LEFT, 1);
- std::list<NotifyArgs> args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))));
processAxis(conv, EV_KEY, BTN_RIGHT, 1);
- args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY |
- AMOTION_EVENT_BUTTON_SECONDARY)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY |
+ AMOTION_EVENT_BUTTON_SECONDARY)))));
processAxis(conv, EV_KEY, BTN_LEFT, 0);
- args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
+ WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY)))));
processAxis(conv, EV_KEY, BTN_RIGHT, 0);
- args = processSync(conv);
- ASSERT_EQ(2u, args.size());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
- args.pop_front();
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0)));
+ EXPECT_THAT(processSync(conv),
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
+ WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY),
+ WithButtonState(0)))));
}
} // namespace android
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
index d77d539..e1f844c 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -32,19 +32,23 @@
} // namespace
void FakeInputReaderPolicy::assertInputDevicesChanged() {
- waitForInputDevices([](bool devicesChanged) {
- if (!devicesChanged) {
- FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
- }
- });
+ waitForInputDevices(
+ [](bool devicesChanged) {
+ if (!devicesChanged) {
+ FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
+ }
+ },
+ ADD_INPUT_DEVICE_TIMEOUT);
}
void FakeInputReaderPolicy::assertInputDevicesNotChanged() {
- waitForInputDevices([](bool devicesChanged) {
- if (devicesChanged) {
- FAIL() << "Expected notifyInputDevicesChanged() to not be called.";
- }
- });
+ waitForInputDevices(
+ [](bool devicesChanged) {
+ if (devicesChanged) {
+ FAIL() << "Expected notifyInputDevicesChanged() to not be called.";
+ }
+ },
+ INPUT_DEVICES_DIDNT_CHANGE_TIMEOUT);
}
void FakeInputReaderPolicy::assertStylusGestureNotified(int32_t deviceId) {
@@ -261,13 +265,13 @@
return "";
}
-void FakeInputReaderPolicy::waitForInputDevices(std::function<void(bool)> processDevicesChanged) {
+void FakeInputReaderPolicy::waitForInputDevices(std::function<void(bool)> processDevicesChanged,
+ std::chrono::milliseconds timeout) {
std::unique_lock<std::mutex> lock(mLock);
base::ScopedLockAssertion assumeLocked(mLock);
const bool devicesChanged =
- mDevicesChangedCondition.wait_for(lock,
- ADD_INPUT_DEVICE_TIMEOUT * HW_TIMEOUT_MULTIPLIER,
+ mDevicesChangedCondition.wait_for(lock, timeout * HW_TIMEOUT_MULTIPLIER,
[this]() REQUIRES(mLock) {
return mInputDevicesChanged;
});
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h
index e5ba620..61bb9fc 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.h
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.h
@@ -88,7 +88,8 @@
std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override;
std::string getDeviceAlias(const InputDeviceIdentifier&) override;
- void waitForInputDevices(std::function<void(bool)> processDevicesChanged);
+ void waitForInputDevices(std::function<void(bool)> processDevicesChanged,
+ std::chrono::milliseconds timeout);
void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override;
mutable std::mutex mLock;
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index d0cd677..225ae0f 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -279,6 +279,8 @@
}
TEST_F(GestureConverterTest, Scroll) {
+ input_flags::enable_touchpad_no_focus_change(true);
+
const nsecs_t downTime = 12345;
InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
@@ -300,7 +302,8 @@
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE),
+ WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE |
+ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
WithToolType(ToolType::FINGER),
WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
@@ -312,7 +315,8 @@
WithGestureScrollDistance(0, 5, EPSILON),
WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
WithToolType(ToolType::FINGER),
- WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE),
+ WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE |
+ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
@@ -325,7 +329,8 @@
WithGestureScrollDistance(0, 0, EPSILON),
WithMotionClassification(
MotionClassification::TWO_FINGER_SWIPE),
- WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))),
+ WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE |
+ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
WithCoords(0, 0),
@@ -845,6 +850,8 @@
}
TEST_F(GestureConverterTest, Pinch_Inwards) {
+ input_flags::enable_touchpad_no_focus_change(true);
+
InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
@@ -867,7 +874,8 @@
AllOf(WithMotionClassification(MotionClassification::PINCH),
WithGesturePinchScaleFactor(1.0f, EPSILON),
WithToolType(ToolType::FINGER),
- WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)))));
Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
/* dz= */ 0.8, GESTURES_ZOOM_UPDATE);
@@ -879,7 +887,8 @@
WithGesturePinchScaleFactor(0.8f, EPSILON),
WithPointerCoords(0, -80, 0), WithPointerCoords(1, 80, 0),
WithPointerCount(2u), WithToolType(ToolType::FINGER),
- WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)))));
Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
GESTURES_ZOOM_END);
@@ -891,12 +900,14 @@
1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
WithMotionClassification(MotionClassification::PINCH),
WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(2u))),
+ WithPointerCount(2u),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
WithMotionClassification(MotionClassification::PINCH),
WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(1u))),
+ WithPointerCount(1u),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
WithCoords(0, 0),
@@ -908,6 +919,8 @@
}
TEST_F(GestureConverterTest, Pinch_Outwards) {
+ input_flags::enable_touchpad_no_focus_change(true);
+
InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
@@ -930,7 +943,8 @@
AllOf(WithMotionClassification(MotionClassification::PINCH),
WithGesturePinchScaleFactor(1.0f, EPSILON),
WithToolType(ToolType::FINGER),
- WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)))));
Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
/* dz= */ 1.1, GESTURES_ZOOM_UPDATE);
@@ -942,7 +956,8 @@
WithGesturePinchScaleFactor(1.1f, EPSILON),
WithPointerCoords(0, -110, 0), WithPointerCoords(1, 110, 0),
WithPointerCount(2u), WithToolType(ToolType::FINGER),
- WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)))));
Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
GESTURES_ZOOM_END);
@@ -954,12 +969,14 @@
1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
WithMotionClassification(MotionClassification::PINCH),
WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(2u))),
+ WithPointerCount(2u),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
WithMotionClassification(MotionClassification::PINCH),
WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(1u))),
+ WithPointerCount(1u),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
WithCoords(0, 0),
@@ -1055,6 +1072,8 @@
}
TEST_F(GestureConverterTest, ResetDuringScroll) {
+ input_flags::enable_touchpad_no_focus_change(true);
+
InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
@@ -1070,7 +1089,8 @@
WithGestureScrollDistance(0, 0, EPSILON),
WithMotionClassification(
MotionClassification::TWO_FINGER_SWIPE),
- WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))),
+ WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE |
+ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
WithCoords(0, 0),
diff --git a/services/inputflinger/tests/InputTracingTest.cpp b/services/inputflinger/tests/InputTracingTest.cpp
index 2ccd93e..3cc4bdd 100644
--- a/services/inputflinger/tests/InputTracingTest.cpp
+++ b/services/inputflinger/tests/InputTracingTest.cpp
@@ -133,8 +133,8 @@
mDispatcher->setFocusedWindow(request);
}
- void tapAndExpect(const std::vector<const sp<FakeWindowHandle>>& windows,
- Level inboundTraceLevel, Level dispatchTraceLevel, InputTraceSession& s) {
+ void tapAndExpect(const std::vector<sp<FakeWindowHandle>>& windows, Level inboundTraceLevel,
+ Level dispatchTraceLevel, InputTraceSession& s) {
const auto down = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(110))
.build();
@@ -156,7 +156,7 @@
}
}
- void keypressAndExpect(const std::vector<const sp<FakeWindowHandle>>& windows,
+ void keypressAndExpect(const std::vector<sp<FakeWindowHandle>>& windows,
Level inboundTraceLevel, Level dispatchTraceLevel,
InputTraceSession& s) {
const auto down = KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build();
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index 4fcffdd..0f92833 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -61,12 +61,12 @@
InputEventTimeline getTestTimeline() {
InputEventTimeline t(
- /*isDown=*/true,
/*eventTime=*/2,
/*readTime=*/3,
/*vendorId=*/0,
/*productId=*/0,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN});
+ /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT);
ConnectionTimeline expectedCT(/*deliveryTime=*/6, /*consumeTime=*/7, /*finishTime=*/8);
std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 9;
@@ -116,9 +116,10 @@
void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
const nsecs_t triggerEventTime =
lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
- mTracker->trackListener(/*inputEventId=*/1, /*isDown=*/true, triggerEventTime,
+ mTracker->trackListener(/*inputEventId=*/1, triggerEventTime,
/*readTime=*/3, DEVICE_ID,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN});
+ /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION);
}
void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
@@ -167,12 +168,15 @@
* any additional ConnectionTimeline's.
*/
TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
- mTracker->trackListener(/*inputEventId=*/1, /*isDown=*/false, /*eventTime=*/2,
- /*readTime=*/3, DEVICE_ID, {InputDeviceUsageSource::UNKNOWN});
+ mTracker->trackListener(/*inputEventId=*/1, /*eventTime=*/2,
+ /*readTime=*/3, DEVICE_ID, {InputDeviceUsageSource::UNKNOWN},
+ AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION);
triggerEventReporting(/*eventTime=*/2);
- assertReceivedTimeline(InputEventTimeline{/*isDown=*/false, /*eventTime=*/2,
- /*readTime=*/3, /*vendorId=*/0, /*productID=*/0,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN}});
+ assertReceivedTimeline(
+ InputEventTimeline{/*eventTime=*/2,
+ /*readTime=*/3, /*vendorId=*/0, /*productID=*/0,
+ /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT});
}
/**
@@ -203,8 +207,9 @@
const auto& [connectionToken, expectedCT] = *expected.connectionTimelines.begin();
- mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime,
- DEVICE_ID, {InputDeviceUsageSource::UNKNOWN});
+ mTracker->trackListener(inputEventId, expected.eventTime, expected.readTime, DEVICE_ID,
+ {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
+ InputEventType::MOTION);
mTracker->trackFinishedEvent(inputEventId, connectionToken, expectedCT.deliveryTime,
expectedCT.consumeTime, expectedCT.finishTime);
mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);
@@ -220,14 +225,15 @@
TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) {
constexpr nsecs_t inputEventId = 1;
constexpr nsecs_t readTime = 3; // does not matter for this test
- constexpr bool isDown = true; // does not matter for this test
// In the following 2 calls to trackListener, the inputEventId's are the same, but event times
// are different.
- mTracker->trackListener(inputEventId, isDown, /*eventTime=*/1, readTime, DEVICE_ID,
- {InputDeviceUsageSource::UNKNOWN});
- mTracker->trackListener(inputEventId, isDown, /*eventTime=*/2, readTime, DEVICE_ID,
- {InputDeviceUsageSource::UNKNOWN});
+ mTracker->trackListener(inputEventId, /*eventTime=*/1, readTime, DEVICE_ID,
+ {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
+ InputEventType::MOTION);
+ mTracker->trackListener(inputEventId, /*eventTime=*/2, readTime, DEVICE_ID,
+ {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
+ InputEventType::MOTION);
triggerEventReporting(/*eventTime=*/2);
// Since we sent duplicate input events, the tracker should just delete all of them, because it
@@ -238,12 +244,12 @@
TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
constexpr int32_t inputEventId1 = 1;
InputEventTimeline timeline1(
- /*isDown*/ true,
/*eventTime*/ 2,
/*readTime*/ 3,
/*vendorId=*/0,
/*productId=*/0,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN});
+ /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ /*inputEventType=*/InputEventActionType::UNKNOWN_INPUT_EVENT);
timeline1.connectionTimelines.emplace(connection1,
ConnectionTimeline(/*deliveryTime*/ 6, /*consumeTime*/ 7,
/*finishTime*/ 8));
@@ -255,12 +261,12 @@
constexpr int32_t inputEventId2 = 10;
InputEventTimeline timeline2(
- /*isDown=*/false,
/*eventTime=*/20,
/*readTime=*/30,
/*vendorId=*/0,
/*productId=*/0,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN});
+ /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT);
timeline2.connectionTimelines.emplace(connection2,
ConnectionTimeline(/*deliveryTime=*/60,
/*consumeTime=*/70,
@@ -272,11 +278,13 @@
connectionTimeline2.setGraphicsTimeline(std::move(graphicsTimeline2));
// Start processing first event
- mTracker->trackListener(inputEventId1, timeline1.isDown, timeline1.eventTime,
- timeline1.readTime, DEVICE_ID, {InputDeviceUsageSource::UNKNOWN});
+ mTracker->trackListener(inputEventId1, timeline1.eventTime, timeline1.readTime, DEVICE_ID,
+ {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
+ InputEventType::MOTION);
// Start processing second event
- mTracker->trackListener(inputEventId2, timeline2.isDown, timeline2.eventTime,
- timeline2.readTime, DEVICE_ID, {InputDeviceUsageSource::UNKNOWN});
+ mTracker->trackListener(inputEventId2, timeline2.eventTime, timeline2.readTime, DEVICE_ID,
+ {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
+ InputEventType::MOTION);
mTracker->trackFinishedEvent(inputEventId1, connection1, connectionTimeline1.deliveryTime,
connectionTimeline1.consumeTime, connectionTimeline1.finishTime);
@@ -301,12 +309,14 @@
const sp<IBinder>& token = timeline.connectionTimelines.begin()->first;
for (size_t i = 1; i <= 100; i++) {
- mTracker->trackListener(/*inputEventId=*/i, timeline.isDown, timeline.eventTime,
- timeline.readTime, /*deviceId=*/DEVICE_ID,
- /*sources=*/{InputDeviceUsageSource::UNKNOWN});
- expectedTimelines.push_back(InputEventTimeline{timeline.isDown, timeline.eventTime,
- timeline.readTime, timeline.vendorId,
- timeline.productId, timeline.sources});
+ mTracker->trackListener(/*inputEventId=*/i, timeline.eventTime, timeline.readTime,
+ /*deviceId=*/DEVICE_ID,
+ /*sources=*/{InputDeviceUsageSource::UNKNOWN},
+ AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION);
+ expectedTimelines.push_back(InputEventTimeline{timeline.eventTime, timeline.readTime,
+ timeline.vendorId, timeline.productId,
+ timeline.sources,
+ timeline.inputEventActionType});
}
// Now, complete the first event that was sent.
mTracker->trackFinishedEvent(/*inputEventId=*/1, token, expectedCT.deliveryTime,
@@ -332,12 +342,13 @@
expectedCT.consumeTime, expectedCT.finishTime);
mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);
- mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime,
- DEVICE_ID, {InputDeviceUsageSource::UNKNOWN});
+ mTracker->trackListener(inputEventId, expected.eventTime, expected.readTime, DEVICE_ID,
+ {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL,
+ InputEventType::MOTION);
triggerEventReporting(expected.eventTime);
- assertReceivedTimeline(InputEventTimeline{expected.isDown, expected.eventTime,
- expected.readTime, expected.vendorId,
- expected.productId, expected.sources});
+ assertReceivedTimeline(InputEventTimeline{expected.eventTime, expected.readTime,
+ expected.vendorId, expected.productId,
+ expected.sources, expected.inputEventActionType});
}
/**
@@ -348,22 +359,92 @@
TEST_F(LatencyTrackerTest, TrackListenerCheck_DeviceInfoFieldsInputEventTimeline) {
constexpr int32_t inputEventId = 1;
InputEventTimeline timeline(
- /*isDown*/ true, /*eventTime*/ 2, /*readTime*/ 3,
+ /*eventTime*/ 2, /*readTime*/ 3,
/*vendorId=*/50, /*productId=*/60,
/*sources=*/
- {InputDeviceUsageSource::TOUCHSCREEN, InputDeviceUsageSource::STYLUS_DIRECT});
+ {InputDeviceUsageSource::TOUCHSCREEN, InputDeviceUsageSource::STYLUS_DIRECT},
+ /*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT);
InputDeviceInfo deviceInfo1 = generateTestDeviceInfo(
/*vendorId=*/5, /*productId=*/6, /*deviceId=*/DEVICE_ID + 1);
InputDeviceInfo deviceInfo2 = generateTestDeviceInfo(
/*vendorId=*/50, /*productId=*/60, /*deviceId=*/DEVICE_ID);
mTracker->setInputDevices({deviceInfo1, deviceInfo2});
- mTracker->trackListener(inputEventId, timeline.isDown, timeline.eventTime, timeline.readTime,
- DEVICE_ID,
+ mTracker->trackListener(inputEventId, timeline.eventTime, timeline.readTime, DEVICE_ID,
{InputDeviceUsageSource::TOUCHSCREEN,
- InputDeviceUsageSource::STYLUS_DIRECT});
+ InputDeviceUsageSource::STYLUS_DIRECT},
+ AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION);
triggerEventReporting(timeline.eventTime);
assertReceivedTimeline(timeline);
}
+/**
+ * Check that InputEventActionType is correctly assigned to InputEventTimeline in trackListener.
+ */
+TEST_F(LatencyTrackerTest, TrackListenerCheck_InputEventActionTypeFieldInputEventTimeline) {
+ constexpr int32_t inputEventId = 1;
+ // Create timelines for different event types (Motion, Key)
+ InputEventTimeline motionDownTimeline(
+ /*eventTime*/ 2, /*readTime*/ 3,
+ /*vendorId*/ 0, /*productId*/ 0,
+ /*sources*/ {InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_DOWN);
+
+ InputEventTimeline motionMoveTimeline(
+ /*eventTime*/ 4, /*readTime*/ 5,
+ /*vendorId*/ 0, /*productId*/ 0,
+ /*sources*/ {InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_MOVE);
+
+ InputEventTimeline motionUpTimeline(
+ /*eventTime*/ 6, /*readTime*/ 7,
+ /*vendorId*/ 0, /*productId*/ 0,
+ /*sources*/ {InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_UP);
+
+ InputEventTimeline keyDownTimeline(
+ /*eventTime*/ 8, /*readTime*/ 9,
+ /*vendorId*/ 0, /*productId*/ 0,
+ /*sources*/ {InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType*/ InputEventActionType::KEY);
+
+ InputEventTimeline keyUpTimeline(
+ /*eventTime*/ 10, /*readTime*/ 11,
+ /*vendorId*/ 0, /*productId*/ 0,
+ /*sources*/ {InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType*/ InputEventActionType::KEY);
+
+ InputEventTimeline unknownTimeline(
+ /*eventTime*/ 12, /*readTime*/ 13,
+ /*vendorId*/ 0, /*productId*/ 0,
+ /*sources*/ {InputDeviceUsageSource::UNKNOWN},
+ /*inputEventActionType*/ InputEventActionType::UNKNOWN_INPUT_EVENT);
+
+ mTracker->trackListener(inputEventId, motionDownTimeline.eventTime, motionDownTimeline.readTime,
+ DEVICE_ID, motionDownTimeline.sources, AMOTION_EVENT_ACTION_DOWN,
+ InputEventType::MOTION);
+ mTracker->trackListener(inputEventId + 1, motionMoveTimeline.eventTime,
+ motionMoveTimeline.readTime, DEVICE_ID, motionMoveTimeline.sources,
+ AMOTION_EVENT_ACTION_MOVE, InputEventType::MOTION);
+ mTracker->trackListener(inputEventId + 2, motionUpTimeline.eventTime, motionUpTimeline.readTime,
+ DEVICE_ID, motionUpTimeline.sources, AMOTION_EVENT_ACTION_UP,
+ InputEventType::MOTION);
+ mTracker->trackListener(inputEventId + 3, keyDownTimeline.eventTime, keyDownTimeline.readTime,
+ DEVICE_ID, keyDownTimeline.sources, AKEY_EVENT_ACTION_DOWN,
+ InputEventType::KEY);
+ mTracker->trackListener(inputEventId + 4, keyUpTimeline.eventTime, keyUpTimeline.readTime,
+ DEVICE_ID, keyUpTimeline.sources, AKEY_EVENT_ACTION_UP,
+ InputEventType::KEY);
+ mTracker->trackListener(inputEventId + 5, unknownTimeline.eventTime, unknownTimeline.readTime,
+ DEVICE_ID, unknownTimeline.sources, AMOTION_EVENT_ACTION_POINTER_DOWN,
+ InputEventType::MOTION);
+
+ triggerEventReporting(unknownTimeline.eventTime);
+
+ std::vector<InputEventTimeline> expectedTimelines = {motionDownTimeline, motionMoveTimeline,
+ motionUpTimeline, keyDownTimeline,
+ keyUpTimeline, unknownTimeline};
+ assertReceivedTimelines(expectedTimelines);
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h
index 082bbb8..d2337dd 100644
--- a/services/inputflinger/tests/TestConstants.h
+++ b/services/inputflinger/tests/TestConstants.h
@@ -25,7 +25,10 @@
using std::chrono_literals::operator""ms;
// Timeout for waiting for an input device to be added and processed
-static constexpr std::chrono::duration ADD_INPUT_DEVICE_TIMEOUT = 500ms;
+static constexpr std::chrono::duration ADD_INPUT_DEVICE_TIMEOUT = 5000ms;
+
+// Timeout for asserting that an input device change did not occur
+static constexpr std::chrono::duration INPUT_DEVICES_DIDNT_CHANGE_TIMEOUT = 100ms;
// Timeout for waiting for an expected event
static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
index 6daeaaf..695eb3c 100644
--- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -18,6 +18,7 @@
#include <linux/input.h>
#include "../../InputDeviceMetricsSource.h"
+#include "../InputEventTimeline.h"
#include "dispatcher/LatencyTracker.h"
namespace android {
@@ -65,14 +66,15 @@
fdp.PickValueInArray<std::function<void()>>({
[&]() -> void {
int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
- int32_t isDown = fdp.ConsumeBool();
nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>();
nsecs_t readTime = fdp.ConsumeIntegral<nsecs_t>();
const DeviceId deviceId = fdp.ConsumeIntegral<int32_t>();
std::set<InputDeviceUsageSource> sources = {
fdp.ConsumeEnum<InputDeviceUsageSource>()};
- tracker.trackListener(inputEventId, isDown, eventTime, readTime, deviceId,
- sources);
+ const int32_t inputEventActionType = fdp.ConsumeIntegral<int32_t>();
+ const InputEventType inputEventType = fdp.ConsumeEnum<InputEventType>();
+ tracker.trackListener(inputEventId, eventTime, readTime, deviceId, sources,
+ inputEventActionType, inputEventType);
},
[&]() -> void {
int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 130c112..f56642b 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -172,7 +172,7 @@
bool SensorService::SensorEventConnection::removeSensor(int32_t handle) {
Mutex::Autolock _l(mConnectionLock);
- if (mSensorInfo.erase(handle) >= 0) {
+ if (mSensorInfo.erase(handle) > 0) {
return true;
}
return false;
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index dc9e821..a8a773a 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -38,10 +38,11 @@
mActivated = false;
}
- SensorRegistrationInfo(int32_t handle, const String8 &packageName,
- int64_t samplingRateNs, int64_t maxReportLatencyNs, bool activate) {
+ SensorRegistrationInfo(int32_t handle, const String8& packageName, int64_t samplingRateNs,
+ int64_t maxReportLatencyNs, bool activate, status_t registerStatus) {
mSensorHandle = handle;
mPackageName = packageName;
+ mRegisteredStatus = registerStatus;
mSamplingRateUs = static_cast<int64_t>(samplingRateNs/1000);
mMaxReportLatencyUs = static_cast<int64_t>(maxReportLatencyNs/1000);
@@ -60,28 +61,43 @@
return (info.mSensorHandle == INT32_MIN && info.mRealtimeSec == 0);
}
- // Dumpable interface
- virtual std::string dump() const override {
+ std::string dump(SensorService* sensorService) const {
struct tm* timeinfo = localtime(&mRealtimeSec);
const int8_t hour = static_cast<int8_t>(timeinfo->tm_hour);
const int8_t min = static_cast<int8_t>(timeinfo->tm_min);
const int8_t sec = static_cast<int8_t>(timeinfo->tm_sec);
std::ostringstream ss;
- ss << std::setfill('0') << std::setw(2) << static_cast<int>(hour) << ":"
- << std::setw(2) << static_cast<int>(min) << ":"
- << std::setw(2) << static_cast<int>(sec)
- << (mActivated ? " +" : " -")
- << " 0x" << std::hex << std::setw(8) << mSensorHandle << std::dec
- << std::setfill(' ') << " pid=" << std::setw(5) << mPid
- << " uid=" << std::setw(5) << mUid << " package=" << mPackageName;
- if (mActivated) {
- ss << " samplingPeriod=" << mSamplingRateUs << "us"
- << " batchingPeriod=" << mMaxReportLatencyUs << "us";
- };
+ ss << std::setfill('0') << std::setw(2) << static_cast<int>(hour) << ":" << std::setw(2)
+ << static_cast<int>(min) << ":" << std::setw(2) << static_cast<int>(sec)
+ << (mActivated ? " +" : " -") << " 0x" << std::hex << std::setw(8) << mSensorHandle;
+ ss << std::dec << std::setfill(' ') << " pid=" << std::setw(5) << mPid
+ << " uid=" << std::setw(5) << mUid;
+
+ std::string samplingRate =
+ mActivated ? std::to_string(mSamplingRateUs) : " N/A ";
+ std::string batchingInterval =
+ mActivated ? std::to_string(mMaxReportLatencyUs) : " N/A ";
+ ss << " samplingPeriod=" << std::setfill(' ') << std::setw(8)
+ << samplingRate << "us" << " batchingPeriod=" << std::setfill(' ')
+ << std::setw(8) << batchingInterval << "us"
+ << " result=" << statusToString(mRegisteredStatus)
+ << " (sensor, package): (" << std::setfill(' ') << std::left
+ << std::setw(27);
+
+ if (sensorService != nullptr) {
+ ss << sensorService->getSensorName(mSensorHandle);
+ } else {
+ ss << "null";
+ }
+ ss << ", " << mPackageName << ")";
+
return ss.str();
}
+ // Dumpable interface
+ virtual std::string dump() const override { return dump(static_cast<SensorService*>(nullptr)); }
+
/**
* Dump debugging information as android.service.SensorRegistrationInfoProto protobuf message
* using ProtoOutputStream.
@@ -110,6 +126,7 @@
int64_t mMaxReportLatencyUs;
bool mActivated;
time_t mRealtimeSec;
+ status_t mRegisteredStatus;
};
} // namespace android;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3895ffe..060508c 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -708,7 +708,7 @@
SENSOR_REGISTRATIONS_BUF_SIZE;
continue;
}
- result.appendFormat("%s\n", reg_info.dump().c_str());
+ result.appendFormat("%s\n", reg_info.dump(this).c_str());
currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
SENSOR_REGISTRATIONS_BUF_SIZE;
} while(startIndex != currentIndex);
@@ -1583,7 +1583,11 @@
// Only 4 modes supported for a SensorEventConnection ... NORMAL, DATA_INJECTION,
// REPLAY_DATA_INJECTION and HAL_BYPASS_REPLAY_DATA_INJECTION
if (requestedMode != NORMAL && !isInjectionMode(requestedMode)) {
- return nullptr;
+ ALOGE(
+ "Failed to create sensor event connection: invalid request mode. "
+ "requestMode: %d",
+ requestedMode);
+ return nullptr;
}
resetTargetSdkVersionCache(opPackageName);
@@ -1591,8 +1595,19 @@
// To create a client in DATA_INJECTION mode to inject data, SensorService should already be
// operating in DI mode.
if (requestedMode == DATA_INJECTION) {
- if (mCurrentOperatingMode != DATA_INJECTION) return nullptr;
- if (!isAllowListedPackage(packageName)) return nullptr;
+ if (mCurrentOperatingMode != DATA_INJECTION) {
+ ALOGE(
+ "Failed to create sensor event connection: sensor service not in "
+ "DI mode when creating a client in DATA_INJECTION mode");
+ return nullptr;
+ }
+ if (!isAllowListedPackage(packageName)) {
+ ALOGE(
+ "Failed to create sensor event connection: package %s not in "
+ "allowed list for DATA_INJECTION mode",
+ packageName.c_str());
+ return nullptr;
+ }
}
uid_t uid = IPCThreadState::self()->getCallingUid();
@@ -2152,17 +2167,17 @@
sensor->getSensor().getRequiredAppOp() >= 0) {
connection->mHandleToAppOp[handle] = sensor->getSensor().getRequiredAppOp();
}
-
- mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
- SensorRegistrationInfo(handle, connection->getPackageName(),
- samplingPeriodNs, maxBatchReportLatencyNs, true);
- mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
if (err != NO_ERROR) {
// batch/activate has failed, reset our state.
cleanupWithoutDisableLocked(connection, handle);
}
+
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
+ SensorRegistrationInfo(handle, connection->getPackageName(), samplingPeriodNs,
+ maxBatchReportLatencyNs, /*activate=*/ true, err);
+ mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
return err;
}
@@ -2175,13 +2190,10 @@
if (err == NO_ERROR) {
std::shared_ptr<SensorInterface> sensor = getSensorInterfaceFromHandle(handle);
err = sensor != nullptr ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
-
}
- if (err == NO_ERROR) {
- mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
- SensorRegistrationInfo(handle, connection->getPackageName(), 0, 0, false);
- mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
- }
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
+ SensorRegistrationInfo(handle, connection->getPackageName(), 0, 0, /*activate=*/ false, err);
+ mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
return err;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index b0b1a02..eb6e677 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -33,6 +33,7 @@
#include "DisplayHardware/HWC2.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/Lut.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
@@ -77,6 +78,7 @@
Error(const std::string&, bool, const std::vector<uint8_t>&));
MOCK_METHOD1(setBrightness, Error(float));
MOCK_METHOD1(setBlockingRegion, Error(const android::Region&));
+ MOCK_METHOD(Error, setLuts, (std::vector<aidl::android::hardware::graphics::composer3::Lut>&));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 629d9f2..e910c72 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -51,7 +51,8 @@
MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t());
MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t());
MOCK_METHOD3(allocateVirtualDisplay, bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*));
- MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId));
+ MOCK_METHOD3(allocatePhysicalDisplay,
+ void(hal::HWDisplayId, PhysicalDisplayId, std::optional<ui::Size>));
MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId));
MOCK_METHOD(status_t, getDeviceCompositionChanges,
@@ -151,6 +152,10 @@
getOverlaySupport, (), (const, override));
MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool));
MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, TimePoint, Fps));
+ MOCK_METHOD(status_t, getRequestedLuts,
+ (PhysicalDisplayId,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*),
+ (override));
};
} // namespace mock
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 0eced73..66237b9 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -60,6 +60,7 @@
using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities;
using AidlHdrConversionCapability =
aidl::android::hardware::graphics::common::HdrConversionCapability;
+using AidlHdcpLevels = aidl::android::hardware::drm::HdcpLevels;
using AidlHdrConversionStrategy = aidl::android::hardware::graphics::common::HdrConversionStrategy;
using AidlOverlayProperties = aidl::android::hardware::graphics::composer3::OverlayProperties;
using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata;
@@ -223,6 +224,12 @@
return ::ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus onHdcpLevelsChanged(int64_t in_display,
+ const AidlHdcpLevels& levels) override {
+ mCallback.onComposerHalHdcpLevelsChanged(translate<Display>(in_display), levels);
+ return ::ndk::ScopedAStatus::ok();
+ }
+
private:
HWC2::ComposerCallback& mCallback;
};
@@ -1540,7 +1547,7 @@
return error;
}
-Error AidlComposer::getDisplayLuts(Display display, std::vector<Lut>* outLuts) {
+Error AidlComposer::getRequestedLuts(Display display, std::vector<DisplayLuts::LayerLut>* outLuts) {
Error error = Error::NONE;
mMutex.lock_shared();
if (auto reader = getReader(display)) {
@@ -1552,6 +1559,18 @@
return error;
}
+Error AidlComposer::setLayerLuts(Display display, Layer layer, std::vector<Lut>& luts) {
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto writer = getWriter(display)) {
+ writer->get().setLayerLuts(translate<int64_t>(display), translate<int64_t>(layer), luts);
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
+}
+
Error AidlComposer::setLayerBrightness(Display display, Layer layer, float brightness) {
Error error = Error::NONE;
mMutex.lock_shared();
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 3669d4c..246223a 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -244,9 +244,13 @@
Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override;
Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime,
int32_t frameIntervalNs) override;
- Error getDisplayLuts(
+ Error getRequestedLuts(
Display display,
- std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) override;
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*
+ outLuts) override;
+ Error setLayerLuts(
+ Display display, Layer layer,
+ std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) override;
private:
// Many public functions above simply write a command into the command
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 888dc08..7db9a94 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -40,6 +40,7 @@
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
#include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayLuts.h>
#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
#include <aidl/android/hardware/graphics/composer3/Lut.h>
#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
@@ -304,7 +305,9 @@
virtual Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) = 0;
virtual Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime,
int32_t frameIntervalNs) = 0;
- virtual Error getDisplayLuts(Display display, std::vector<V3_0::Lut>* outLuts) = 0;
+ virtual Error getRequestedLuts(Display display,
+ std::vector<V3_0::DisplayLuts::LayerLut>* outLuts) = 0;
+ virtual Error setLayerLuts(Display display, Layer layer, std::vector<V3_0::Lut>& luts) = 0;
};
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index d5f65c6..f1fa938 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -41,6 +41,7 @@
using aidl::android::hardware::graphics::composer3::Composition;
using AidlCapability = aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
+using aidl::android::hardware::graphics::composer3::DisplayLuts;
using aidl::android::hardware::graphics::composer3::Lut;
using aidl::android::hardware::graphics::composer3::OverlayProperties;
@@ -608,13 +609,14 @@
return static_cast<Error>(error);
}
-Error Display::getDisplayLuts(std::vector<Lut>* outLuts) {
- std::vector<Lut> tmpLuts;
- const auto error = mComposer.getDisplayLuts(mId, &tmpLuts);
- for (Lut& lut : tmpLuts) {
- if (lut.pfd.get() >= 0) {
- outLuts->push_back(
- {lut.layer, ndk::ScopedFileDescriptor(lut.pfd.release()), lut.lutProperties});
+Error Display::getRequestedLuts(std::vector<DisplayLuts::LayerLut>* outLayerLuts) {
+ std::vector<DisplayLuts::LayerLut> tmpLayerLuts;
+ const auto error = mComposer.getRequestedLuts(mId, &tmpLayerLuts);
+ for (DisplayLuts::LayerLut& layerLut : tmpLayerLuts) {
+ if (layerLut.lut.pfd.get() >= 0) {
+ outLayerLuts->push_back({layerLut.layer,
+ Lut{ndk::ScopedFileDescriptor(layerLut.lut.pfd.release()),
+ layerLut.lut.lutProperties}});
}
}
return static_cast<Error>(error);
@@ -673,6 +675,11 @@
}
});
}
+
+void Display::setPhysicalSizeInMm(std::optional<ui::Size> size) {
+ mPhysicalSize = size;
+}
+
} // namespace impl
// Layer methods
@@ -1050,6 +1057,14 @@
return static_cast<Error>(intError);
}
+Error Layer::setLuts(std::vector<Lut>& luts) {
+ if (CC_UNLIKELY(!mDisplay)) {
+ return Error::BAD_DISPLAY;
+ }
+ const auto intError = mComposer.setLayerLuts(mDisplay->getId(), mId, luts);
+ return static_cast<Error>(intError);
+}
+
} // namespace impl
} // namespace HWC2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index be2059a..8e2aeaf 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -67,6 +67,7 @@
namespace hal = android::hardware::graphics::composer::hal;
+using aidl::android::hardware::drm::HdcpLevels;
using aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
@@ -85,6 +86,7 @@
virtual void onComposerHalSeamlessPossible(hal::HWDisplayId) = 0;
virtual void onComposerHalVsyncIdle(hal::HWDisplayId) = 0;
virtual void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) = 0;
+ virtual void onComposerHalHdcpLevelsChanged(hal::HWDisplayId, const HdcpLevels& levels) = 0;
protected:
~ComposerCallback() = default;
@@ -103,6 +105,7 @@
virtual bool isVsyncPeriodSwitchSupported() const = 0;
virtual bool hasDisplayIdleTimerCapability() const = 0;
virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0;
+ virtual std::optional<ui::Size> getPhysicalSizeInMm() const = 0;
[[nodiscard]] virtual hal::Error acceptChanges() = 0;
[[nodiscard]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>
@@ -179,8 +182,9 @@
[[nodiscard]] virtual hal::Error getClientTargetProperty(
aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
outClientTargetProperty) = 0;
- [[nodiscard]] virtual hal::Error getDisplayLuts(
- std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) = 0;
+ [[nodiscard]] virtual hal::Error getRequestedLuts(
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*
+ outLuts) = 0;
[[nodiscard]] virtual hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
@@ -264,8 +268,9 @@
hal::Error getClientTargetProperty(
aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
outClientTargetProperty) override;
- hal::Error getDisplayLuts(
- std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) override;
+ hal::Error getRequestedLuts(
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*
+ outLuts) override;
hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
@@ -281,6 +286,8 @@
bool hasDisplayIdleTimerCapability() const override;
void onLayerDestroyed(hal::HWLayerId layerId) override;
hal::Error getPhysicalDisplayOrientation(Hwc2::AidlTransform* outTransform) const override;
+ void setPhysicalSizeInMm(std::optional<ui::Size> size);
+ std::optional<ui::Size> getPhysicalSizeInMm() const override { return mPhysicalSize; }
private:
void loadDisplayCapabilities();
@@ -314,6 +321,8 @@
std::optional<
std::unordered_set<aidl::android::hardware::graphics::composer3::DisplayCapability>>
mDisplayCapabilities GUARDED_BY(mDisplayCapabilitiesMutex);
+ // Physical size in mm.
+ std::optional<ui::Size> mPhysicalSize;
};
} // namespace impl
@@ -359,6 +368,8 @@
// AIDL HAL
[[nodiscard]] virtual hal::Error setBrightness(float brightness) = 0;
[[nodiscard]] virtual hal::Error setBlockingRegion(const android::Region& region) = 0;
+ [[nodiscard]] virtual hal::Error setLuts(
+ std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) = 0;
};
namespace impl {
@@ -409,6 +420,8 @@
// AIDL HAL
hal::Error setBrightness(float brightness) override;
hal::Error setBlockingRegion(const android::Region& region) override;
+ hal::Error setLuts(
+ std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) override;
private:
// These are references to data owned by HWComposer, which will outlive
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 73fa855..bd093f5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -76,6 +76,7 @@
using aidl::android::hardware::graphics::common::HdrConversionStrategy;
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
+using aidl::android::hardware::graphics::composer3::DisplayConfiguration;
using namespace std::string_literals;
namespace android {
@@ -222,8 +223,8 @@
return true;
}
-void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId,
- PhysicalDisplayId displayId) {
+void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, PhysicalDisplayId displayId,
+ std::optional<ui::Size> physicalSize) {
mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
if (!mPrimaryHwcDisplayId) {
@@ -235,6 +236,7 @@
std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId,
hal::DisplayType::PHYSICAL);
newDisplay->setConnected(true);
+ newDisplay->setPhysicalSizeInMm(physicalSize);
displayData.hwcDisplay = std::move(newDisplay);
}
@@ -276,6 +278,47 @@
return getModesFromLegacyDisplayConfigs(hwcDisplayId);
}
+DisplayConfiguration::Dpi HWComposer::getEstimatedDotsPerInchFromSize(
+ uint64_t hwcDisplayId, const HWCDisplayMode& hwcMode) const {
+ if (!FlagManager::getInstance().correct_dpi_with_display_size()) {
+ return {-1, -1};
+ }
+ if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
+ if (const auto it = mDisplayData.find(displayId.value());
+ it != mDisplayData.end() && it->second.hwcDisplay->getPhysicalSizeInMm()) {
+ ui::Size size = it->second.hwcDisplay->getPhysicalSizeInMm().value();
+ if (hwcMode.width > 0 && hwcMode.height > 0 && size.width > 0 && size.height > 0) {
+ static constexpr float kMmPerInch = 25.4f;
+ return {hwcMode.width * kMmPerInch / size.width,
+ hwcMode.height * kMmPerInch / size.height};
+ }
+ }
+ }
+ return {-1, -1};
+}
+
+DisplayConfiguration::Dpi HWComposer::correctedDpiIfneeded(
+ DisplayConfiguration::Dpi dpi, DisplayConfiguration::Dpi estimatedDpi) const {
+ // hwc can be unreliable when it comes to dpi. A rough estimated dpi may yield better
+ // results. For instance, libdrm and bad edid may result in a dpi of {350, 290} for a
+ // 16:9 3840x2160 display, which would match a 4:3 aspect ratio.
+ // The logic here checks if hwc was able to provide some dpi, and if so if the dpi
+ // disparity between the axes is more reasonable than a rough estimate, otherwise use
+ // the estimated dpi as a corrected value.
+ if (estimatedDpi.x == -1 || estimatedDpi.x == -1) {
+ return dpi;
+ }
+ if (dpi.x == -1 || dpi.y == -1) {
+ return estimatedDpi;
+ }
+ if (std::min(dpi.x, dpi.y) != 0 && std::min(estimatedDpi.x, estimatedDpi.y) != 0 &&
+ abs(dpi.x - dpi.y) / std::min(dpi.x, dpi.y) >
+ abs(estimatedDpi.x - estimatedDpi.y) / std::min(estimatedDpi.x, estimatedDpi.y)) {
+ return estimatedDpi;
+ }
+ return dpi;
+}
+
std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromDisplayConfigurations(
uint64_t hwcDisplayId, int32_t maxFrameIntervalNs) const {
std::vector<hal::DisplayConfiguration> configs;
@@ -294,9 +337,16 @@
.configGroup = config.configGroup,
.vrrConfig = config.vrrConfig};
+ const DisplayConfiguration::Dpi estimatedDPI =
+ getEstimatedDotsPerInchFromSize(hwcDisplayId, hwcMode);
if (config.dpi) {
- hwcMode.dpiX = config.dpi->x;
- hwcMode.dpiY = config.dpi->y;
+ const DisplayConfiguration::Dpi dpi =
+ correctedDpiIfneeded(config.dpi.value(), estimatedDPI);
+ hwcMode.dpiX = dpi.x;
+ hwcMode.dpiY = dpi.y;
+ } else if (estimatedDPI.x != -1 && estimatedDPI.y != -1) {
+ hwcMode.dpiX = estimatedDPI.x;
+ hwcMode.dpiY = estimatedDPI.y;
}
if (!mEnableVrrTimeout) {
@@ -328,12 +378,14 @@
const int32_t dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X);
const int32_t dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y);
- if (dpiX != -1) {
- hwcMode.dpiX = static_cast<float>(dpiX) / 1000.f;
- }
- if (dpiY != -1) {
- hwcMode.dpiY = static_cast<float>(dpiY) / 1000.f;
- }
+ const DisplayConfiguration::Dpi hwcDpi =
+ DisplayConfiguration::Dpi{dpiX == -1 ? dpiY : dpiX / 1000.f,
+ dpiY == -1 ? dpiY : dpiY / 1000.f};
+ const DisplayConfiguration::Dpi estimatedDPI =
+ getEstimatedDotsPerInchFromSize(hwcDisplayId, hwcMode);
+ const DisplayConfiguration::Dpi dpi = correctedDpiIfneeded(hwcDpi, estimatedDPI);
+ hwcMode.dpiX = dpi.x;
+ hwcMode.dpiY = dpi.y;
modes.push_back(hwcMode);
}
@@ -533,6 +585,7 @@
DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
error = hwcDisplay->getClientTargetProperty(&clientTargetProperty);
+ RETURN_IF_HWC_ERROR_FOR("getClientTargetProperty", error, displayId, BAD_INDEX);
outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
std::move(layerRequests),
@@ -925,6 +978,21 @@
return NO_ERROR;
}
+status_t HWComposer::getRequestedLuts(
+ PhysicalDisplayId displayId,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>* outLuts) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto error = mDisplayData[displayId].hwcDisplay->getRequestedLuts(outLuts);
+ if (error == hal::Error::UNSUPPORTED) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == hal::Error::BAD_PARAMETER) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return NO_ERROR;
+}
+
status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on);
@@ -1056,6 +1124,8 @@
getDisplayIdentificationData(hwcDisplayId, &port, &data);
if (auto newInfo = parseDisplayIdentificationData(port, data)) {
info->deviceProductInfo = std::move(newInfo->deviceProductInfo);
+ info->preferredDetailedTimingDescriptor =
+ std::move(newInfo->preferredDetailedTimingDescriptor);
} else {
ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId);
}
@@ -1098,7 +1168,11 @@
}
if (!isConnected(info->id)) {
- allocatePhysicalDisplay(hwcDisplayId, info->id);
+ std::optional<ui::Size> size = std::nullopt;
+ if (info->preferredDetailedTimingDescriptor) {
+ size = info->preferredDetailedTimingDescriptor->physicalSizeInMm;
+ }
+ allocatePhysicalDisplay(hwcDisplayId, info->id, size);
}
return info;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 9368b7b..b95c619 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -52,6 +52,7 @@
#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayLuts.h>
#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
namespace android {
@@ -133,7 +134,8 @@
// supported by the HWC can be queried in advance, but allocation may fail for other reasons.
virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) = 0;
- virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0;
+ virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId,
+ std::optional<ui::Size> physicalSize) = 0;
// Attempts to create a new layer on this display
virtual std::shared_ptr<HWC2::Layer> createLayer(HalDisplayId) = 0;
@@ -309,6 +311,11 @@
virtual status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) = 0;
virtual status_t notifyExpectedPresent(PhysicalDisplayId, TimePoint expectedPresentTime,
Fps frameInterval) = 0;
+
+ // Composer 4.0
+ virtual status_t getRequestedLuts(
+ PhysicalDisplayId,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*) = 0;
};
static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs,
@@ -343,7 +350,8 @@
bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) override;
// Called from SurfaceFlinger, when the state for a new physical display needs to be recreated.
- void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override;
+ void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId,
+ std::optional<ui::Size> physicalSize) override;
// Attempts to create a new layer on this display
std::shared_ptr<HWC2::Layer> createLayer(HalDisplayId) override;
@@ -472,6 +480,12 @@
status_t notifyExpectedPresent(PhysicalDisplayId, TimePoint expectedPresentTime,
Fps frameInterval) override;
+ // Composer 4.0
+ status_t getRequestedLuts(
+ PhysicalDisplayId,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*)
+ override;
+
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
void dumpOverlayProperties(std::string& out) const override;
@@ -520,6 +534,13 @@
std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hal::HWDisplayId);
bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const;
+ aidl::android::hardware::graphics::composer3::DisplayConfiguration::Dpi
+ getEstimatedDotsPerInchFromSize(uint64_t hwcDisplayId, const HWCDisplayMode& hwcMode) const;
+
+ aidl::android::hardware::graphics::composer3::DisplayConfiguration::Dpi correctedDpiIfneeded(
+ aidl::android::hardware::graphics::composer3::DisplayConfiguration::Dpi dpi,
+ aidl::android::hardware::graphics::composer3::DisplayConfiguration::Dpi estimatedDpi)
+ const;
std::vector<HWCDisplayMode> getModesFromDisplayConfigurations(uint64_t hwcDisplayId,
int32_t maxFrameIntervalNs) const;
std::vector<HWCDisplayMode> getModesFromLegacyDisplayConfigs(uint64_t hwcDisplayId) const;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index ec2a3ec..ee1e07a 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -46,6 +46,7 @@
using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using aidl::android::hardware::graphics::composer3::DimmingStage;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
+using aidl::android::hardware::graphics::composer3::DisplayLuts;
using aidl::android::hardware::graphics::composer3::Lut;
using aidl::android::hardware::graphics::composer3::OverlayProperties;
@@ -1409,7 +1410,11 @@
return Error::NONE;
}
-Error HidlComposer::getDisplayLuts(Display, std::vector<Lut>*) {
+Error HidlComposer::getRequestedLuts(Display, std::vector<DisplayLuts::LayerLut>*) {
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerLuts(Display, Layer, std::vector<Lut>&) {
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 8bca5ad..701a54b 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -351,8 +351,12 @@
Hdr*) override;
Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override;
Error notifyExpectedPresent(Display, nsecs_t, int32_t) override;
- Error getDisplayLuts(Display,
- std::vector<aidl::android::hardware::graphics::composer3::Lut>*) override;
+ Error getRequestedLuts(
+ Display,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*)
+ override;
+ Error setLayerLuts(Display, Layer,
+ std::vector<aidl::android::hardware::graphics::composer3::Lut>&) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 2a0ee5a..47b811b 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -38,6 +38,8 @@
using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent;
using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
+namespace {
+
void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals,
const std::string& indent, PredictionState predictionState, nsecs_t baseTime) {
StringAppendF(&result, "%s", indent.c_str());
@@ -319,6 +321,16 @@
return minTime;
}
+bool shouldTraceForDataSource(const FrameTimelineDataSource::TraceContext& ctx, nsecs_t timestamp) {
+ if (auto ds = ctx.GetDataSourceLocked(); ds && ds->getStartTime() > timestamp) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
int64_t TraceCookieCounter::getCookieForTracing() {
return ++mTraceCookie;
}
@@ -697,6 +709,23 @@
jd.jankType = mJankType;
jd.frameIntervalNs =
(mRenderRate ? *mRenderRate : mDisplayFrameRenderRate).getPeriodNsecs();
+
+ if (mPredictionState == PredictionState::Valid) {
+ jd.scheduledAppFrameTimeNs = mPredictions.endTime - mPredictions.startTime;
+
+ // Using expected start, rather than actual, to measure the entire frame time. That is
+ // if the application starts the frame later than scheduled, include that delay in the
+ // frame time, as it usually means main thread being busy with non-rendering work.
+ if (mPresentState == PresentState::Dropped) {
+ jd.actualAppFrameTimeNs = mDropTime - mPredictions.startTime;
+ } else {
+ jd.actualAppFrameTimeNs = mActuals.endTime - mPredictions.startTime;
+ }
+ } else {
+ jd.scheduledAppFrameTimeNs = 0;
+ jd.actualAppFrameTimeNs = 0;
+ }
+
JankTracker::onJankData(mLayerId, jd);
}
}
@@ -709,15 +738,24 @@
classifyJankLocked(JankType::None, refreshRate, displayFrameRenderRate, nullptr);
}
-void SurfaceFrame::tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
+void SurfaceFrame::tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+ bool traced = false;
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ const auto timestamp = mPredictions.startTime;
+ if (filterFramesBeforeTraceStarts && !shouldTraceForDataSource(ctx, timestamp)) {
+ // Do not trace packets started before tracing starts.
+ return;
+ }
+ traced = true;
+
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime + monoBootOffset));
+ packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedSurfaceFrameStartEvent = event->set_expected_surface_frame_start();
@@ -731,42 +769,54 @@
expectedSurfaceFrameStartEvent->set_layer_name(mDebugName);
});
- // Expected timeline end
- FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
- std::scoped_lock lock(mMutex);
- auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime + monoBootOffset));
+ if (traced) {
+ // Expected timeline end
+ FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ std::scoped_lock lock(mMutex);
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime + monoBootOffset));
- auto* event = packet->set_frame_timeline_event();
- auto* expectedSurfaceFrameEndEvent = event->set_frame_end();
+ auto* event = packet->set_frame_timeline_event();
+ auto* expectedSurfaceFrameEndEvent = event->set_frame_end();
- expectedSurfaceFrameEndEvent->set_cookie(expectedTimelineCookie);
- });
+ expectedSurfaceFrameEndEvent->set_cookie(expectedTimelineCookie);
+ });
+ }
}
-void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
+void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+ bool traced = false;
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ const auto timestamp = [&]() {
+ std::scoped_lock lock(mMutex);
+ // Actual start time is not yet available, so use expected start instead
+ if (mPredictionState == PredictionState::Expired) {
+ // If prediction is expired, we can't use the predicted start time. Instead, just
+ // use a start time a little earlier than the end time so that we have some info
+ // about this frame in the trace.
+ nsecs_t endTime =
+ (mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime);
+ return endTime - kPredictionExpiredStartTimeDelta;
+ }
+
+ return mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime;
+ }();
+
+ if (filterFramesBeforeTraceStarts && !shouldTraceForDataSource(ctx, timestamp)) {
+ // Do not trace packets started before tracing starts.
+ return;
+ }
+ traced = true;
+
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- // Actual start time is not yet available, so use expected start instead
- if (mPredictionState == PredictionState::Expired) {
- // If prediction is expired, we can't use the predicted start time. Instead, just use a
- // start time a little earlier than the end time so that we have some info about this
- // frame in the trace.
- nsecs_t endTime =
- (mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime);
- const auto timestamp = endTime - kPredictionExpiredStartTimeDelta;
- packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
- } else {
- const auto timestamp =
- mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime;
- packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
- }
+ packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* actualSurfaceFrameStartEvent = event->set_actual_surface_frame_start();
@@ -795,28 +845,31 @@
actualSurfaceFrameStartEvent->set_jank_severity_type(toProto(mJankSeverityType));
});
- // Actual timeline end
- FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
- std::scoped_lock lock(mMutex);
- auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- if (mPresentState == PresentState::Dropped) {
- packet->set_timestamp(static_cast<uint64_t>(mDropTime + monoBootOffset));
- } else {
- packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime + monoBootOffset));
- }
+ if (traced) {
+ // Actual timeline end
+ FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ std::scoped_lock lock(mMutex);
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ if (mPresentState == PresentState::Dropped) {
+ packet->set_timestamp(static_cast<uint64_t>(mDropTime + monoBootOffset));
+ } else {
+ packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime + monoBootOffset));
+ }
- auto* event = packet->set_frame_timeline_event();
- auto* actualSurfaceFrameEndEvent = event->set_frame_end();
+ auto* event = packet->set_frame_timeline_event();
+ auto* actualSurfaceFrameEndEvent = event->set_frame_end();
- actualSurfaceFrameEndEvent->set_cookie(actualTimelineCookie);
- });
+ actualSurfaceFrameEndEvent->set_cookie(actualTimelineCookie);
+ });
+ }
}
/**
* TODO(b/178637512): add inputEventId to the perfetto trace.
*/
-void SurfaceFrame::trace(int64_t displayFrameToken, nsecs_t monoBootOffset) const {
+void SurfaceFrame::trace(int64_t displayFrameToken, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const {
if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID ||
displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
// No packets can be traced with a missing token.
@@ -825,9 +878,9 @@
if (getPredictionState() != PredictionState::Expired) {
// Expired predictions have zeroed timestamps. This cannot be used in any meaningful way in
// a trace.
- tracePredictions(displayFrameToken, monoBootOffset);
+ tracePredictions(displayFrameToken, monoBootOffset, filterFramesBeforeTraceStarts);
}
- traceActuals(displayFrameToken, monoBootOffset);
+ traceActuals(displayFrameToken, monoBootOffset, filterFramesBeforeTraceStarts);
}
namespace impl {
@@ -853,8 +906,12 @@
}
FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
- JankClassificationThresholds thresholds, bool useBootTimeClock)
+ JankClassificationThresholds thresholds, bool useBootTimeClock,
+ bool filterFramesBeforeTraceStarts)
: mUseBootTimeClock(useBootTimeClock),
+ mFilterFramesBeforeTraceStarts(
+ FlagManager::getInstance().filter_frames_before_trace_starts() &&
+ filterFramesBeforeTraceStarts),
mMaxDisplayFrames(kDefaultMaxDisplayFrames),
mTimeStats(std::move(timeStats)),
mSurfaceFlingerPid(surfaceFlingerPid),
@@ -1137,16 +1194,23 @@
}
}
-void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid,
- nsecs_t monoBootOffset) const {
+void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+ bool traced = false;
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ const auto timestamp = mSurfaceFlingerPredictions.startTime;
+ if (filterFramesBeforeTraceStarts && !shouldTraceForDataSource(ctx, timestamp)) {
+ // Do not trace packets started before tracing starts.
+ return;
+ }
+ traced = true;
+
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- packet->set_timestamp(
- static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime + monoBootOffset));
+ packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* expectedDisplayFrameStartEvent = event->set_expected_display_frame_start();
@@ -1157,22 +1221,25 @@
expectedDisplayFrameStartEvent->set_pid(surfaceFlingerPid);
});
- // Expected timeline end
- FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
- auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- packet->set_timestamp(
- static_cast<uint64_t>(mSurfaceFlingerPredictions.endTime + monoBootOffset));
+ if (traced) {
+ // Expected timeline end
+ FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerPredictions.endTime + monoBootOffset));
- auto* event = packet->set_frame_timeline_event();
- auto* expectedDisplayFrameEndEvent = event->set_frame_end();
+ auto* event = packet->set_frame_timeline_event();
+ auto* expectedDisplayFrameEndEvent = event->set_frame_end();
- expectedDisplayFrameEndEvent->set_cookie(expectedTimelineCookie);
- });
+ expectedDisplayFrameEndEvent->set_cookie(expectedTimelineCookie);
+ });
+ }
}
void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs_t monoBootOffset,
- nsecs_t previousPredictionPresentTime) const {
+ nsecs_t previousPredictionPresentTime,
+ bool filterFramesBeforeTraceStarts) const {
nsecs_t skippedFrameStartTime = 0, skippedFramePresentTime = 0;
const constexpr float kThresh = 0.5f;
const constexpr float kRange = 1.5f;
@@ -1188,7 +1255,7 @@
(static_cast<float>(previousPredictionPresentTime) +
kThresh * static_cast<float>(mRenderRate.getPeriodNsecs())) &&
// sf skipped frame is not considered if app is self janked
- !surfaceFrame->isSelfJanky()) {
+ surfaceFrame->getJankType() != JankType::None && !surfaceFrame->isSelfJanky()) {
skippedFrameStartTime = surfaceFrame->getPredictions().endTime;
skippedFramePresentTime = surfaceFrame->getPredictions().presentTime;
break;
@@ -1198,9 +1265,17 @@
// add slice
if (skippedFrameStartTime != 0 && skippedFramePresentTime != 0) {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+ bool traced = false;
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ if (filterFramesBeforeTraceStarts &&
+ !shouldTraceForDataSource(ctx, skippedFrameStartTime)) {
+ // Do not trace packets started before tracing starts.
+ return;
+ }
+ traced = true;
+
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
packet->set_timestamp(static_cast<uint64_t>(skippedFrameStartTime + monoBootOffset));
@@ -1221,30 +1296,40 @@
actualDisplayFrameStartEvent->set_jank_severity_type(toProto(JankSeverityType::None));
});
- // Actual timeline end
- FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
- auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- packet->set_timestamp(static_cast<uint64_t>(skippedFramePresentTime + monoBootOffset));
+ if (traced) {
+ // Actual timeline end
+ FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(skippedFramePresentTime + monoBootOffset));
- auto* event = packet->set_frame_timeline_event();
- auto* actualDisplayFrameEndEvent = event->set_frame_end();
+ auto* event = packet->set_frame_timeline_event();
+ auto* actualDisplayFrameEndEvent = event->set_frame_end();
- actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie);
- });
+ actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie);
+ });
+ }
}
}
-void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid,
- nsecs_t monoBootOffset) const {
+void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+ bool traced = false;
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ const auto timestamp = mSurfaceFlingerActuals.startTime;
+ if (filterFramesBeforeTraceStarts && !shouldTraceForDataSource(ctx, timestamp)) {
+ // Do not trace packets started before tracing starts.
+ return;
+ }
+ traced = true;
+
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- packet->set_timestamp(
- static_cast<uint64_t>(mSurfaceFlingerActuals.startTime + monoBootOffset));
+ packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset));
auto* event = packet->set_frame_timeline_event();
auto* actualDisplayFrameStartEvent = event->set_actual_display_frame_start();
@@ -1263,22 +1348,25 @@
actualDisplayFrameStartEvent->set_jank_severity_type(toProto(mJankSeverityType));
});
- // Actual timeline end
- FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
- auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
- packet->set_timestamp(
- static_cast<uint64_t>(mSurfaceFlingerActuals.presentTime + monoBootOffset));
+ if (traced) {
+ // Actual timeline end
+ FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
+ packet->set_timestamp(
+ static_cast<uint64_t>(mSurfaceFlingerActuals.presentTime + monoBootOffset));
- auto* event = packet->set_frame_timeline_event();
- auto* actualDisplayFrameEndEvent = event->set_frame_end();
+ auto* event = packet->set_frame_timeline_event();
+ auto* actualDisplayFrameEndEvent = event->set_frame_end();
- actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie);
- });
+ actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie);
+ });
+ }
}
nsecs_t FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset,
- nsecs_t previousPredictionPresentTime) const {
+ nsecs_t previousPredictionPresentTime,
+ bool filterFramesBeforeTraceStarts) const {
if (mSurfaceFrames.empty()) {
// We don't want to trace display frames without any surface frames updates as this cannot
// be janky
@@ -1294,16 +1382,17 @@
if (mPredictionState == PredictionState::Valid) {
// Expired and unknown predictions have zeroed timestamps. This cannot be used in any
// meaningful way in a trace.
- tracePredictions(surfaceFlingerPid, monoBootOffset);
+ tracePredictions(surfaceFlingerPid, monoBootOffset, filterFramesBeforeTraceStarts);
}
- traceActuals(surfaceFlingerPid, monoBootOffset);
+ traceActuals(surfaceFlingerPid, monoBootOffset, filterFramesBeforeTraceStarts);
for (auto& surfaceFrame : mSurfaceFrames) {
- surfaceFrame->trace(mToken, monoBootOffset);
+ surfaceFrame->trace(mToken, monoBootOffset, filterFramesBeforeTraceStarts);
}
if (FlagManager::getInstance().add_sf_skipped_frames_to_trace()) {
- addSkippedFrame(surfaceFlingerPid, monoBootOffset, previousPredictionPresentTime);
+ addSkippedFrame(surfaceFlingerPid, monoBootOffset, previousPredictionPresentTime,
+ filterFramesBeforeTraceStarts);
}
return mSurfaceFlingerPredictions.presentTime;
}
@@ -1397,8 +1486,9 @@
const nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
auto& displayFrame = pendingPresentFence.second;
displayFrame->onPresent(signalTime, mPreviousActualPresentTime);
- mPreviousPredictionPresentTime = displayFrame->trace(mSurfaceFlingerPid, monoBootOffset,
- mPreviousPredictionPresentTime);
+ mPreviousPredictionPresentTime =
+ displayFrame->trace(mSurfaceFlingerPid, monoBootOffset,
+ mPreviousPredictionPresentTime, mFilterFramesBeforeTraceStarts);
mPendingPresentFences.erase(mPendingPresentFences.begin());
}
@@ -1414,8 +1504,9 @@
auto& displayFrame = pendingPresentFence.second;
displayFrame->onPresent(signalTime, mPreviousActualPresentTime);
- mPreviousPredictionPresentTime = displayFrame->trace(mSurfaceFlingerPid, monoBootOffset,
- mPreviousPredictionPresentTime);
+ mPreviousPredictionPresentTime =
+ displayFrame->trace(mSurfaceFlingerPid, monoBootOffset,
+ mPreviousPredictionPresentTime, mFilterFramesBeforeTraceStarts);
mPreviousActualPresentTime = signalTime;
mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 94cfcb4..cffb61e 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -214,7 +214,8 @@
// enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
// DisplayFrame at the trace processor side. monoBootOffset is the difference
// between SYSTEM_TIME_BOOTTIME and SYSTEM_TIME_MONOTONIC.
- void trace(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
+ void trace(int64_t displayFrameToken, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const;
// Getter functions used only by FrameTimelineTests and SurfaceFrame internally
TimelineItem getActuals() const;
@@ -234,8 +235,10 @@
std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
private:
- void tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
- void traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
+ void tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const;
+ void traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const;
void classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
Fps displayFrameRenderRate, nsecs_t* outDeadlineDelta) REQUIRES(mMutex);
@@ -367,9 +370,15 @@
class FrameTimeline : public android::frametimeline::FrameTimeline {
public:
class FrameTimelineDataSource : public perfetto::DataSource<FrameTimelineDataSource> {
- void OnSetup(const SetupArgs&) override{};
- void OnStart(const StartArgs&) override{};
- void OnStop(const StopArgs&) override{};
+ public:
+ nsecs_t getStartTime() const { return mTraceStartTime; }
+
+ private:
+ void OnSetup(const SetupArgs&) override {};
+ void OnStart(const StartArgs&) override { mTraceStartTime = systemTime(); };
+ void OnStop(const StopArgs&) override {};
+
+ nsecs_t mTraceStartTime = 0;
};
/*
@@ -390,7 +399,8 @@
// is enabled. monoBootOffset is the difference between SYSTEM_TIME_BOOTTIME
// and SYSTEM_TIME_MONOTONIC.
nsecs_t trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset,
- nsecs_t previousPredictionPresentTime) const;
+ nsecs_t previousPredictionPresentTime,
+ bool filterFramesBeforeTraceStarts) const;
// Sets the token, vsyncPeriod, predictions and SF start time.
void onSfWakeUp(int64_t token, Fps refreshRate, Fps renderRate,
std::optional<TimelineItem> predictions, nsecs_t wakeUpTime);
@@ -424,10 +434,13 @@
private:
void dump(std::string& result, nsecs_t baseTime) const;
- void tracePredictions(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const;
- void traceActuals(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const;
+ void tracePredictions(pid_t surfaceFlingerPid, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const;
+ void traceActuals(pid_t surfaceFlingerPid, nsecs_t monoBootOffset,
+ bool filterFramesBeforeTraceStarts) const;
void addSkippedFrame(pid_t surfaceFlingerPid, nsecs_t monoBootOffset,
- nsecs_t previousActualPresentTime) const;
+ nsecs_t previousActualPresentTime,
+ bool filterFramesBeforeTraceStarts) const;
void classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync,
nsecs_t previousPresentTime);
@@ -471,7 +484,8 @@
};
FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
- JankClassificationThresholds thresholds = {}, bool useBootTimeClock = true);
+ JankClassificationThresholds thresholds = {}, bool useBootTimeClock = true,
+ bool filterFramesBeforeTraceStarts = true);
~FrameTimeline() = default;
frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
@@ -516,6 +530,7 @@
TraceCookieCounter mTraceCookieCounter;
mutable std::mutex mMutex;
const bool mUseBootTimeClock;
+ const bool mFilterFramesBeforeTraceStarts;
uint32_t mMaxDisplayFrames;
std::shared_ptr<TimeStats> mTimeStats;
const pid_t mSurfaceFlingerPid;
diff --git a/services/surfaceflinger/FrontEnd/Update.h b/services/surfaceflinger/FrontEnd/Update.h
index e5cca8f..4af27ab 100644
--- a/services/surfaceflinger/FrontEnd/Update.h
+++ b/services/surfaceflinger/FrontEnd/Update.h
@@ -22,28 +22,13 @@
#include "RequestedLayerState.h"
#include "TransactionState.h"
-namespace android {
-struct LayerCreatedState {
- LayerCreatedState(const wp<Layer>& layer, const wp<Layer>& parent, bool addToRoot)
- : layer(layer), initialParent(parent), addToRoot(addToRoot) {}
- wp<Layer> layer;
- // Indicates the initial parent of the created layer, only used for creating layer in
- // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers.
- wp<Layer> initialParent;
- // Indicates whether the layer getting created should be added at root if there's no parent
- // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will
- // be added offscreen.
- bool addToRoot;
-};
-} // namespace android
-
namespace android::surfaceflinger::frontend {
// Atomic set of changes affecting layer state. These changes are queued in binder threads and
// applied every vsync.
struct Update {
std::vector<TransactionState> transactions;
- std::vector<LayerCreatedState> layerCreatedStates;
+ std::vector<sp<Layer>> legacyLayers;
std::vector<std::unique_ptr<frontend::RequestedLayerState>> newLayers;
std::vector<LayerCreationArgs> layerCreationArgs;
std::vector<std::pair<uint32_t, std::string /* debugName */>> destroyedHandles;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 636f7bd..c8bb068 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -60,9 +60,7 @@
#include <utils/StopWatch.h>
#include <algorithm>
-#include <mutex>
#include <optional>
-#include <sstream>
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
@@ -72,7 +70,6 @@
#include "FrontEnd/LayerHandle.h"
#include "Layer.h"
#include "LayerProtoHelper.h"
-#include "MutexUtils.h"
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
#include "TransactionCallbackInvoker.h"
@@ -89,18 +86,6 @@
const ui::Transform kIdentityTransform;
-ui::LogicalDisplayId toLogicalDisplayId(const ui::LayerStack& layerStack) {
- return ui::LogicalDisplayId{static_cast<int32_t>(layerStack.id)};
-}
-
-bool assignTransform(ui::Transform* dst, ui::Transform& from) {
- if (*dst == from) {
- return false;
- }
- *dst = from;
- return true;
-}
-
TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
@@ -149,24 +134,11 @@
: sequence(args.sequence),
mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)),
mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
- mClientRef(args.client),
mWindowType(static_cast<WindowInfo::Type>(
- args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))),
- mLayerCreationFlags(args.flags),
- mLegacyLayerFE(args.flinger->getFactory().createLayerFE(mName, this)) {
+ args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))) {
ALOGV("Creating Layer %s", getDebugName());
- uint32_t layerFlags = 0;
- if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
- if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
- if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
- if (args.flags & ISurfaceComposerClient::eSkipScreenshot)
- layerFlags |= layer_state_t::eLayerSkipScreenshot;
- mDrawingState.flags = layerFlags;
mDrawingState.crop.makeInvalid();
- mDrawingState.z = 0;
- mDrawingState.color.a = 1.0f;
- mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK;
mDrawingState.sequence = 0;
mDrawingState.transform.set(0, 0);
mDrawingState.frameNumber = 0;
@@ -179,33 +151,9 @@
mDrawingState.acquireFence = sp<Fence>::make(-1);
mDrawingState.acquireFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
mDrawingState.dataspace = ui::Dataspace::V0_SRGB;
- mDrawingState.hdrMetadata.validTypes = 0;
- mDrawingState.surfaceDamageRegion = Region::INVALID_REGION;
- mDrawingState.cornerRadius = 0.0f;
- mDrawingState.backgroundBlurRadius = 0;
- mDrawingState.api = -1;
- mDrawingState.hasColorTransform = false;
- mDrawingState.colorSpaceAgnostic = false;
- mDrawingState.frameRateSelectionPriority = PRIORITY_UNSET;
mDrawingState.metadata = args.metadata;
- mDrawingState.shadowRadius = 0.f;
- mDrawingState.fixedTransformHint = ui::Transform::ROT_INVALID;
mDrawingState.frameTimelineInfo = {};
mDrawingState.postTime = -1;
- mDrawingState.destinationFrame.makeInvalid();
- mDrawingState.isTrustedOverlay = false;
- mDrawingState.dropInputMode = gui::DropInputMode::NONE;
- mDrawingState.dimmingEnabled = true;
- mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default;
- mDrawingState.frameRateSelectionStrategy = FrameRateSelectionStrategy::Propagate;
-
- if (args.flags & ISurfaceComposerClient::eNoColorFill) {
- // Set an invalid color so there is no color fill.
- mDrawingState.color.r = -1.0_hf;
- mDrawingState.color.g = -1.0_hf;
- mDrawingState.color.b = -1.0_hf;
- }
-
mFrameTracker.setDisplayRefreshPeriod(
args.flinger->mScheduler->getPacesetterVsyncPeriod().ns());
@@ -213,14 +161,9 @@
mOwnerPid = args.ownerPid;
mOwnerAppId = mOwnerUid % PER_USER_RANGE;
- mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
- mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;
-
- mSnapshot->sequence = sequence;
- mSnapshot->name = getDebugName();
- mSnapshot->premultipliedAlpha = mPremultipliedAlpha;
- mSnapshot->parentTransform = {};
+ mLayerFEs.emplace_back(frontend::LayerHierarchy::TraversalPath{static_cast<uint32_t>(sequence)},
+ args.flinger->getFactory().createLayerFE(mName, this));
}
void Layer::onFirstRef() {
@@ -231,10 +174,6 @@
LOG_ALWAYS_FATAL_IF(std::this_thread::get_id() != mFlinger->mMainThreadId,
"Layer destructor called off the main thread.");
- // The original layer and the clone layer share the same texture and buffer. Therefore, only
- // one of the layers, in this case the original layer, needs to handle the deletion. The
- // original layer and the clone should be removed at the same time so there shouldn't be any
- // issue with the clone layer trying to use the texture.
if (mBufferInfo.mBuffer != nullptr) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
@@ -250,10 +189,6 @@
if (mDrawingState.sidebandStream != nullptr) {
mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
}
- if (mHadClonedChild) {
- auto& roots = mFlinger->mLayerMirrorRoots;
- roots.erase(std::remove(roots.begin(), roots.end(), this), roots.end());
- }
if (hasTrustedPresentationListener()) {
mFlinger->mNumTrustedPresentationListeners--;
updateTrustedPresentationState(nullptr, nullptr, -1 /* time_in_ms */, true /* leaveState*/);
@@ -261,77 +196,8 @@
}
// ---------------------------------------------------------------------------
-// callbacks
-// ---------------------------------------------------------------------------
-
-void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
- if (mDrawingState.zOrderRelativeOf == nullptr) {
- return;
- }
-
- sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote();
- if (strongRelative == nullptr) {
- setZOrderRelativeOf(nullptr);
- return;
- }
-
- if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
- strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
- mFlinger->setTransactionFlags(eTraversalNeeded);
- setZOrderRelativeOf(nullptr);
- }
-}
-
-void Layer::removeFromCurrentState() {
- if (!mRemovedFromDrawingState) {
- mRemovedFromDrawingState = true;
- mFlinger->mScheduler->deregisterLayer(this);
- }
- updateTrustedPresentationState(nullptr, nullptr, -1 /* time_in_ms */, true /* leaveState*/);
-
- mFlinger->markLayerPendingRemovalLocked(sp<Layer>::fromExisting(this));
-}
-
-sp<Layer> Layer::getRootLayer() {
- sp<Layer> parent = getParent();
- if (parent == nullptr) {
- return sp<Layer>::fromExisting(this);
- }
- return parent->getRootLayer();
-}
-
-void Layer::onRemovedFromCurrentState() {
- // Use the root layer since we want to maintain the hierarchy for the entire subtree.
- auto layersInTree = getRootLayer()->getLayersInTree(LayerVector::StateSet::Current);
- std::sort(layersInTree.begin(), layersInTree.end());
-
- REQUIRE_MUTEX(mFlinger->mStateLock);
- traverse(LayerVector::StateSet::Current,
- [&](Layer* layer) REQUIRES(layer->mFlinger->mStateLock) {
- layer->removeFromCurrentState();
- layer->removeRelativeZ(layersInTree);
- });
-}
-
-void Layer::addToCurrentState() {
- if (mRemovedFromDrawingState) {
- mRemovedFromDrawingState = false;
- mFlinger->mScheduler->registerLayer(this, FrameRateCompatibility::Default);
- }
-
- for (const auto& child : mCurrentChildren) {
- child->addToCurrentState();
- }
-}
-
-// ---------------------------------------------------------------------------
// set-up
// ---------------------------------------------------------------------------
-
-bool Layer::getPremultipledAlpha() const {
- return mPremultipliedAlpha;
-}
-
sp<IBinder> Layer::getHandle() {
Mutex::Autolock _l(mLock);
if (mGetHandleCalled) {
@@ -347,46 +213,6 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-static Rect reduce(const Rect& win, const Region& exclude) {
- if (CC_LIKELY(exclude.isEmpty())) {
- return win;
- }
- if (exclude.isRect()) {
- return win.reduce(exclude.getBounds());
- }
- return Region(win).subtract(exclude).getBounds();
-}
-
-static FloatRect reduce(const FloatRect& win, const Region& exclude) {
- if (CC_LIKELY(exclude.isEmpty())) {
- return win;
- }
- // Convert through Rect (by rounding) for lack of FloatRegion
- return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
-}
-
-Rect Layer::getScreenBounds(bool reduceTransparentRegion) const {
- if (!reduceTransparentRegion) {
- return Rect{mScreenBounds};
- }
-
- FloatRect bounds = getBounds();
- ui::Transform t = getTransform();
- // Transform to screen space.
- bounds = t.transform(bounds);
- return Rect{bounds};
-}
-
-FloatRect Layer::getBounds() const {
- const State& s(getDrawingState());
- return getBounds(getActiveTransparentRegion(s));
-}
-
-FloatRect Layer::getBounds(const Region& activeTransparentRegion) const {
- // Subtract the transparent region and snap to the bounds.
- return reduce(mBounds, activeTransparentRegion);
-}
-
// No early returns.
void Layer::updateTrustedPresentationState(const DisplayDevice* display,
const frontend::LayerSnapshot* snapshot,
@@ -488,57 +314,6 @@
return true;
}
-void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform,
- float parentShadowRadius) {
- const State& s(getDrawingState());
-
- // Calculate effective layer transform
- mEffectiveTransform = parentTransform * getActiveTransform(s);
-
- if (CC_UNLIKELY(!isTransformValid())) {
- ALOGW("Stop computing bounds for %s because it has invalid transformation.",
- getDebugName());
- return;
- }
-
- // Transform parent bounds to layer space
- parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
-
- // Calculate source bounds
- mSourceBounds = computeSourceBounds(parentBounds);
-
- // Calculate bounds by croping diplay frame with layer crop and parent bounds
- FloatRect bounds = mSourceBounds;
- const Rect layerCrop = getCrop(s);
- if (!layerCrop.isEmpty()) {
- bounds = mSourceBounds.intersect(layerCrop.toFloatRect());
- }
- bounds = bounds.intersect(parentBounds);
-
- mBounds = bounds;
- mScreenBounds = mEffectiveTransform.transform(mBounds);
-
- // Use the layer's own shadow radius if set. Otherwise get the radius from
- // parent.
- if (s.shadowRadius > 0.f) {
- mEffectiveShadowRadius = s.shadowRadius;
- } else {
- mEffectiveShadowRadius = parentShadowRadius;
- }
-
- // Shadow radius is passed down to only one layer so if the layer can draw shadows,
- // don't pass it to its children.
- const float childShadowRadius = canDrawShadows() ? 0.f : mEffectiveShadowRadius;
-
- for (const sp<Layer>& child : mDrawingChildren) {
- child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius);
- }
-
- if (mPotentialCursor) {
- prepareCursorCompositionState();
- }
-}
-
Rect Layer::getCroppedBufferSize(const State& s) const {
Rect size = getBufferSize(s);
Rect crop = getCrop(s);
@@ -550,181 +325,6 @@
return size;
}
-void Layer::setupRoundedCornersCropCoordinates(Rect win,
- const FloatRect& roundedCornersCrop) const {
- // Translate win by the rounded corners rect coordinates, to have all values in
- // layer coordinate space.
- win.left -= roundedCornersCrop.left;
- win.right -= roundedCornersCrop.left;
- win.top -= roundedCornersCrop.top;
- win.bottom -= roundedCornersCrop.top;
-}
-
-void Layer::prepareBasicGeometryCompositionState() {
- const auto& drawingState{getDrawingState()};
- const auto alpha = static_cast<float>(getAlpha());
- const bool opaque = isOpaque(drawingState);
- const bool usesRoundedCorners = hasRoundedCorners();
-
- auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
- if (!opaque || alpha != 1.0f) {
- blendMode = mPremultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED
- : Hwc2::IComposerClient::BlendMode::COVERAGE;
- }
-
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
- snapshot->outputFilter = getOutputFilter();
- snapshot->isVisible = isVisible();
- snapshot->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
- snapshot->shadowSettings.length = mEffectiveShadowRadius;
-
- snapshot->contentDirty = contentDirty;
- contentDirty = false;
-
- snapshot->geomLayerBounds = mBounds;
- snapshot->geomLayerTransform = getTransform();
- snapshot->geomInverseLayerTransform = snapshot->geomLayerTransform.inverse();
- snapshot->transparentRegionHint = getActiveTransparentRegion(drawingState);
- snapshot->localTransform = getActiveTransform(drawingState);
- snapshot->localTransformInverse = snapshot->localTransform.inverse();
- snapshot->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
- snapshot->alpha = alpha;
- snapshot->backgroundBlurRadius = getBackgroundBlurRadius();
- snapshot->blurRegions = getBlurRegions();
- snapshot->stretchEffect = getStretchEffect();
-}
-
-void Layer::prepareGeometryCompositionState() {
- const auto& drawingState{getDrawingState()};
- auto* snapshot = editLayerSnapshot();
-
- // Please keep in sync with LayerSnapshotBuilder
- snapshot->geomBufferSize = getBufferSize(drawingState);
- snapshot->geomContentCrop = getBufferCrop();
- snapshot->geomCrop = getCrop(drawingState);
- snapshot->geomBufferTransform = getBufferTransform();
- snapshot->geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse();
- snapshot->geomUsesSourceCrop = usesSourceCrop();
- snapshot->isSecure = isSecure();
-
- snapshot->metadata.clear();
- const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
- for (const auto& [key, mandatory] : supportedMetadata) {
- const auto& genericLayerMetadataCompatibilityMap =
- mFlinger->getGenericLayerMetadataKeyMap();
- auto compatIter = genericLayerMetadataCompatibilityMap.find(key);
- if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) {
- continue;
- }
- const uint32_t id = compatIter->second;
-
- auto it = drawingState.metadata.mMap.find(id);
- if (it == std::end(drawingState.metadata.mMap)) {
- continue;
- }
-
- snapshot->metadata.emplace(key,
- compositionengine::GenericLayerMetadataEntry{mandatory,
- it->second});
- }
-}
-
-void Layer::preparePerFrameCompositionState() {
- const auto& drawingState{getDrawingState()};
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
-
- snapshot->forceClientComposition = false;
-
- snapshot->isColorspaceAgnostic = isColorSpaceAgnostic();
- snapshot->dataspace = getDataSpace();
- snapshot->colorTransform = getColorTransform();
- snapshot->colorTransformIsIdentity = !hasColorTransform();
- snapshot->surfaceDamage = surfaceDamageRegion;
- snapshot->hasProtectedContent = isProtected();
- snapshot->dimmingEnabled = isDimmingEnabled();
- snapshot->currentHdrSdrRatio = getCurrentHdrSdrRatio();
- snapshot->desiredHdrSdrRatio = getDesiredHdrSdrRatio();
- snapshot->cachingHint = getCachingHint();
-
- const bool usesRoundedCorners = hasRoundedCorners();
-
- snapshot->isOpaque = isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
-
- // Force client composition for special cases known only to the front-end.
- // Rounded corners no longer force client composition, since we may use a
- // hole punch so that the layer will appear to have rounded corners.
- if (drawShadows() || snapshot->stretchEffect.hasEffect()) {
- snapshot->forceClientComposition = true;
- }
- // If there are no visible region changes, we still need to update blur parameters.
- snapshot->blurRegions = getBlurRegions();
- snapshot->backgroundBlurRadius = getBackgroundBlurRadius();
-
- // Layer framerate is used in caching decisions.
- // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in
- // LayerFECompositionState where it would be visible to Flattener.
- snapshot->fps = mFlinger->getLayerFramerate(systemTime(), getSequence());
-
- if (hasBufferOrSidebandStream()) {
- preparePerFrameBufferCompositionState();
- } else {
- preparePerFrameEffectsCompositionState();
- }
-}
-
-void Layer::preparePerFrameBufferCompositionState() {
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
- // Sideband layers
- if (snapshot->sidebandStream.get() && !snapshot->sidebandStreamHasFrame) {
- snapshot->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::SIDEBAND;
- return;
- } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) {
- snapshot->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
- } else if ((mDrawingState.flags & layer_state_t::eLayerIsRefreshRateIndicator) != 0) {
- snapshot->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::REFRESH_RATE_INDICATOR;
- } else {
- // Normal buffer layers
- snapshot->hdrMetadata = mBufferInfo.mHdrMetadata;
- snapshot->compositionType = mPotentialCursor
- ? aidl::android::hardware::graphics::composer3::Composition::CURSOR
- : aidl::android::hardware::graphics::composer3::Composition::DEVICE;
- }
-
- snapshot->buffer = getBuffer();
- snapshot->acquireFence = mBufferInfo.mFence;
- snapshot->frameNumber = mBufferInfo.mFrameNumber;
- snapshot->sidebandStreamHasFrame = false;
-}
-
-void Layer::preparePerFrameEffectsCompositionState() {
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
- snapshot->color = getColor();
- snapshot->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
-}
-
-void Layer::prepareCursorCompositionState() {
- const State& drawingState{getDrawingState()};
- // Please keep in sync with LayerSnapshotBuilder
- auto* snapshot = editLayerSnapshot();
-
- // Apply the layer's transform, followed by the display's global transform
- // Here we're guaranteed that the layer's transform preserves rects
- Rect win = getCroppedBufferSize(drawingState);
- // Subtract the transparent region and snap to the bounds
- Rect bounds = reduce(win, getActiveTransparentRegion(drawingState));
- Rect frame(getTransform().transform(bounds));
-
- snapshot->cursorFrame = frame;
-}
-
const char* Layer::getDebugName() const {
return mName.c_str();
}
@@ -752,45 +352,18 @@
}
// ----------------------------------------------------------------------------
-// local state
-// ----------------------------------------------------------------------------
-
-bool Layer::isSecure() const {
- const State& s(mDrawingState);
- if (s.flags & layer_state_t::eLayerSecure) {
- return true;
- }
-
- const auto p = mDrawingParent.promote();
- return (p != nullptr) ? p->isSecure() : false;
-}
-
-// ----------------------------------------------------------------------------
// transaction
// ----------------------------------------------------------------------------
uint32_t Layer::doTransaction(uint32_t flags) {
SFTRACE_CALL();
- // TODO: This is unfortunate.
- mDrawingStateModified = mDrawingState.modified;
- mDrawingState.modified = false;
-
const State& s(getDrawingState());
- if (updateGeometry()) {
- // invalidate and recompute the visible regions if needed
- flags |= Layer::eVisibleRegion;
- }
-
if (s.sequence != mLastCommittedTxSequence) {
// invalidate and recompute the visible regions if needed
mLastCommittedTxSequence = s.sequence;
flags |= eVisibleRegion;
- this->contentDirty = true;
-
- // we may use linear filtering, if the matrix scales us
- mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering();
}
if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) {
@@ -826,275 +399,11 @@
mTransactionFlags |= mask;
}
-bool Layer::setChildLayer(const sp<Layer>& childLayer, int32_t z) {
- ssize_t idx = mCurrentChildren.indexOf(childLayer);
- if (idx < 0) {
- return false;
- }
- if (childLayer->setLayer(z)) {
- mCurrentChildren.removeAt(idx);
- mCurrentChildren.add(childLayer);
- return true;
- }
- return false;
-}
-
-bool Layer::setChildRelativeLayer(const sp<Layer>& childLayer,
- const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
- ssize_t idx = mCurrentChildren.indexOf(childLayer);
- if (idx < 0) {
- return false;
- }
- if (childLayer->setRelativeLayer(relativeToHandle, relativeZ)) {
- mCurrentChildren.removeAt(idx);
- mCurrentChildren.add(childLayer);
- return true;
- }
- return false;
-}
-
-bool Layer::setLayer(int32_t z) {
- if (mDrawingState.z == z && !usingRelativeZ(LayerVector::StateSet::Current)) return false;
- mDrawingState.sequence++;
- mDrawingState.z = z;
- mDrawingState.modified = true;
-
- mFlinger->mSomeChildrenChanged = true;
-
- // Discard all relative layering.
- if (mDrawingState.zOrderRelativeOf != nullptr) {
- sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote();
- if (strongRelative != nullptr) {
- strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
- }
- setZOrderRelativeOf(nullptr);
- }
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-void Layer::removeZOrderRelative(const wp<Layer>& relative) {
- mDrawingState.zOrderRelatives.remove(relative);
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-}
-
-void Layer::addZOrderRelative(const wp<Layer>& relative) {
- mDrawingState.zOrderRelatives.add(relative);
- mDrawingState.modified = true;
- mDrawingState.sequence++;
- setTransactionFlags(eTransactionNeeded);
-}
-
-void Layer::setZOrderRelativeOf(const wp<Layer>& relativeOf) {
- mDrawingState.zOrderRelativeOf = relativeOf;
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- mDrawingState.isRelativeOf = relativeOf != nullptr;
-
- setTransactionFlags(eTransactionNeeded);
-}
-
-bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
- sp<Layer> relative = LayerHandle::getLayer(relativeToHandle);
- if (relative == nullptr) {
- return false;
- }
-
- if (mDrawingState.z == relativeZ && usingRelativeZ(LayerVector::StateSet::Current) &&
- mDrawingState.zOrderRelativeOf == relative) {
- return false;
- }
-
- if (CC_UNLIKELY(relative->usingRelativeZ(LayerVector::StateSet::Drawing)) &&
- (relative->mDrawingState.zOrderRelativeOf == this)) {
- ALOGE("Detected relative layer loop between %s and %s",
- mName.c_str(), relative->mName.c_str());
- ALOGE("Ignoring new call to set relative layer");
- return false;
- }
-
- mFlinger->mSomeChildrenChanged = true;
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- mDrawingState.z = relativeZ;
-
- auto oldZOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
- if (oldZOrderRelativeOf != nullptr) {
- oldZOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this));
- }
- setZOrderRelativeOf(relative);
- relative->addZOrderRelative(wp<Layer>::fromExisting(this));
-
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
-bool Layer::setTrustedOverlay(bool isTrustedOverlay) {
- if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false;
- mDrawingState.isTrustedOverlay = isTrustedOverlay;
- mDrawingState.modified = true;
- mFlinger->mUpdateInputInfo = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::isTrustedOverlay() const {
- if (getDrawingState().isTrustedOverlay) {
- return true;
- }
- const auto& p = mDrawingParent.promote();
- return (p != nullptr) && p->isTrustedOverlay();
-}
-
-bool Layer::setAlpha(float alpha) {
- if (mDrawingState.color.a == alpha) return false;
- mDrawingState.sequence++;
- mDrawingState.color.a = alpha;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace) {
- if (!mDrawingState.bgColorLayer && alpha == 0) {
- return false;
- }
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- if (!mDrawingState.bgColorLayer && alpha != 0) {
- // create background color layer if one does not yet exist
- uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect;
- std::string name = mName + "BackgroundColorLayer";
- mDrawingState.bgColorLayer = mFlinger->getFactory().createEffectLayer(
- surfaceflinger::LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), flags,
- LayerMetadata()));
-
- // add to child list
- addChild(mDrawingState.bgColorLayer);
- mFlinger->mLayersAdded = true;
- // set up SF to handle added color layer
- if (isRemovedFromCurrentState()) {
- MUTEX_ALIAS(mFlinger->mStateLock, mDrawingState.bgColorLayer->mFlinger->mStateLock);
- mDrawingState.bgColorLayer->onRemovedFromCurrentState();
- }
- mFlinger->setTransactionFlags(eTransactionNeeded);
- } else if (mDrawingState.bgColorLayer && alpha == 0) {
- MUTEX_ALIAS(mFlinger->mStateLock, mDrawingState.bgColorLayer->mFlinger->mStateLock);
- mDrawingState.bgColorLayer->reparent(nullptr);
- mDrawingState.bgColorLayer = nullptr;
- return true;
- }
-
- mDrawingState.bgColorLayer->setColor(color);
- mDrawingState.bgColorLayer->setLayer(std::numeric_limits<int32_t>::min());
- mDrawingState.bgColorLayer->setAlpha(alpha);
- mDrawingState.bgColorLayer->setDataspace(dataspace);
-
- return true;
-}
-
-bool Layer::setCornerRadius(float cornerRadius) {
- if (mDrawingState.cornerRadius == cornerRadius) return false;
-
- mDrawingState.sequence++;
- mDrawingState.cornerRadius = cornerRadius;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) {
- if (mDrawingState.backgroundBlurRadius == backgroundBlurRadius) return false;
- // If we start or stop drawing blur then the layer's visibility state may change so increment
- // the magic sequence number.
- if (mDrawingState.backgroundBlurRadius == 0 || backgroundBlurRadius == 0) {
- mDrawingState.sequence++;
- }
- mDrawingState.backgroundBlurRadius = backgroundBlurRadius;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setTransparentRegionHint(const Region& transparent) {
- mDrawingState.sequence++;
- mDrawingState.transparentRegionHint = transparent;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
- // If we start or stop drawing blur then the layer's visibility state may change so increment
- // the magic sequence number.
- if (mDrawingState.blurRegions.size() == 0 || blurRegions.size() == 0) {
- mDrawingState.sequence++;
- }
- mDrawingState.blurRegions = blurRegions;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setFlags(uint32_t flags, uint32_t mask) {
- const uint32_t newFlags = (mDrawingState.flags & ~mask) | (flags & mask);
- if (mDrawingState.flags == newFlags) return false;
- mDrawingState.sequence++;
- mDrawingState.flags = newFlags;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
bool Layer::setCrop(const Rect& crop) {
if (mDrawingState.crop == crop) return false;
mDrawingState.sequence++;
mDrawingState.crop = crop;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setMetadata(const LayerMetadata& data) {
- if (!mDrawingState.metadata.merge(data, true /* eraseEmpty */)) return false;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setLayerStack(ui::LayerStack layerStack) {
- if (mDrawingState.layerStack == layerStack) return false;
- mDrawingState.sequence++;
- mDrawingState.layerStack = layerStack;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setColorSpaceAgnostic(const bool agnostic) {
- if (mDrawingState.colorSpaceAgnostic == agnostic) {
- return false;
- }
- mDrawingState.sequence++;
- mDrawingState.colorSpaceAgnostic = agnostic;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setDimmingEnabled(const bool dimmingEnabled) {
- if (mDrawingState.dimmingEnabled == dimmingEnabled) return false;
-
- mDrawingState.sequence++;
- mDrawingState.dimmingEnabled = dimmingEnabled;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1103,68 +412,6 @@
return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
};
-ui::LayerStack Layer::getLayerStack(LayerVector::StateSet state) const {
- bool useDrawing = state == LayerVector::StateSet::Drawing;
- const auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
- if (parent) {
- return parent->getLayerStack();
- }
- return getDrawingState().layerStack;
-}
-
-bool Layer::setShadowRadius(float shadowRadius) {
- if (mDrawingState.shadowRadius == shadowRadius) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.shadowRadius = shadowRadius;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint) {
- if (mDrawingState.fixedTransformHint == fixedTransformHint) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.fixedTransformHint = fixedTransformHint;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setStretchEffect(const StretchEffect& effect) {
- StretchEffect temp = effect;
- temp.sanitize();
- if (mDrawingState.stretchEffect == temp) {
- return false;
- }
- mDrawingState.sequence++;
- mDrawingState.stretchEffect = temp;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-StretchEffect Layer::getStretchEffect() const {
- if (mDrawingState.stretchEffect.hasEffect()) {
- return mDrawingState.stretchEffect;
- }
-
- sp<Layer> parent = getParent();
- if (parent != nullptr) {
- auto effect = parent->getStretchEffect();
- if (effect.hasEffect()) {
- // TODO(b/179047472): Map it? Or do we make the effect be in global space?
- return effect;
- }
- }
- return StretchEffect{};
-}
-
void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info,
nsecs_t postTime, gui::GameMode gameMode) {
mDrawingState.postTime = postTime;
@@ -1193,7 +440,6 @@
gui::GameMode gameMode) {
mDrawingState.frameTimelineInfo = info;
mDrawingState.postTime = postTime;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
if (const auto& bufferSurfaceFrameTX = mDrawingState.bufferSurfaceFrameTX;
@@ -1315,40 +561,6 @@
return getDrawingState().frameRateForLayerTree;
}
-bool Layer::isHiddenByPolicy() const {
- const State& s(mDrawingState);
- const auto& parent = mDrawingParent.promote();
- if (parent != nullptr && parent->isHiddenByPolicy()) {
- return true;
- }
- if (usingRelativeZ(LayerVector::StateSet::Drawing)) {
- auto zOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
- if (zOrderRelativeOf != nullptr) {
- if (zOrderRelativeOf->isHiddenByPolicy()) {
- return true;
- }
- }
- }
- if (CC_UNLIKELY(!isTransformValid())) {
- ALOGW("Hide layer %s because it has invalid transformation.", getDebugName());
- return true;
- }
- return s.flags & layer_state_t::eLayerHidden;
-}
-
-uint32_t Layer::getEffectiveUsage(uint32_t usage) const {
- // TODO: should we do something special if mSecure is set?
- if (mProtectedByApp) {
- // need a hardware-protected path to external video sink
- usage |= GraphicBuffer::USAGE_PROTECTED;
- }
- if (mPotentialCursor) {
- usage |= GraphicBuffer::USAGE_CURSOR;
- }
- usage |= GraphicBuffer::USAGE_HW_COMPOSER;
- return usage;
-}
-
// ----------------------------------------------------------------------------
// debugging
// ----------------------------------------------------------------------------
@@ -1427,489 +639,12 @@
mFrameTracker.getStats(outStats);
}
-void Layer::dumpOffscreenDebugInfo(std::string& result) const {
- std::string hasBuffer = hasBufferOrSidebandStream() ? " (contains buffer)" : "";
- StringAppendF(&result, "Layer %s%s pid:%d uid:%d%s\n", getName().c_str(), hasBuffer.c_str(),
- mOwnerPid, mOwnerUid, isHandleAlive() ? " handleAlive" : "");
-}
-
void Layer::onDisconnect() {
const int32_t layerId = getSequence();
mFlinger->mTimeStats->onDestroy(layerId);
mFlinger->mFrameTracer->onDestroy(layerId);
}
-size_t Layer::getDescendantCount() const {
- size_t count = 0;
- for (const sp<Layer>& child : mDrawingChildren) {
- count += 1 + child->getChildrenCount();
- }
- return count;
-}
-
-void Layer::addChild(const sp<Layer>& layer) {
- mFlinger->mSomeChildrenChanged = true;
- setTransactionFlags(eTransactionNeeded);
-
- mCurrentChildren.add(layer);
- layer->setParent(sp<Layer>::fromExisting(this));
-}
-
-ssize_t Layer::removeChild(const sp<Layer>& layer) {
- mFlinger->mSomeChildrenChanged = true;
- setTransactionFlags(eTransactionNeeded);
-
- layer->setParent(nullptr);
- const auto removeResult = mCurrentChildren.remove(layer);
-
- return removeResult;
-}
-
-void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
- for (const sp<Layer>& child : mDrawingChildren) {
- child->mDrawingParent = newParent;
- const float parentShadowRadius =
- newParent->canDrawShadows() ? 0.f : newParent->mEffectiveShadowRadius;
- child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
- parentShadowRadius);
- }
-}
-
-bool Layer::reparent(const sp<IBinder>& newParentHandle) {
- sp<Layer> newParent;
- if (newParentHandle != nullptr) {
- newParent = LayerHandle::getLayer(newParentHandle);
- if (newParent == nullptr) {
- ALOGE("Unable to promote Layer handle");
- return false;
- }
- if (newParent == this) {
- ALOGE("Invalid attempt to reparent Layer (%s) to itself", getName().c_str());
- return false;
- }
- }
-
- sp<Layer> parent = getParent();
- if (parent != nullptr) {
- parent->removeChild(sp<Layer>::fromExisting(this));
- }
-
- if (newParentHandle != nullptr) {
- newParent->addChild(sp<Layer>::fromExisting(this));
- if (!newParent->isRemovedFromCurrentState()) {
- addToCurrentState();
- } else {
- onRemovedFromCurrentState();
- }
- } else {
- onRemovedFromCurrentState();
- }
-
- return true;
-}
-
-bool Layer::setColorTransform(const mat4& matrix) {
- static const mat4 identityMatrix = mat4();
-
- if (mDrawingState.colorTransform == matrix) {
- return false;
- }
- ++mDrawingState.sequence;
- mDrawingState.colorTransform = matrix;
- mDrawingState.hasColorTransform = matrix != identityMatrix;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-mat4 Layer::getColorTransform() const {
- mat4 colorTransform = mat4(getDrawingState().colorTransform);
- if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
- colorTransform = parent->getColorTransform() * colorTransform;
- }
- return colorTransform;
-}
-
-bool Layer::hasColorTransform() const {
- bool hasColorTransform = getDrawingState().hasColorTransform;
- if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
- hasColorTransform = hasColorTransform || parent->hasColorTransform();
- }
- return hasColorTransform;
-}
-
-bool Layer::isLegacyDataSpace() const {
- // return true when no higher bits are set
- return !(getDataSpace() &
- (ui::Dataspace::STANDARD_MASK | ui::Dataspace::TRANSFER_MASK |
- ui::Dataspace::RANGE_MASK));
-}
-
-void Layer::setParent(const sp<Layer>& layer) {
- mCurrentParent = layer;
-}
-
-int32_t Layer::getZ(LayerVector::StateSet) const {
- return mDrawingState.z;
-}
-
-bool Layer::usingRelativeZ(LayerVector::StateSet stateSet) const {
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const State& state = useDrawing ? mDrawingState : mDrawingState;
- return state.isRelativeOf;
-}
-
-__attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::makeTraversalList(
- LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers) {
- LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
- "makeTraversalList received invalid stateSet");
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
- const State& state = useDrawing ? mDrawingState : mDrawingState;
-
- if (state.zOrderRelatives.size() == 0) {
- *outSkipRelativeZUsers = true;
- return children;
- }
-
- LayerVector traverse(stateSet);
- for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
- sp<Layer> strongRelative = weakRelative.promote();
- if (strongRelative != nullptr) {
- traverse.add(strongRelative);
- }
- }
-
- for (const sp<Layer>& child : children) {
- if (child->usingRelativeZ(stateSet)) {
- continue;
- }
- traverse.add(child);
- }
-
- return traverse;
-}
-
-/**
- * Negatively signed relatives are before 'this' in Z-order.
- */
-void Layer::traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor) {
- // In the case we have other layers who are using a relative Z to us, makeTraversalList will
- // produce a new list for traversing, including our relatives, and not including our children
- // who are relatives of another surface. In the case that there are no relative Z,
- // makeTraversalList returns our children directly to avoid significant overhead.
- // However in this case we need to take the responsibility for filtering children which
- // are relatives of another surface here.
- bool skipRelativeZUsers = false;
- const LayerVector list = makeTraversalList(stateSet, &skipRelativeZUsers);
-
- size_t i = 0;
- for (; i < list.size(); i++) {
- const auto& relative = list[i];
- if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
- continue;
- }
-
- if (relative->getZ(stateSet) >= 0) {
- break;
- }
- relative->traverseInZOrder(stateSet, visitor);
- }
-
- visitor(this);
- for (; i < list.size(); i++) {
- const auto& relative = list[i];
-
- if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
- continue;
- }
- relative->traverseInZOrder(stateSet, visitor);
- }
-}
-
-/**
- * Positively signed relatives are before 'this' in reverse Z-order.
- */
-void Layer::traverseInReverseZOrder(LayerVector::StateSet stateSet,
- const LayerVector::Visitor& visitor) {
- // See traverseInZOrder for documentation.
- bool skipRelativeZUsers = false;
- LayerVector list = makeTraversalList(stateSet, &skipRelativeZUsers);
-
- int32_t i = 0;
- for (i = int32_t(list.size()) - 1; i >= 0; i--) {
- const auto& relative = list[i];
-
- if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
- continue;
- }
-
- if (relative->getZ(stateSet) < 0) {
- break;
- }
- relative->traverseInReverseZOrder(stateSet, visitor);
- }
- visitor(this);
- for (; i >= 0; i--) {
- const auto& relative = list[i];
-
- if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
- continue;
- }
-
- relative->traverseInReverseZOrder(stateSet, visitor);
- }
-}
-
-void Layer::traverse(LayerVector::StateSet state, const LayerVector::Visitor& visitor) {
- visitor(this);
- const LayerVector& children =
- state == LayerVector::StateSet::Drawing ? mDrawingChildren : mCurrentChildren;
- for (const sp<Layer>& child : children) {
- child->traverse(state, visitor);
- }
-}
-
-void Layer::traverseChildren(const LayerVector::Visitor& visitor) {
- for (const sp<Layer>& child : mDrawingChildren) {
- visitor(child.get());
- }
-}
-
-LayerVector Layer::makeChildrenTraversalList(LayerVector::StateSet stateSet,
- const std::vector<Layer*>& layersInTree) {
- LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
- "makeTraversalList received invalid stateSet");
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
- const State& state = useDrawing ? mDrawingState : mDrawingState;
-
- LayerVector traverse(stateSet);
- for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
- sp<Layer> strongRelative = weakRelative.promote();
- // Only add relative layers that are also descendents of the top most parent of the tree.
- // If a relative layer is not a descendent, then it should be ignored.
- if (std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
- traverse.add(strongRelative);
- }
- }
-
- for (const sp<Layer>& child : children) {
- const State& childState = useDrawing ? child->mDrawingState : child->mDrawingState;
- // If a layer has a relativeOf layer, only ignore if the layer it's relative to is a
- // descendent of the top most parent of the tree. If it's not a descendent, then just add
- // the child here since it won't be added later as a relative.
- if (std::binary_search(layersInTree.begin(), layersInTree.end(),
- childState.zOrderRelativeOf.promote().get())) {
- continue;
- }
- traverse.add(child);
- }
-
- return traverse;
-}
-
-void Layer::traverseChildrenInZOrderInner(const std::vector<Layer*>& layersInTree,
- LayerVector::StateSet stateSet,
- const LayerVector::Visitor& visitor) {
- const LayerVector list = makeChildrenTraversalList(stateSet, layersInTree);
-
- size_t i = 0;
- for (; i < list.size(); i++) {
- const auto& relative = list[i];
- if (relative->getZ(stateSet) >= 0) {
- break;
- }
- relative->traverseChildrenInZOrderInner(layersInTree, stateSet, visitor);
- }
-
- visitor(this);
- for (; i < list.size(); i++) {
- const auto& relative = list[i];
- relative->traverseChildrenInZOrderInner(layersInTree, stateSet, visitor);
- }
-}
-
-std::vector<Layer*> Layer::getLayersInTree(LayerVector::StateSet stateSet) {
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
-
- std::vector<Layer*> layersInTree = {this};
- for (size_t i = 0; i < children.size(); i++) {
- const auto& child = children[i];
- std::vector<Layer*> childLayers = child->getLayersInTree(stateSet);
- layersInTree.insert(layersInTree.end(), childLayers.cbegin(), childLayers.cend());
- }
-
- return layersInTree;
-}
-
-void Layer::traverseChildrenInZOrder(LayerVector::StateSet stateSet,
- const LayerVector::Visitor& visitor) {
- std::vector<Layer*> layersInTree = getLayersInTree(stateSet);
- std::sort(layersInTree.begin(), layersInTree.end());
- traverseChildrenInZOrderInner(layersInTree, stateSet, visitor);
-}
-
-ui::Transform Layer::getTransform() const {
- return mEffectiveTransform;
-}
-
-bool Layer::isTransformValid() const {
- float transformDet = getTransform().det();
- return transformDet != 0 && !isinf(transformDet) && !isnan(transformDet);
-}
-
-half Layer::getAlpha() const {
- const auto& p = mDrawingParent.promote();
-
- half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
- return parentAlpha * getDrawingState().color.a;
-}
-
-ui::Transform::RotationFlags Layer::getFixedTransformHint() const {
- ui::Transform::RotationFlags fixedTransformHint = mDrawingState.fixedTransformHint;
- if (fixedTransformHint != ui::Transform::ROT_INVALID) {
- return fixedTransformHint;
- }
- const auto& p = mCurrentParent.promote();
- if (!p) return fixedTransformHint;
- return p->getFixedTransformHint();
-}
-
-half4 Layer::getColor() const {
- const half4 color(getDrawingState().color);
- return half4(color.r, color.g, color.b, getAlpha());
-}
-
-int32_t Layer::getBackgroundBlurRadius() const {
- if (getDrawingState().backgroundBlurRadius == 0) {
- return 0;
- }
-
- const auto& p = mDrawingParent.promote();
- half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
- return parentAlpha * getDrawingState().backgroundBlurRadius;
-}
-
-const std::vector<BlurRegion> Layer::getBlurRegions() const {
- auto regionsCopy(getDrawingState().blurRegions);
- float layerAlpha = getAlpha();
- for (auto& region : regionsCopy) {
- region.alpha = region.alpha * layerAlpha;
- }
- return regionsCopy;
-}
-
-RoundedCornerState Layer::getRoundedCornerState() const {
- // Today's DPUs cannot do rounded corners. If RenderEngine cannot render
- // protected content, remove rounded corners from protected content so it
- // can be rendered by the DPU.
- if (isProtected() && !mFlinger->getRenderEngine().supportsProtectedContent()) {
- return {};
- }
-
- // Get parent settings
- RoundedCornerState parentSettings;
- const auto& parent = mDrawingParent.promote();
- if (parent != nullptr) {
- parentSettings = parent->getRoundedCornerState();
- if (parentSettings.hasRoundedCorners()) {
- ui::Transform t = getActiveTransform(getDrawingState());
- t = t.inverse();
- parentSettings.cropRect = t.transform(parentSettings.cropRect);
- parentSettings.radius.x *= t.getScaleX();
- parentSettings.radius.y *= t.getScaleY();
- }
- }
-
- // Get layer settings
- Rect layerCropRect = getCroppedBufferSize(getDrawingState());
- const vec2 radius(getDrawingState().cornerRadius, getDrawingState().cornerRadius);
- RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
- const bool layerSettingsValid = layerSettings.hasRoundedCorners() && layerCropRect.isValid();
-
- if (layerSettingsValid && parentSettings.hasRoundedCorners()) {
- // If the parent and the layer have rounded corner settings, use the parent settings if the
- // parent crop is entirely inside the layer crop.
- // This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
- if (parentSettings.cropRect.left > layerCropRect.left &&
- parentSettings.cropRect.top > layerCropRect.top &&
- parentSettings.cropRect.right < layerCropRect.right &&
- parentSettings.cropRect.bottom < layerCropRect.bottom) {
- return parentSettings;
- } else {
- return layerSettings;
- }
- } else if (layerSettingsValid) {
- return layerSettings;
- } else if (parentSettings.hasRoundedCorners()) {
- return parentSettings;
- }
- return {};
-}
-
-bool Layer::findInHierarchy(const sp<Layer>& l) {
- if (l == this) {
- return true;
- }
- for (auto& child : mDrawingChildren) {
- if (child->findInHierarchy(l)) {
- return true;
- }
- }
- return false;
-}
-
-void Layer::commitChildList() {
- for (size_t i = 0; i < mCurrentChildren.size(); i++) {
- const auto& child = mCurrentChildren[i];
- child->commitChildList();
- }
- mDrawingChildren = mCurrentChildren;
- mDrawingParent = mCurrentParent;
- if (CC_UNLIKELY(usingRelativeZ(LayerVector::StateSet::Drawing))) {
- auto zOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
- if (zOrderRelativeOf == nullptr) return;
- if (findInHierarchy(zOrderRelativeOf)) {
- ALOGE("Detected Z ordering loop between %s and %s", mName.c_str(),
- zOrderRelativeOf->mName.c_str());
- ALOGE("Severing rel Z loop, potentially dangerous");
- mDrawingState.isRelativeOf = false;
- zOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this));
- }
- }
-}
-
-
-void Layer::setInputInfo(const WindowInfo& info) {
- mDrawingState.inputInfo = info;
- mDrawingState.touchableRegionCrop =
- LayerHandle::getLayer(info.touchableRegionCropHandle.promote());
- mDrawingState.modified = true;
- mFlinger->mUpdateInputInfo = true;
- setTransactionFlags(eTransactionNeeded);
-}
-
-perfetto::protos::LayerProto* Layer::writeToProto(perfetto::protos::LayersProto& layersProto,
- uint32_t traceFlags) {
- perfetto::protos::LayerProto* layerProto = layersProto.add_layers();
- writeToProtoDrawingState(layerProto);
- writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
-
- if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
- ui::LayerStack layerStack =
- (mSnapshot) ? mSnapshot->outputFilter.layerStack : ui::INVALID_LAYER_STACK;
- writeCompositionStateToProto(layerProto, layerStack);
- }
-
- for (const sp<Layer>& layer : mDrawingChildren) {
- layer->writeToProto(layersProto, traceFlags);
- }
-
- return layerProto;
-}
-
void Layer::writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto,
ui::LayerStack layerStack) {
ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread.
@@ -1925,376 +660,6 @@
}
}
-void Layer::writeToProtoDrawingState(perfetto::protos::LayerProto* layerInfo) {
- const ui::Transform transform = getTransform();
- auto buffer = getExternalTexture();
- if (buffer != nullptr) {
- LayerProtoHelper::writeToProto(*buffer,
- [&]() { return layerInfo->mutable_active_buffer(); });
- LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()),
- layerInfo->mutable_buffer_transform());
- }
- layerInfo->set_invalidate(contentDirty);
- layerInfo->set_is_protected(isProtected());
- layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
- layerInfo->set_queued_frames(getQueuedFrameCount());
- layerInfo->set_curr_frame(mCurrentFrameNumber);
- layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
- layerInfo->set_corner_radius(
- (getRoundedCornerState().radius.x + getRoundedCornerState().radius.y) / 2.0);
- layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
- layerInfo->set_is_trusted_overlay(isTrustedOverlay());
- LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform());
- LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
- [&]() { return layerInfo->mutable_position(); });
- LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
- LayerProtoHelper::writeToProto(surfaceDamageRegion,
- [&]() { return layerInfo->mutable_damage_region(); });
-
- if (hasColorTransform()) {
- LayerProtoHelper::writeToProto(getColorTransform(), layerInfo->mutable_color_transform());
- }
-
- LayerProtoHelper::writeToProto(mSourceBounds,
- [&]() { return layerInfo->mutable_source_bounds(); });
- LayerProtoHelper::writeToProto(mScreenBounds,
- [&]() { return layerInfo->mutable_screen_bounds(); });
- LayerProtoHelper::writeToProto(getRoundedCornerState().cropRect,
- [&]() { return layerInfo->mutable_corner_radius_crop(); });
- layerInfo->set_shadow_radius(mEffectiveShadowRadius);
-}
-
-void Layer::writeToProtoCommonState(perfetto::protos::LayerProto* layerInfo,
- LayerVector::StateSet stateSet, uint32_t traceFlags) {
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
- const State& state = useDrawing ? mDrawingState : mDrawingState;
-
- ui::Transform requestedTransform = state.transform;
-
- layerInfo->set_id(sequence);
- layerInfo->set_name(getName().c_str());
- layerInfo->set_type(getType());
-
- for (const auto& child : children) {
- layerInfo->add_children(child->sequence);
- }
-
- for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
- sp<Layer> strongRelative = weakRelative.promote();
- if (strongRelative != nullptr) {
- layerInfo->add_relatives(strongRelative->sequence);
- }
- }
-
- LayerProtoHelper::writeToProto(state.transparentRegionHint,
- [&]() { return layerInfo->mutable_transparent_region(); });
-
- layerInfo->set_layer_stack(getLayerStack().id);
- layerInfo->set_z(state.z);
-
- LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
- return layerInfo->mutable_requested_position();
- });
-
- LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); });
-
- layerInfo->set_is_opaque(isOpaque(state));
-
- layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
- LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
- LayerProtoHelper::writeToProto(state.color,
- [&]() { return layerInfo->mutable_requested_color(); });
- layerInfo->set_flags(state.flags);
-
- LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
- layerInfo->mutable_requested_transform());
-
- auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
- if (parent != nullptr) {
- layerInfo->set_parent(parent->sequence);
- }
-
- auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
- if (zOrderRelativeOf != nullptr) {
- layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
- }
-
- layerInfo->set_is_relative_of(state.isRelativeOf);
-
- layerInfo->set_owner_uid(mOwnerUid);
-
- if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
- WindowInfo info;
- if (useDrawing) {
- info = fillInputInfo(
- InputDisplayArgs{.transform = &kIdentityTransform, .isSecure = true});
- } else {
- info = state.inputInfo;
- }
-
- LayerProtoHelper::writeToProto(info, state.touchableRegionCrop,
- [&]() { return layerInfo->mutable_input_window_info(); });
- }
-
- if (traceFlags & LayerTracing::TRACE_EXTRA) {
- auto protoMap = layerInfo->mutable_metadata();
- for (const auto& entry : state.metadata.mMap) {
- (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
- }
- }
-
- LayerProtoHelper::writeToProto(state.destinationFrame,
- [&]() { return layerInfo->mutable_destination_frame(); });
-}
-
-bool Layer::isRemovedFromCurrentState() const {
- return mRemovedFromDrawingState;
-}
-
-// Applies the given transform to the region, while protecting against overflows caused by any
-// offsets. If applying the offset in the transform to any of the Rects in the region would result
-// in an overflow, they are not added to the output Region.
-static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r,
- const std::string& debugWindowName) {
- // Round the translation using the same rounding strategy used by ui::Transform.
- const auto tx = static_cast<int32_t>(t.tx() + 0.5);
- const auto ty = static_cast<int32_t>(t.ty() + 0.5);
-
- ui::Transform transformWithoutOffset = t;
- transformWithoutOffset.set(0.f, 0.f);
-
- const Region transformed = transformWithoutOffset.transform(r);
-
- // Apply the translation to each of the Rects in the region while discarding any that overflow.
- Region ret;
- for (const auto& rect : transformed) {
- Rect newRect;
- if (__builtin_add_overflow(rect.left, tx, &newRect.left) ||
- __builtin_add_overflow(rect.top, ty, &newRect.top) ||
- __builtin_add_overflow(rect.right, tx, &newRect.right) ||
- __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) {
- ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.",
- debugWindowName.c_str());
- continue;
- }
- ret.orSelf(newRect);
- }
- return ret;
-}
-
-void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
- auto [inputBounds, inputBoundsValid] = getInputBounds(/*fillParentBounds=*/false);
- if (!inputBoundsValid) {
- info.touchableRegion.clear();
- }
-
- info.frame = getInputBoundsInDisplaySpace(inputBounds, screenToDisplay);
-
- ui::Transform inputToLayer;
- inputToLayer.set(inputBounds.left, inputBounds.top);
- const ui::Transform layerToScreen = getInputTransform();
- const ui::Transform inputToDisplay = screenToDisplay * layerToScreen * inputToLayer;
-
- // InputDispatcher expects a display-to-input transform.
- info.transform = inputToDisplay.inverse();
-
- // The touchable region is specified in the input coordinate space. Change it to display space.
- info.touchableRegion =
- transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName);
-}
-
-void Layer::fillTouchOcclusionMode(WindowInfo& info) {
- sp<Layer> p = sp<Layer>::fromExisting(this);
- while (p != nullptr && !p->hasInputInfo()) {
- p = p->mDrawingParent.promote();
- }
- if (p != nullptr) {
- info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode;
- }
-}
-
-gui::DropInputMode Layer::getDropInputMode() const {
- gui::DropInputMode mode = mDrawingState.dropInputMode;
- if (mode == gui::DropInputMode::ALL) {
- return mode;
- }
- sp<Layer> parent = mDrawingParent.promote();
- if (parent) {
- gui::DropInputMode parentMode = parent->getDropInputMode();
- if (parentMode != gui::DropInputMode::NONE) {
- return parentMode;
- }
- }
- return mode;
-}
-
-void Layer::handleDropInputMode(gui::WindowInfo& info) const {
- if (mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
- return;
- }
-
- // Check if we need to drop input unconditionally
- gui::DropInputMode dropInputMode = getDropInputMode();
- if (dropInputMode == gui::DropInputMode::ALL) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
- ALOGV("Dropping input for %s as requested by policy.", getDebugName());
- return;
- }
-
- // Check if we need to check if the window is obscured by parent
- if (dropInputMode != gui::DropInputMode::OBSCURED) {
- return;
- }
-
- // Check if the parent has set an alpha on the layer
- sp<Layer> parent = mDrawingParent.promote();
- if (parent && parent->getAlpha() != 1.0_hf) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
- ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(),
- static_cast<float>(getAlpha()));
- }
-
- // Check if the parent has cropped the buffer
- Rect bufferSize = getCroppedBufferSize(getDrawingState());
- if (!bufferSize.isValid()) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED;
- return;
- }
-
- // Screenbounds are the layer bounds cropped by parents, transformed to screenspace.
- // To check if the layer has been cropped, we take the buffer bounds, apply the local
- // layer crop and apply the same set of transforms to move to screenspace. If the bounds
- // match then the layer has not been cropped by its parents.
- Rect bufferInScreenSpace(getTransform().transform(bufferSize));
- bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds};
-
- if (croppedByParent) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
- ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent",
- getDebugName());
- } else {
- // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop
- // input if the window is obscured. This check should be done in surfaceflinger but the
- // logic currently resides in inputflinger. So pass the if_obscured check to input to only
- // drop input events if the window is obscured.
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED;
- }
-}
-
-WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) {
- if (!hasInputInfo()) {
- mDrawingState.inputInfo.name = getName();
- mDrawingState.inputInfo.ownerUid = gui::Uid{mOwnerUid};
- mDrawingState.inputInfo.ownerPid = gui::Pid{mOwnerPid};
- mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NO_INPUT_CHANNEL;
- mDrawingState.inputInfo.displayId = toLogicalDisplayId(getLayerStack());
- }
-
- const ui::Transform& displayTransform =
- displayArgs.transform != nullptr ? *displayArgs.transform : kIdentityTransform;
-
- WindowInfo info = mDrawingState.inputInfo;
- info.id = sequence;
- info.displayId = toLogicalDisplayId(getLayerStack());
-
- fillInputFrameInfo(info, displayTransform);
-
- if (displayArgs.transform == nullptr) {
- // Do not let the window receive touches if it is not associated with a valid display
- // transform. We still allow the window to receive keys and prevent ANRs.
- info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE;
- }
-
- info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !isVisibleForInput());
-
- info.alpha = getAlpha();
- fillTouchOcclusionMode(info);
- handleDropInputMode(info);
-
- // If the window will be blacked out on a display because the display does not have the secure
- // flag and the layer has the secure flag set, then drop input.
- if (!displayArgs.isSecure && isSecure()) {
- info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
- }
-
- sp<Layer> cropLayer = mDrawingState.touchableRegionCrop.promote();
- if (info.replaceTouchableRegionWithCrop) {
- Rect inputBoundsInDisplaySpace;
- if (!cropLayer) {
- FloatRect inputBounds = getInputBounds(/*fillParentBounds=*/true).first;
- inputBoundsInDisplaySpace = getInputBoundsInDisplaySpace(inputBounds, displayTransform);
- } else {
- FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first;
- inputBoundsInDisplaySpace =
- cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform);
- }
- info.touchableRegion = Region(inputBoundsInDisplaySpace);
- } else if (cropLayer != nullptr) {
- FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first;
- Rect inputBoundsInDisplaySpace =
- cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform);
- info.touchableRegion = info.touchableRegion.intersect(inputBoundsInDisplaySpace);
- }
-
- // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
- // if it was set by WM for a known system overlay
- if (isTrustedOverlay()) {
- info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY;
- }
-
- // If the layer is a clone, we need to crop the input region to cloned root to prevent
- // touches from going outside the cloned area.
- if (isClone()) {
- info.inputConfig |= WindowInfo::InputConfig::CLONE;
- if (const sp<Layer> clonedRoot = getClonedRoot()) {
- const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds});
- info.touchableRegion = info.touchableRegion.intersect(rect);
- }
- }
-
- Rect bufferSize = getBufferSize(getDrawingState());
- info.contentSize = Size(bufferSize.width(), bufferSize.height());
-
- return info;
-}
-
-Rect Layer::getInputBoundsInDisplaySpace(const FloatRect& inputBounds,
- const ui::Transform& screenToDisplay) {
- // InputDispatcher works in the display device's coordinate space. Here, we calculate the
- // frame and transform used for the layer, which determines the bounds and the coordinate space
- // within which the layer will receive input.
-
- // Coordinate space definitions:
- // - display: The display device's coordinate space. Correlates to pixels on the display.
- // - screen: The post-rotation coordinate space for the display, a.k.a. logical display space.
- // - layer: The coordinate space of this layer.
- // - input: The coordinate space in which this layer will receive input events. This could be
- // different than layer space if a surfaceInset is used, which changes the origin
- // of the input space.
-
- // Crop the input bounds to ensure it is within the parent's bounds.
- const FloatRect croppedInputBounds = mBounds.intersect(inputBounds);
- const ui::Transform layerToScreen = getInputTransform();
- const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
- return Rect{layerToDisplay.transform(croppedInputBounds)};
-}
-
-sp<Layer> Layer::getClonedRoot() {
- if (mClonedChild != nullptr) {
- return sp<Layer>::fromExisting(this);
- }
- if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) {
- return nullptr;
- }
- return mDrawingParent.promote()->getClonedRoot();
-}
-
-bool Layer::hasInputInfo() const {
- return mDrawingState.inputInfo.token != nullptr ||
- mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);
-}
-
compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
const DisplayDevice* display) const {
if (!display) return nullptr;
@@ -2329,215 +694,27 @@
return outputLayer ? outputLayer->getState().visibleRegion : Region();
}
-void Layer::updateCloneBufferInfo() {
- if (!isClone() || !isClonedFromAlive()) {
- return;
- }
-
- sp<Layer> clonedFrom = getClonedFrom();
- mBufferInfo = clonedFrom->mBufferInfo;
- mSidebandStream = clonedFrom->mSidebandStream;
- surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
- mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load();
- mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber;
-
- // After buffer info is updated, the drawingState from the real layer needs to be copied into
- // the cloned. This is because some properties of drawingState can change when latchBuffer is
- // called. However, copying the drawingState would also overwrite the cloned layer's relatives
- // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in
- // the cloned drawingState again.
- wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
- SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
- wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
- WindowInfo tmpInputInfo = mDrawingState.inputInfo;
-
- cloneDrawingState(clonedFrom.get());
-
- mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
- mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
- mDrawingState.zOrderRelatives = tmpZOrderRelatives;
- mDrawingState.inputInfo = tmpInputInfo;
-}
-
-bool Layer::updateMirrorInfo(const std::deque<Layer*>& cloneRootsPendingUpdates) {
- if (mClonedChild == nullptr || !mClonedChild->isClonedFromAlive()) {
- // If mClonedChild is null, there is nothing to mirror. If isClonedFromAlive returns false,
- // it means that there is a clone, but the layer it was cloned from has been destroyed. In
- // that case, we want to delete the reference to the clone since we want it to get
- // destroyed. The root, this layer, will still be around since the client can continue
- // to hold a reference, but no cloned layers will be displayed.
- mClonedChild = nullptr;
- return true;
- }
-
- std::map<sp<Layer>, sp<Layer>> clonedLayersMap;
- // If the real layer exists and is in current state, add the clone as a child of the root.
- // There's no need to remove from drawingState when the layer is offscreen since currentState is
- // copied to drawingState for the root layer. So the clonedChild is always removed from
- // drawingState and then needs to be added back each traversal.
- if (!mClonedChild->getClonedFrom()->isRemovedFromCurrentState()) {
- addChildToDrawing(mClonedChild);
- }
-
- mClonedChild->updateClonedDrawingState(clonedLayersMap);
- mClonedChild->updateClonedChildren(sp<Layer>::fromExisting(this), clonedLayersMap);
- mClonedChild->updateClonedRelatives(clonedLayersMap);
-
- for (Layer* root : cloneRootsPendingUpdates) {
- if (clonedLayersMap.find(sp<Layer>::fromExisting(root)) != clonedLayersMap.end()) {
- return false;
- }
- }
- return true;
-}
-
-void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
- // If the layer the clone was cloned from is alive, copy the content of the drawingState
- // to the clone. If the real layer is no longer alive, continue traversing the children
- // since we may be able to pull out other children that are still alive.
- if (isClonedFromAlive()) {
- sp<Layer> clonedFrom = getClonedFrom();
- cloneDrawingState(clonedFrom.get());
- clonedLayersMap.emplace(clonedFrom, sp<Layer>::fromExisting(this));
- }
-
- // The clone layer may have children in drawingState since they may have been created and
- // added from a previous request to updateMirorInfo. This is to ensure we don't recreate clones
- // that already exist, since we can just re-use them.
- // The drawingChildren will not get overwritten by the currentChildren since the clones are
- // not updated in the regular traversal. They are skipped since the root will lose the
- // reference to them when it copies its currentChildren to drawing.
- for (sp<Layer>& child : mDrawingChildren) {
- child->updateClonedDrawingState(clonedLayersMap);
- }
-}
-
-void Layer::updateClonedChildren(const sp<Layer>& mirrorRoot,
- std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
- mDrawingChildren.clear();
-
- if (!isClonedFromAlive()) {
- return;
- }
-
- sp<Layer> clonedFrom = getClonedFrom();
- for (sp<Layer>& child : clonedFrom->mDrawingChildren) {
- if (child == mirrorRoot) {
- // This is to avoid cyclical mirroring.
- continue;
- }
- sp<Layer> clonedChild = clonedLayersMap[child];
- if (clonedChild == nullptr) {
- clonedChild = child->createClone();
- clonedLayersMap[child] = clonedChild;
- }
- addChildToDrawing(clonedChild);
- clonedChild->updateClonedChildren(mirrorRoot, clonedLayersMap);
- }
-}
-
-void Layer::updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
- auto cropLayer = mDrawingState.touchableRegionCrop.promote();
- if (cropLayer != nullptr) {
- if (clonedLayersMap.count(cropLayer) == 0) {
- // Real layer had a crop layer but it's not in the cloned hierarchy. Just set to
- // self as crop layer to avoid going outside bounds.
- mDrawingState.touchableRegionCrop = wp<Layer>::fromExisting(this);
- } else {
- const sp<Layer>& clonedCropLayer = clonedLayersMap.at(cropLayer);
- mDrawingState.touchableRegionCrop = clonedCropLayer;
- }
- }
- // Cloned layers shouldn't handle watch outside since their z order is not determined by
- // WM or the client.
- mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, false);
-}
-
-void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
- mDrawingState.zOrderRelativeOf = wp<Layer>();
- mDrawingState.zOrderRelatives.clear();
-
- if (!isClonedFromAlive()) {
- return;
- }
-
- const sp<Layer>& clonedFrom = getClonedFrom();
- for (wp<Layer>& relativeWeak : clonedFrom->mDrawingState.zOrderRelatives) {
- const sp<Layer>& relative = relativeWeak.promote();
- if (clonedLayersMap.count(relative) > 0) {
- auto& clonedRelative = clonedLayersMap.at(relative);
- mDrawingState.zOrderRelatives.add(clonedRelative);
- }
- }
-
- // Check if the relativeLayer for the real layer is part of the cloned hierarchy.
- // It's possible that the layer it's relative to is outside the requested cloned hierarchy.
- // In that case, we treat the layer as if the relativeOf has been removed. This way, it will
- // still traverse the children, but the layer with the missing relativeOf will not be shown
- // on screen.
- const sp<Layer>& relativeOf = clonedFrom->mDrawingState.zOrderRelativeOf.promote();
- if (clonedLayersMap.count(relativeOf) > 0) {
- const sp<Layer>& clonedRelativeOf = clonedLayersMap.at(relativeOf);
- mDrawingState.zOrderRelativeOf = clonedRelativeOf;
- }
-
- updateClonedInputInfo(clonedLayersMap);
-
- for (sp<Layer>& child : mDrawingChildren) {
- child->updateClonedRelatives(clonedLayersMap);
- }
-}
-
-void Layer::addChildToDrawing(const sp<Layer>& layer) {
- mDrawingChildren.add(layer);
- layer->mDrawingParent = sp<Layer>::fromExisting(this);
-}
-
-bool Layer::isInternalDisplayOverlay() const {
- const State& s(mDrawingState);
- if (s.flags & layer_state_t::eLayerSkipScreenshot) {
- return true;
- }
-
- sp<Layer> parent = mDrawingParent.promote();
- return parent && parent->isInternalDisplayOverlay();
-}
-
-void Layer::setClonedChild(const sp<Layer>& clonedChild) {
- mClonedChild = clonedChild;
- mHadClonedChild = true;
- mFlinger->mLayerMirrorRoots.push_back(this);
-}
-
-bool Layer::setDropInputMode(gui::DropInputMode mode) {
- if (mDrawingState.dropInputMode == mode) {
- return false;
- }
- mDrawingState.dropInputMode = mode;
- return true;
-}
-
-void Layer::cloneDrawingState(const Layer* from) {
- mDrawingState = from->mDrawingState;
- // Skip callback info since they are not applicable for cloned layers.
- mDrawingState.releaseBufferListener = nullptr;
- // TODO (b/238781169) currently broken for mirror layers because we do not
- // track release fences for mirror layers composed on other displays
- mDrawingState.callbackHandles = {};
-}
-
void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, uint64_t framenumber,
const sp<Fence>& releaseFence) {
- if (!listener) {
+ if (!listener && !mBufferReleaseChannel) {
return;
}
+
SFTRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);
+
+ ReleaseCallbackId callbackId{buffer->getId(), framenumber};
+ const sp<Fence>& fence = releaseFence ? releaseFence : Fence::NO_FENCE;
uint32_t currentMaxAcquiredBufferCount =
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
- listener->onReleaseBuffer({buffer->getId(), framenumber},
- releaseFence ? releaseFence : Fence::NO_FENCE,
- currentMaxAcquiredBufferCount);
+
+ if (listener) {
+ listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount);
+ }
+
+ if (mBufferReleaseChannel) {
+ mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount);
+ }
}
sp<CallbackHandle> Layer::findCallbackHandle() {
@@ -2655,6 +832,7 @@
void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->bufferReleaseChannel = mBufferReleaseChannel;
handle->transformHint = mTransformHint;
handle->dequeueReadyTime = dequeueReadyTime;
handle->currentMaxAcquiredBufferCount =
@@ -2674,17 +852,9 @@
mDrawingState.callbackHandles = {};
}
-bool Layer::willPresentCurrentTransaction() const {
- // Returns true if the most recent Transaction applied to CurrentState will be presented.
- return (getSidebandStreamChanged() || getAutoRefresh() ||
- (mDrawingState.modified &&
- (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr)));
-}
-
bool Layer::setTransform(uint32_t transform) {
if (mDrawingState.bufferTransform == transform) return false;
mDrawingState.bufferTransform = transform;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2693,7 +863,6 @@
if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false;
mDrawingState.sequence++;
mDrawingState.transformToDisplayInverse = transformToDisplayInverse;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2704,100 +873,10 @@
mDrawingState.sequence++;
mDrawingState.bufferCrop = bufferCrop;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
-bool Layer::setDestinationFrame(const Rect& destinationFrame) {
- if (mDrawingState.destinationFrame == destinationFrame) return false;
-
- mDrawingState.sequence++;
- mDrawingState.destinationFrame = destinationFrame;
-
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-// Translate destination frame into scale and position. If a destination frame is not set, use the
-// provided scale and position
-bool Layer::updateGeometry() {
- if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) ||
- mDrawingState.destinationFrame.isEmpty()) {
- // If destination frame is not set, use the requested transform set via
- // Layer::setPosition and Layer::setMatrix.
- return assignTransform(&mDrawingState.transform, mRequestedTransform);
- }
-
- Rect destRect = mDrawingState.destinationFrame;
- int32_t destW = destRect.width();
- int32_t destH = destRect.height();
- if (destRect.left < 0) {
- destRect.left = 0;
- destRect.right = destW;
- }
- if (destRect.top < 0) {
- destRect.top = 0;
- destRect.bottom = destH;
- }
-
- if (!mDrawingState.buffer) {
- ui::Transform t;
- t.set(destRect.left, destRect.top);
- return assignTransform(&mDrawingState.transform, t);
- }
-
- uint32_t bufferWidth = mDrawingState.buffer->getWidth();
- uint32_t bufferHeight = mDrawingState.buffer->getHeight();
- // Undo any transformations on the buffer.
- if (mDrawingState.bufferTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- uint32_t invTransform = SurfaceFlinger::getActiveDisplayRotationFlags();
- if (mDrawingState.transformToDisplayInverse) {
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- }
-
- float sx = destW / static_cast<float>(bufferWidth);
- float sy = destH / static_cast<float>(bufferHeight);
- ui::Transform t;
- t.set(sx, 0, 0, sy);
- t.set(destRect.left, destRect.top);
- return assignTransform(&mDrawingState.transform, t);
-}
-
-bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
- if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy &&
- mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) {
- return false;
- }
-
- mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
-bool Layer::setPosition(float x, float y) {
- if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) {
- return false;
- }
-
- mRequestedTransform.set(x, y);
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
void Layer::releasePreviousBuffer() {
mReleasePreviousBuffer = true;
if (!mBufferInfo.mBuffer ||
@@ -2861,7 +940,6 @@
mDrawingState.isAutoTimestamp = isAutoTimestamp;
mDrawingState.latchedVsyncId = info.vsyncId;
mDrawingState.useVsyncIdForRefreshRateSelection = info.useForRefreshRateSelection;
- mDrawingState.modified = true;
if (!buffer) {
resetDrawingStateBufferInfo();
setTransactionFlags(eTransactionNeeded);
@@ -3009,7 +1087,6 @@
bool Layer::setDataspace(ui::Dataspace dataspace) {
if (mDrawingState.dataspace == dataspace) return false;
mDrawingState.dataspace = dataspace;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -3020,7 +1097,6 @@
return false;
mDrawingState.currentHdrSdrRatio = currentBufferRatio;
mDrawingState.desiredHdrSdrRatio = desiredRatio;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -3028,40 +1104,6 @@
bool Layer::setDesiredHdrHeadroom(float desiredRatio) {
if (mDrawingState.desiredHdrSdrRatio == desiredRatio) return false;
mDrawingState.desiredHdrSdrRatio = desiredRatio;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setCachingHint(gui::CachingHint cachingHint) {
- if (mDrawingState.cachingHint == cachingHint) return false;
- mDrawingState.cachingHint = cachingHint;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
- if (mDrawingState.hdrMetadata == hdrMetadata) return false;
- mDrawingState.hdrMetadata = hdrMetadata;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setSurfaceDamageRegion(const Region& surfaceDamage) {
- if (mDrawingState.surfaceDamageRegion.hasSameRects(surfaceDamage)) return false;
- mDrawingState.surfaceDamageRegion = surfaceDamage;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- setIsSmallDirty(surfaceDamage, getTransform());
- return true;
-}
-
-bool Layer::setApi(int32_t api) {
- if (mDrawingState.api == api) return false;
- mDrawingState.api = api;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -3077,7 +1119,6 @@
}
mDrawingState.sidebandStream = sidebandStream;
- mDrawingState.modified = true;
if (sidebandStream != nullptr && mDrawingState.buffer != nullptr) {
releasePreviousBuffer();
resetDrawingStateBufferInfo();
@@ -3174,14 +1215,6 @@
return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight));
}
-FloatRect Layer::computeSourceBounds(const FloatRect& parentBounds) const {
- if (mBufferInfo.mBuffer == nullptr) {
- return parentBounds;
- }
-
- return getBufferSize(getDrawingState()).toFloatRect();
-}
-
bool Layer::fenceHasSignaled() const {
if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
return true;
@@ -3203,37 +1236,21 @@
}
}
-void Layer::setAutoRefresh(bool autoRefresh) {
- mDrawingState.autoRefresh = autoRefresh;
-}
-
bool Layer::latchSidebandStream(bool& recomputeVisibleRegions) {
- // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
- auto* snapshot = editLayerSnapshot();
- snapshot->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
-
if (mSidebandStreamChanged.exchange(false)) {
const State& s(getDrawingState());
// mSidebandStreamChanged was true
mSidebandStream = s.sidebandStream;
- snapshot->sidebandStream = mSidebandStream;
if (mSidebandStream != nullptr) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
recomputeVisibleRegions = true;
-
return true;
}
return false;
}
-bool Layer::hasFrameUpdate() const {
- const State& c(getDrawingState());
- return (mDrawingStateModified || mDrawingState.modified) &&
- (c.buffer != nullptr || c.bgColorLayer != nullptr);
-}
-
void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) {
const State& s(getDrawingState());
@@ -3280,8 +1297,6 @@
mFlinger->getTransactionCallbackInvoker()
.addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
mDrawingState.callbackHandles = remainingHandles;
-
- mDrawingStateModified = false;
}
void Layer::gatherBufferInfo() {
@@ -3305,7 +1320,6 @@
mBufferInfo.mFrameLatencyNeeded = true;
mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime;
mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
- mBufferInfo.mFence = mDrawingState.acquireFence;
mBufferInfo.mTransform = mDrawingState.bufferTransform;
auto lastDataspace = mBufferInfo.mDataspace;
mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace);
@@ -3353,10 +1367,6 @@
mFlinger->mHdrLayerInfoChanged = true;
}
mBufferInfo.mCrop = computeBufferCrop(mDrawingState);
- mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
- mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion;
- mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata;
- mBufferInfo.mApi = mDrawingState.api;
mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse;
}
@@ -3372,13 +1382,6 @@
}
}
-sp<Layer> Layer::createClone() {
- surfaceflinger::LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0,
- LayerMetadata());
- sp<Layer> layer = mFlinger->getFactory().createBufferStateLayer(args);
- return layer;
-}
-
void Layer::decrementPendingBufferCount() {
int32_t pendingBuffers = --mPendingBufferTransactions;
tracePendingBufferCount(pendingBuffers);
@@ -3388,294 +1391,6 @@
SFTRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
}
-/*
- * We don't want to send the layer's transform to input, but rather the
- * parent's transform. This is because Layer's transform is
- * information about how the buffer is placed on screen. The parent's
- * transform makes more sense to send since it's information about how the
- * layer is placed on screen. This transform is used by input to determine
- * how to go from screen space back to window space.
- */
-ui::Transform Layer::getInputTransform() const {
- if (!hasBufferOrSidebandStream()) {
- return getTransform();
- }
- sp<Layer> parent = mDrawingParent.promote();
- if (parent == nullptr) {
- return ui::Transform();
- }
-
- return parent->getTransform();
-}
-
-/**
- * Returns the bounds used to fill the input frame and the touchable region.
- *
- * Similar to getInputTransform, we need to update the bounds to include the transform.
- * This is because bounds don't include the buffer transform, where the input assumes
- * that's already included.
- */
-std::pair<FloatRect, bool> Layer::getInputBounds(bool fillParentBounds) const {
- Rect croppedBufferSize = getCroppedBufferSize(getDrawingState());
- FloatRect inputBounds = croppedBufferSize.toFloatRect();
- if (hasBufferOrSidebandStream() && croppedBufferSize.isValid() &&
- mDrawingState.transform.getType() != ui::Transform::IDENTITY) {
- inputBounds = mDrawingState.transform.transform(inputBounds);
- }
-
- bool inputBoundsValid = croppedBufferSize.isValid();
- if (!inputBoundsValid) {
- /**
- * Input bounds are based on the layer crop or buffer size. But if we are using
- * the layer bounds as the input bounds (replaceTouchableRegionWithCrop flag) then
- * we can use the parent bounds as the input bounds if the layer does not have buffer
- * or a crop. We want to unify this logic but because of compat reasons we cannot always
- * use the parent bounds. A layer without a buffer can get input. So when a window is
- * initially added, its touchable region can fill its parent layer bounds and that can
- * have negative consequences.
- */
- inputBounds = fillParentBounds ? mBounds : FloatRect{};
- }
-
- // Clamp surface inset to the input bounds.
- const float inset = static_cast<float>(mDrawingState.inputInfo.surfaceInset);
- const float xSurfaceInset = std::clamp(inset, 0.f, inputBounds.getWidth() / 2.f);
- const float ySurfaceInset = std::clamp(inset, 0.f, inputBounds.getHeight() / 2.f);
-
- // Apply the insets to the input bounds.
- inputBounds.left += xSurfaceInset;
- inputBounds.top += ySurfaceInset;
- inputBounds.right -= xSurfaceInset;
- inputBounds.bottom -= ySurfaceInset;
-
- return {inputBounds, inputBoundsValid};
-}
-
-bool Layer::isSimpleBufferUpdate(const layer_state_t& s) const {
- const uint64_t requiredFlags = layer_state_t::eBufferChanged;
-
- const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
- layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
- layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
- layer_state_t::eLayerStackChanged | layer_state_t::eReparent |
- (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed()
- ? 0
- : layer_state_t::eAutoRefreshChanged);
-
- if ((s.what & requiredFlags) != requiredFlags) {
- SFTRACE_FORMAT_INSTANT("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
- (s.what | requiredFlags) & ~s.what);
- return false;
- }
-
- if (s.what & deniedFlags) {
- SFTRACE_FORMAT_INSTANT("%s: false [has denied flags 0x%" PRIx64 "]", __func__,
- s.what & deniedFlags);
- return false;
- }
-
- if (s.what & layer_state_t::ePositionChanged) {
- if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) {
- SFTRACE_FORMAT_INSTANT("%s: false [ePositionChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eAlphaChanged) {
- if (mDrawingState.color.a != s.color.a) {
- SFTRACE_FORMAT_INSTANT("%s: false [eAlphaChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eColorTransformChanged) {
- if (mDrawingState.colorTransform != s.colorTransform) {
- SFTRACE_FORMAT_INSTANT("%s: false [eColorTransformChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBackgroundColorChanged) {
- if (mDrawingState.bgColorLayer || s.bgColor.a != 0) {
- SFTRACE_FORMAT_INSTANT("%s: false [eBackgroundColorChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eMatrixChanged) {
- if (mRequestedTransform.dsdx() != s.matrix.dsdx ||
- mRequestedTransform.dtdy() != s.matrix.dtdy ||
- mRequestedTransform.dtdx() != s.matrix.dtdx ||
- mRequestedTransform.dsdy() != s.matrix.dsdy) {
- SFTRACE_FORMAT_INSTANT("%s: false [eMatrixChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eCornerRadiusChanged) {
- if (mDrawingState.cornerRadius != s.cornerRadius) {
- SFTRACE_FORMAT_INSTANT("%s: false [eCornerRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) {
- if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) {
- SFTRACE_FORMAT_INSTANT("%s: false [eBackgroundBlurRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBufferTransformChanged) {
- if (mDrawingState.bufferTransform != s.bufferTransform) {
- SFTRACE_FORMAT_INSTANT("%s: false [eBufferTransformChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eTransformToDisplayInverseChanged) {
- if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) {
- SFTRACE_FORMAT_INSTANT("%s: false [eTransformToDisplayInverseChanged changed]",
- __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eCropChanged) {
- if (mDrawingState.crop != s.crop) {
- SFTRACE_FORMAT_INSTANT("%s: false [eCropChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDataspaceChanged) {
- if (mDrawingState.dataspace != s.dataspace) {
- SFTRACE_FORMAT_INSTANT("%s: false [eDataspaceChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eHdrMetadataChanged) {
- if (mDrawingState.hdrMetadata != s.hdrMetadata) {
- SFTRACE_FORMAT_INSTANT("%s: false [eHdrMetadataChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eSidebandStreamChanged) {
- if (mDrawingState.sidebandStream != s.sidebandStream) {
- SFTRACE_FORMAT_INSTANT("%s: false [eSidebandStreamChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eColorSpaceAgnosticChanged) {
- if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) {
- SFTRACE_FORMAT_INSTANT("%s: false [eColorSpaceAgnosticChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eShadowRadiusChanged) {
- if (mDrawingState.shadowRadius != s.shadowRadius) {
- SFTRACE_FORMAT_INSTANT("%s: false [eShadowRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eFixedTransformHintChanged) {
- if (mDrawingState.fixedTransformHint != s.fixedTransformHint) {
- SFTRACE_FORMAT_INSTANT("%s: false [eFixedTransformHintChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eTrustedOverlayChanged) {
- if (mDrawingState.isTrustedOverlay != (s.trustedOverlay == gui::TrustedOverlay::ENABLED)) {
- SFTRACE_FORMAT_INSTANT("%s: false [eTrustedOverlayChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eStretchChanged) {
- StretchEffect temp = s.stretchEffect;
- temp.sanitize();
- if (mDrawingState.stretchEffect != temp) {
- SFTRACE_FORMAT_INSTANT("%s: false [eStretchChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBufferCropChanged) {
- if (mDrawingState.bufferCrop != s.bufferCrop) {
- SFTRACE_FORMAT_INSTANT("%s: false [eBufferCropChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDestinationFrameChanged) {
- if (mDrawingState.destinationFrame != s.destinationFrame) {
- SFTRACE_FORMAT_INSTANT("%s: false [eDestinationFrameChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDimmingEnabledChanged) {
- if (mDrawingState.dimmingEnabled != s.dimmingEnabled) {
- SFTRACE_FORMAT_INSTANT("%s: false [eDimmingEnabledChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eExtendedRangeBrightnessChanged) {
- if (mDrawingState.currentHdrSdrRatio != s.currentHdrSdrRatio ||
- mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) {
- SFTRACE_FORMAT_INSTANT("%s: false [eExtendedRangeBrightnessChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDesiredHdrHeadroomChanged) {
- if (mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) {
- SFTRACE_FORMAT_INSTANT("%s: false [eDesiredHdrHeadroomChanged changed]", __func__);
- return false;
- }
- }
-
- return true;
-}
-
-sp<LayerFE> Layer::getCompositionEngineLayerFE() const {
- // There's no need to get a CE Layer if the layer isn't going to draw anything.
- return hasSomethingToDraw() ? mLegacyLayerFE : nullptr;
-}
-
-const LayerSnapshot* Layer::getLayerSnapshot() const {
- return mSnapshot.get();
-}
-
-LayerSnapshot* Layer::editLayerSnapshot() {
- return mSnapshot.get();
-}
-
-std::unique_ptr<frontend::LayerSnapshot> Layer::stealLayerSnapshot() {
- return std::move(mSnapshot);
-}
-
-void Layer::updateLayerSnapshot(std::unique_ptr<frontend::LayerSnapshot> snapshot) {
- mSnapshot = std::move(snapshot);
-}
-
-const compositionengine::LayerFECompositionState* Layer::getCompositionState() const {
- return mSnapshot.get();
-}
-
-sp<LayerFE> Layer::copyCompositionEngineLayerFE() const {
- auto result = mFlinger->getFactory().createLayerFE(mName, this);
- result->mSnapshot = std::make_unique<LayerSnapshot>(*mSnapshot);
- return result;
-}
-
sp<LayerFE> Layer::getCompositionEngineLayerFE(
const frontend::LayerHierarchy::TraversalPath& path) {
for (auto& [p, layerFE] : mLayerFEs) {
@@ -3688,55 +1403,6 @@
return layerFE;
}
-void Layer::useSurfaceDamage() {
- if (mFlinger->mForceFullDamage) {
- surfaceDamageRegion = Region::INVALID_REGION;
- } else {
- surfaceDamageRegion = mBufferInfo.mSurfaceDamage;
- }
-}
-
-void Layer::useEmptyDamage() {
- surfaceDamageRegion.clear();
-}
-
-bool Layer::isOpaque(const Layer::State& s) const {
- // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
- // layer's opaque flag.
- if (!hasSomethingToDraw()) {
- return false;
- }
-
- // if the layer has the opaque flag, then we're always opaque
- if ((s.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque) {
- return true;
- }
-
- // If the buffer has no alpha channel, then we are opaque
- if (hasBufferOrSidebandStream() && LayerSnapshot::isOpaqueFormat(getPixelFormat())) {
- return true;
- }
-
- // Lastly consider the layer opaque if drawing a color with alpha == 1.0
- return fillsColor() && getAlpha() == 1.0_hf;
-}
-
-bool Layer::canReceiveInput() const {
- return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f);
-}
-
-bool Layer::isVisible() const {
- if (!hasSomethingToDraw()) {
- return false;
- }
-
- if (isHiddenByPolicy()) {
- return false;
- }
-
- return getAlpha() > 0.0f || hasBlur();
-}
-
void Layer::onCompositionPresented(const DisplayDevice* display,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
@@ -3829,11 +1495,6 @@
return !mDrawingState.buffer && mBufferInfo.mBuffer;
}
-bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
- const bool bgColorOnly = mDrawingState.bgColorLayer != nullptr;
- return latchBufferImpl(recomputeVisibleRegions, latchTime, bgColorOnly);
-}
-
bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly) {
SFTRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
getDrawingState().frameNumber);
@@ -3855,7 +1516,6 @@
// Capture the old state of the layer for comparisons later
BufferInfo oldBufferInfo = mBufferInfo;
- const bool oldOpacity = isOpaque(mDrawingState);
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mDrawingState.frameNumber;
gatherBufferInfo();
@@ -3880,7 +1540,6 @@
if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
(mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
- (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
(mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
recomputeVisibleRegions = true;
}
@@ -3893,35 +1552,14 @@
recomputeVisibleRegions = true;
}
}
-
- if (oldOpacity != isOpaque(mDrawingState)) {
- recomputeVisibleRegions = true;
- }
-
return true;
}
-bool Layer::hasReadyFrame() const {
- return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
-}
-
bool Layer::isProtected() const {
return (mBufferInfo.mBuffer != nullptr) &&
(mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
-void Layer::latchAndReleaseBuffer() {
- if (hasReadyFrame()) {
- bool ignored = false;
- latchBuffer(ignored, systemTime());
- }
- releasePendingBuffer(systemTime());
-}
-
-PixelFormat Layer::getPixelFormat() const {
- return mBufferInfo.mPixelFormat;
-}
-
bool Layer::getTransformToDisplayInverse() const {
return mBufferInfo.mTransformToDisplayInverse;
}
@@ -3945,18 +1583,6 @@
return mBufferInfo.mTransform;
}
-ui::Dataspace Layer::getDataSpace() const {
- return hasBufferOrSidebandStream() ? mBufferInfo.mDataspace : mDrawingState.dataspace;
-}
-
-bool Layer::isFrontBuffered() const {
- if (mBufferInfo.mBuffer == nullptr) {
- return false;
- }
-
- return mBufferInfo.mBuffer->getUsage() & AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
-}
-
ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) {
ui::Dataspace updatedDataspace = dataspace;
// translate legacy dataspaces to modern dataspaces
@@ -3992,84 +1618,6 @@
return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
}
-const std::shared_ptr<renderengine::ExternalTexture>& Layer::getExternalTexture() const {
- return mBufferInfo.mBuffer;
-}
-
-bool Layer::setColor(const half3& color) {
- if (mDrawingState.color.rgb == color) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.color.rgb = color;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::fillsColor() const {
- return !hasBufferOrSidebandStream() && mDrawingState.color.r >= 0.0_hf &&
- mDrawingState.color.g >= 0.0_hf && mDrawingState.color.b >= 0.0_hf;
-}
-
-bool Layer::hasBlur() const {
- return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0;
-}
-
-void Layer::updateSnapshot(bool updateGeometry) {
- if (!getCompositionEngineLayerFE()) {
- return;
- }
-
- auto* snapshot = editLayerSnapshot();
- if (updateGeometry) {
- prepareBasicGeometryCompositionState();
- prepareGeometryCompositionState();
- snapshot->roundedCorner = getRoundedCornerState();
- snapshot->transformedBounds = mScreenBounds;
- if (mEffectiveShadowRadius > 0.f) {
- snapshot->shadowSettings = mFlinger->mDrawingState.globalShadowSettings;
-
- // Note: this preserves existing behavior of shadowing the entire layer and not cropping
- // it if transparent regions are present. This may not be necessary since shadows are
- // typically cast by layers without transparent regions.
- snapshot->shadowSettings.boundaries = mBounds;
-
- const float casterAlpha = snapshot->alpha;
- const bool casterIsOpaque =
- ((mBufferInfo.mBuffer != nullptr) && isOpaque(mDrawingState));
-
- // If the casting layer is translucent, we need to fill in the shadow underneath the
- // layer. Otherwise the generated shadow will only be shown around the casting layer.
- snapshot->shadowSettings.casterIsTranslucent = !casterIsOpaque || (casterAlpha < 1.0f);
- snapshot->shadowSettings.ambientColor *= casterAlpha;
- snapshot->shadowSettings.spotColor *= casterAlpha;
- }
- snapshot->shadowSettings.length = mEffectiveShadowRadius;
- }
- snapshot->contentOpaque = isOpaque(mDrawingState);
- snapshot->layerOpaqueFlagSet =
- (mDrawingState.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
- sp<Layer> p = mDrawingParent.promote();
- if (p != nullptr) {
- snapshot->parentTransform = p->getTransform();
- } else {
- snapshot->parentTransform.reset();
- }
- snapshot->bufferSize = getBufferSize(mDrawingState);
- snapshot->externalTexture = mBufferInfo.mBuffer;
- snapshot->hasReadyFrame = hasReadyFrame();
- preparePerFrameCompositionState();
-}
-
-void Layer::updateChildrenSnapshots(bool updateGeometry) {
- for (const sp<Layer>& child : mDrawingChildren) {
- child->updateSnapshot(updateGeometry);
- child->updateChildrenSnapshots(updateGeometry);
- }
-}
-
bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds,
TrustedPresentationListener const& listener) {
bool hadTrustedPresentationListener = hasTrustedPresentationListener();
@@ -4093,39 +1641,41 @@
return haveTrustedPresentationListener;
}
+void Layer::setBufferReleaseChannel(
+ const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel) {
+ mBufferReleaseChannel = channel;
+}
+
void Layer::updateLastLatchTime(nsecs_t latchTime) {
mLastLatchTime = latchTime;
}
-void Layer::setIsSmallDirty(const Region& damageRegion,
- const ui::Transform& layerToDisplayTransform) {
- mSmallDirty = false;
+void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) {
if (!mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) {
+ snapshot->isSmallDirty = false;
return;
}
if (mWindowType != WindowInfo::Type::APPLICATION &&
mWindowType != WindowInfo::Type::BASE_APPLICATION) {
+ snapshot->isSmallDirty = false;
return;
}
- Rect bounds = damageRegion.getBounds();
+ Rect bounds = snapshot->surfaceDamage.getBounds();
if (!bounds.isValid()) {
+ snapshot->isSmallDirty = false;
return;
}
// Transform to screen space.
- bounds = layerToDisplayTransform.transform(bounds);
+ bounds = snapshot->localTransform.transform(bounds);
// If the damage region is a small dirty, this could give the hint for the layer history that
// it could suppress the heuristic rate when calculating.
- mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId,
- bounds.getWidth() * bounds.getHeight());
-}
-
-void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) {
- setIsSmallDirty(snapshot->surfaceDamage, snapshot->localTransform);
- snapshot->isSmallDirty = mSmallDirty;
+ snapshot->isSmallDirty =
+ mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId,
+ bounds.getWidth() * bounds.getHeight());
}
} // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f6eed63..9caa20c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -43,9 +43,7 @@
#include <scheduler/Fps.h>
#include <scheduler/Seamlessness.h>
-#include <chrono>
#include <cstdint>
-#include <list>
#include <optional>
#include <vector>
@@ -56,7 +54,6 @@
#include "LayerVector.h"
#include "Scheduler/LayerInfo.h"
#include "SurfaceFlinger.h"
-#include "Tracing/LayerTracing.h"
#include "TransactionCallbackInvoker.h"
using namespace android::surfaceflinger;
@@ -97,42 +94,15 @@
eInputInfoChanged = 0x00000004
};
- struct Geometry {
- uint32_t w;
- uint32_t h;
- ui::Transform transform;
-
- inline bool operator==(const Geometry& rhs) const {
- return (w == rhs.w && h == rhs.h) && (transform.tx() == rhs.transform.tx()) &&
- (transform.ty() == rhs.transform.ty());
- }
- inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); }
- };
-
using FrameRate = scheduler::LayerInfo::FrameRate;
using FrameRateCompatibility = scheduler::FrameRateCompatibility;
using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy;
struct State {
- int32_t z;
- ui::LayerStack layerStack;
- uint32_t flags;
int32_t sequence; // changes when visible regions can change
- bool modified;
// Crop is expressed in layer space coordinate.
Rect crop;
LayerMetadata metadata;
- // If non-null, a Surface this Surface's Z-order is interpreted relative to.
- wp<Layer> zOrderRelativeOf;
- bool isRelativeOf{false};
-
- // A list of surfaces whose Z-order is interpreted relative to ours.
- SortedVector<wp<Layer>> zOrderRelatives;
- half4 color;
- float cornerRadius;
- int backgroundBlurRadius;
- gui::WindowInfo inputInfo;
- wp<Layer> touchableRegionCrop;
ui::Dataspace dataspace;
@@ -154,52 +124,18 @@
std::shared_ptr<renderengine::ExternalTexture> buffer;
sp<Fence> acquireFence;
std::shared_ptr<FenceTime> acquireFenceTime;
- HdrMetadata hdrMetadata;
- Region surfaceDamageRegion;
- int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
- bool hasColorTransform;
- // pointer to background color layer that, if set, appears below the buffer state layer
- // and the buffer state layer's children. Z order will be set to
- // INT_MIN
- sp<Layer> bgColorLayer;
// The deque of callback handles for this frame. The back of the deque contains the most
// recent callback handle.
std::deque<sp<CallbackHandle>> callbackHandles;
- bool colorSpaceAgnostic;
nsecs_t desiredPresentTime = 0;
bool isAutoTimestamp = true;
- // Length of the cast shadow. If the radius is > 0, a shadow of length shadowRadius will
- // be rendered around the layer.
- float shadowRadius;
-
- // Layer regions that are made of custom materials, like frosted glass
- std::vector<BlurRegion> blurRegions;
-
- // Priority of the layer assigned by Window Manager.
- int32_t frameRateSelectionPriority;
-
- // Default frame rate compatibility used to set the layer refresh rate votetype.
- FrameRateCompatibility defaultFrameRateCompatibility;
- FrameRate frameRate;
-
// The combined frame rate of parents / children of this layer
FrameRate frameRateForLayerTree;
- FrameRateSelectionStrategy frameRateSelectionStrategy;
-
- // Set by window manager indicating the layer and all its children are
- // in a different orientation than the display. The hint suggests that
- // the graphic producers should receive a transform hint as if the
- // display was in this orientation. When the display changes to match
- // the layer orientation, the graphic producer may not need to allocate
- // a buffer of a different size. ui::Transform::ROT_INVALID means the
- // a fixed transform hint is not set.
- ui::Transform::RotationFlags fixedTransformHint;
-
// The vsync info that was used to start the transaction
FrameTimelineInfo frameTimelineInfo;
@@ -219,21 +155,12 @@
// An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to
// trigger a warning if the number of SurfaceFrames crosses the threshold.
static constexpr uint32_t kStateSurfaceFramesThreshold = 25;
-
- // Stretch effect to apply to this layer
- StretchEffect stretchEffect;
-
- // Whether or not this layer is a trusted overlay for input
- bool isTrustedOverlay;
Rect bufferCrop;
Rect destinationFrame;
sp<IBinder> releaseBufferEndpoint;
- gui::DropInputMode dropInputMode;
bool autoRefresh = false;
- bool dimmingEnabled = true;
float currentHdrSdrRatio = 1.f;
float desiredHdrSdrRatio = -1.f;
- gui::CachingHint cachingHint = gui::CachingHint::Enabled;
int64_t latchedVsyncId = 0;
bool useVsyncIdForRefreshRateSelection = false;
};
@@ -245,17 +172,7 @@
static void miniDumpHeader(std::string& result);
// Provide unique string for each class type in the Layer hierarchy
- virtual const char* getType() const { return "Layer"; }
-
- // true if this layer is visible, false otherwise
- virtual bool isVisible() const;
-
- virtual sp<Layer> createClone();
-
- // Set a 2x2 transformation matrix on the layer. This transform
- // will be applied after parent transforms, but before any final
- // producer specified transform.
- bool setMatrix(const layer_state_t::matrix22_t& matrix);
+ const char* getType() const { return "Layer"; }
// This second set of geometry attributes are controlled by
// setGeometryAppliesWithResize, and their default mode is to be
@@ -263,50 +180,9 @@
// while a resize is pending, then update of these attributes will
// be delayed until the resize completes.
- // setPosition operates in parent buffer space (pre parent-transform) or display
- // space for top-level layers.
- bool setPosition(float x, float y);
// Buffer space
bool setCrop(const Rect& crop);
- // TODO(b/38182121): Could we eliminate the various latching modes by
- // using the layer hierarchy?
- // -----------------------------------------------------------------------
- virtual bool setLayer(int32_t z);
- virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
-
- virtual bool setAlpha(float alpha);
- bool setColor(const half3& /*color*/);
-
- // Set rounded corner radius for this layer and its children.
- //
- // We only support 1 radius per layer in the hierarchy, where parent layers have precedence.
- // The shape of the rounded corner rectangle is specified by the crop rectangle of the layer
- // from which we inferred the rounded corner radius.
- virtual bool setCornerRadius(float cornerRadius);
- // When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which
- // is specified in pixels.
- virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
- virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions);
- bool setTransparentRegionHint(const Region& transparent);
- virtual bool setTrustedOverlay(bool);
- virtual bool setFlags(uint32_t flags, uint32_t mask);
- virtual bool setLayerStack(ui::LayerStack);
- virtual ui::LayerStack getLayerStack(
- LayerVector::StateSet state = LayerVector::StateSet::Drawing) const;
-
- virtual bool setMetadata(const LayerMetadata& data);
- virtual void setChildrenDrawingParent(const sp<Layer>&);
- virtual bool reparent(const sp<IBinder>& newParentHandle) REQUIRES(mFlinger->mStateLock);
- virtual bool setColorTransform(const mat4& matrix);
- virtual mat4 getColorTransform() const;
- virtual bool hasColorTransform() const;
- virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
- virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; }
- float getDesiredHdrSdrRatio() const { return getDrawingState().desiredHdrSdrRatio; }
- float getCurrentHdrSdrRatio() const { return getDrawingState().currentHdrSdrRatio; }
- gui::CachingHint getCachingHint() const { return getDrawingState().cachingHint; }
-
bool setTransform(uint32_t /*transform*/);
bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/);
bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
@@ -317,116 +193,36 @@
bool setDataspace(ui::Dataspace /*dataspace*/);
bool setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio);
bool setDesiredHdrHeadroom(float desiredRatio);
- bool setCachingHint(gui::CachingHint cachingHint);
- bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/);
- bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/);
- bool setApi(int32_t /*api*/);
bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/,
const FrameTimelineInfo& /* info*/, nsecs_t /* postTime */,
gui::GameMode gameMode);
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& /*handles*/,
bool willPresent);
- virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace)
- REQUIRES(mFlinger->mStateLock);
- virtual bool setColorSpaceAgnostic(const bool agnostic);
- virtual bool setDimmingEnabled(const bool dimmingEnabled);
- virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
- void setAutoRefresh(bool /* autoRefresh */);
- bool setDropInputMode(gui::DropInputMode);
- ui::Dataspace getDataSpace() const;
-
- virtual bool isFrontBuffered() const;
-
- virtual sp<LayerFE> getCompositionEngineLayerFE() const;
- virtual sp<LayerFE> copyCompositionEngineLayerFE() const;
sp<LayerFE> getCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
sp<LayerFE> getOrCreateCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
- const frontend::LayerSnapshot* getLayerSnapshot() const;
- frontend::LayerSnapshot* editLayerSnapshot();
- std::unique_ptr<frontend::LayerSnapshot> stealLayerSnapshot();
- void updateLayerSnapshot(std::unique_ptr<frontend::LayerSnapshot> snapshot);
-
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
- void useSurfaceDamage();
- void useEmptyDamage();
Region getVisibleRegion(const DisplayDevice*) const;
void updateLastLatchTime(nsecs_t latchtime);
/*
- * isOpaque - true if this surface is opaque
- *
- * This takes into account the buffer format (i.e. whether or not the
- * pixel format includes an alpha channel) and the "opaque" flag set
- * on the layer. It does not examine the current plane alpha value.
- */
- bool isOpaque(const Layer::State&) const;
-
- /*
- * Returns whether this layer can receive input.
- */
- bool canReceiveInput() const;
-
- /*
- * Whether or not the layer should be considered visible for input calculations.
- */
- virtual bool isVisibleForInput() const {
- // For compatibility reasons we let layers which can receive input
- // receive input before they have actually submitted a buffer. Because
- // of this we use canReceiveInput instead of isVisible to check the
- // policy-visibility, ignoring the buffer state. However for layers with
- // hasInputInfo()==false we can use the real visibility state.
- // We are just using these layers for occlusion detection in
- // InputDispatcher, and obviously if they aren't visible they can't occlude
- // anything.
- return hasInputInfo() ? canReceiveInput() : isVisible();
- }
-
- /*
* isProtected - true if the layer may contain protected contents in the
* GRALLOC_USAGE_PROTECTED sense.
*/
bool isProtected() const;
-
- /*
- * isFixedSize - true if content has a fixed size
- */
- virtual bool isFixedSize() const { return true; }
-
/*
* usesSourceCrop - true if content should use a source crop
*/
bool usesSourceCrop() const { return hasBufferOrSidebandStream(); }
- // Most layers aren't created from the main thread, and therefore need to
- // grab the SF state lock to access HWC, but ContainerLayer does, so we need
- // to avoid grabbing the lock again to avoid deadlock
- virtual bool isCreatedFromMainThread() const { return false; }
-
- ui::Transform getActiveTransform(const Layer::State& s) const { return s.transform; }
- Region getActiveTransparentRegion(const Layer::State& s) const {
- return s.transparentRegionHint;
- }
Rect getCrop(const Layer::State& s) const { return s.crop; }
bool needsFiltering(const DisplayDevice*) const;
- // True if this layer requires filtering
- // This method is distinct from needsFiltering() in how the filter
- // requirement is computed. needsFiltering() compares displayFrame and crop,
- // where as this method transforms the displayFrame to layer-stack space
- // first. This method should be used if there is no physical display to
- // project onto when taking screenshots, as the filtering requirements are
- // different.
- // If the parent transform needs to be undone when capturing the layer, then
- // the inverse parent transform is also required.
- bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const;
-
// from graphics API
static ui::Dataspace translateDataspace(ui::Dataspace dataspace);
- void updateCloneBufferInfo();
uint64_t mPreviousFrameNumber = 0;
void onCompositionPresented(const DisplayDevice*,
@@ -443,8 +239,6 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/);
-
bool latchBufferImpl(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
bool bgColorOnly);
@@ -455,14 +249,6 @@
bool willReleaseBufferOnLatch() const;
/*
- * Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
- * This is used if the buffer is just latched and releases to free up the buffer
- * and will not be shown on screen.
- * Should only be called on the main thread.
- */
- void latchAndReleaseBuffer();
-
- /*
* returns the rectangle that crops the content of the layer and scales it
* to the layer's size.
*/
@@ -474,15 +260,6 @@
uint32_t getBufferTransform() const;
sp<GraphicBuffer> getBuffer() const;
- const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const;
-
- /*
- * Returns if a frame is ready
- */
- bool hasReadyFrame() const;
-
- virtual int32_t getQueuedFrameCount() const { return 0; }
-
/**
* Returns active buffer size in the correct orientation. Buffer size is determined by undoing
* any buffer transformations. Returns Rect::INVALID_RECT if the layer has no buffer or the
@@ -490,33 +267,10 @@
*/
Rect getBufferSize(const Layer::State&) const;
- /**
- * Returns the source bounds. If the bounds are not defined, it is inferred from the
- * buffer size. Failing that, the bounds are determined from the passed in parent bounds.
- * For the root layer, this is the display viewport size.
- */
- FloatRect computeSourceBounds(const FloatRect& parentBounds) const;
- virtual FrameRate getFrameRateForLayerTree() const;
+ FrameRate getFrameRateForLayerTree() const;
bool getTransformToDisplayInverse() const;
- // Returns how rounded corners should be drawn for this layer.
- // A layer can override its parent's rounded corner settings if the parent's rounded
- // corner crop does not intersect with its own rounded corner crop.
- virtual frontend::RoundedCornerState getRoundedCornerState() const;
-
- bool hasRoundedCorners() const { return getRoundedCornerState().hasRoundedCorners(); }
-
- PixelFormat getPixelFormat() const;
- /**
- * Return whether this layer needs an input info. We generate InputWindowHandles for all
- * non-cursor buffered layers regardless of whether they have an InputChannel. This is to enable
- * the InputDispatcher to do PID based occlusion detection.
- */
- bool needsInputInfo() const {
- return (hasInputInfo() || hasBufferOrSidebandStream()) && !mPotentialCursor;
- }
-
// Implements RefBase.
void onFirstRef() override;
@@ -527,25 +281,18 @@
uint32_t mTransform{0};
ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
Rect mCrop;
- uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
- Region mSurfaceDamage;
- HdrMetadata mHdrMetadata;
- int mApi;
PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
bool mTransformToDisplayInverse{false};
-
std::shared_ptr<renderengine::ExternalTexture> mBuffer;
uint64_t mFrameNumber;
sp<IBinder> mReleaseBufferEndpoint;
-
bool mFrameLatencyNeeded{false};
float mDesiredHdrSdrRatio = -1.f;
};
BufferInfo mBufferInfo;
+ std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseChannel;
- // implements compositionengine::LayerFE
- const compositionengine::LayerFECompositionState* getCompositionState() const;
bool fenceHasSignaled() const;
void onPreComposition(nsecs_t refreshStartTime);
void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack,
@@ -566,15 +313,6 @@
const char* getDebugName() const;
- bool setShadowRadius(float shadowRadius);
-
- // Before color management is introduced, contents on Android have to be
- // desaturated in order to match what they appears like visually.
- // With color management, these contents will appear desaturated, thus
- // needed to be saturated so that they match what they are designed for
- // visually.
- bool isLegacyDataSpace() const;
-
uint32_t getTransactionFlags() const { return mTransactionFlags; }
static bool computeTrustedPresentationState(const FloatRect& bounds,
@@ -597,14 +335,6 @@
// Clears and returns the masked bits.
uint32_t clearTransactionFlags(uint32_t mask);
- FloatRect getBounds(const Region& activeTransparentRegion) const;
- FloatRect getBounds() const;
- Rect getInputBoundsInDisplaySpace(const FloatRect& insetBounds,
- const ui::Transform& displayTransform);
-
- // Compute bounds for the layer and cache the results.
- void computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float shadowRadius);
-
int32_t getSequence() const { return sequence; }
// For tracing.
@@ -615,159 +345,36 @@
// only used within a single layer.
uint64_t getCurrentBufferId() const { return getBuffer() ? getBuffer()->getId() : 0; }
- /*
- * isSecure - true if this surface is secure, that is if it prevents
- * screenshots or VNC servers. A surface can be set to be secure by the
- * application, being secure doesn't mean the surface has DRM contents.
- */
- bool isSecure() const;
-
- /*
- * isHiddenByPolicy - true if this layer has been forced invisible.
- * just because this is false, doesn't mean isVisible() is true.
- * For example if this layer has no active buffer, it may not be hidden by
- * policy, but it still can not be visible.
- */
- bool isHiddenByPolicy() const;
-
- // True if the layer should be skipped in screenshots, screen recordings,
- // and mirroring to external or virtual displays.
- bool isInternalDisplayOverlay() const;
-
- ui::LayerFilter getOutputFilter() const {
- return {getLayerStack(), isInternalDisplayOverlay()};
- }
-
- bool isRemovedFromCurrentState() const;
-
- perfetto::protos::LayerProto* writeToProto(perfetto::protos::LayersProto& layersProto,
- uint32_t traceFlags);
void writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto,
ui::LayerStack layerStack);
- // Write states that are modified by the main thread. This includes drawing
- // state as well as buffer data. This should be called in the main or tracing
- // thread.
- void writeToProtoDrawingState(perfetto::protos::LayerProto* layerInfo);
- // Write drawing or current state. If writing current state, the caller should hold the
- // external mStateLock. If writing drawing state, this function should be called on the
- // main or tracing thread.
- void writeToProtoCommonState(perfetto::protos::LayerProto* layerInfo, LayerVector::StateSet,
- uint32_t traceFlags = LayerTracing::TRACE_ALL);
-
gui::WindowInfo::Type getWindowType() const { return mWindowType; }
- bool updateMirrorInfo(const std::deque<Layer*>& cloneRootsPendingUpdates);
-
/*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
- virtual uint32_t doTransaction(uint32_t transactionFlags);
-
- /*
- * Remove relative z for the layer if its relative parent is not part of the
- * provided layer tree.
- */
- void removeRelativeZ(const std::vector<Layer*>& layersInTree);
-
- /*
- * Remove from current state and mark for removal.
- */
- void removeFromCurrentState() REQUIRES(mFlinger->mStateLock);
-
- /*
- * called with the state lock from a binder thread when the layer is
- * removed from the current list to the pending removal list
- */
- void onRemovedFromCurrentState() REQUIRES(mFlinger->mStateLock);
-
- /*
- * Called when the layer is added back to the current state list.
- */
- void addToCurrentState();
+ uint32_t doTransaction(uint32_t transactionFlags);
inline const State& getDrawingState() const { return mDrawingState; }
inline State& getDrawingState() { return mDrawingState; }
void miniDump(std::string& result, const frontend::LayerSnapshot&, const DisplayDevice&) const;
void dumpFrameStats(std::string& result) const;
- void dumpOffscreenDebugInfo(std::string& result) const;
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
void onDisconnect();
ui::Transform getTransform() const;
- bool isTransformValid() const;
- // Returns the Alpha of the Surface, accounting for the Alpha
- // of parent Surfaces in the hierarchy (alpha's will be multiplied
- // down the hierarchy).
- half getAlpha() const;
half4 getColor() const;
int32_t getBackgroundBlurRadius() const;
bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
- // Returns the transform hint set by Window Manager on the layer or one of its parents.
- // This traverses the current state because the data is needed when creating
- // the layer(off drawing thread) and the hint should be available before the producer
- // is ready to acquire a buffer.
- ui::Transform::RotationFlags getFixedTransformHint() const;
-
- /**
- * Traverse this layer and it's hierarchy of children directly. Unlike traverseInZOrder
- * which will not emit children who have relativeZOrder to another layer, this method
- * just directly emits all children. It also emits them in no particular order.
- * So this method is not suitable for graphical operations, as it doesn't represent
- * the scene state, but it's also more efficient than traverseInZOrder and so useful for
- * book-keeping.
- */
- void traverse(LayerVector::StateSet, const LayerVector::Visitor&);
- void traverseInReverseZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
- void traverseInZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
- void traverseChildren(const LayerVector::Visitor&);
-
- /**
- * Traverse only children in z order, ignoring relative layers that are not children of the
- * parent.
- */
- void traverseChildrenInZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
-
- size_t getDescendantCount() const;
- size_t getChildrenCount() const { return mDrawingChildren.size(); }
bool isHandleAlive() const { return mHandleAlive; }
bool onHandleDestroyed() { return mHandleAlive = false; }
- // ONLY CALL THIS FROM THE LAYER DTOR!
- // See b/141111965. We need to add current children to offscreen layers in
- // the layer dtor so as not to dangle layers. Since the layer has not
- // committed its transaction when the layer is destroyed, we must add
- // current children. This is safe in the dtor as we will no longer update
- // the current state, but should not be called anywhere else!
- LayerVector& getCurrentChildren() { return mCurrentChildren; }
-
- void addChild(const sp<Layer>&);
- // Returns index if removed, or negative value otherwise
- // for symmetry with Vector::remove
- ssize_t removeChild(const sp<Layer>& layer);
- sp<Layer> getParent() const { return mCurrentParent.promote(); }
-
- // Should be called with the surfaceflinger statelock held
- bool isAtRoot() const { return mIsAtRoot; }
- void setIsAtRoot(bool isAtRoot) { mIsAtRoot = isAtRoot; }
-
- bool hasParent() const { return getParent() != nullptr; }
- Rect getScreenBounds(bool reduceTransparentRegion = true) const;
- bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
- bool setChildRelativeLayer(const sp<Layer>& childLayer,
- const sp<IBinder>& relativeToHandle, int32_t relativeZ);
-
- // Copy the current list of children to the drawing state. Called by
- // SurfaceFlinger to complete a transaction.
- void commitChildList();
- int32_t getZ(LayerVector::StateSet) const;
-
/**
* Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
* INVALID_RECT if the layer has no buffer and no crop.
@@ -776,7 +383,7 @@
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
- virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
+ void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime,
gui::GameMode gameMode);
void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
@@ -798,45 +405,21 @@
bool setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds,
TrustedPresentationListener const& listener);
+ void setBufferReleaseChannel(
+ const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel);
// Creates a new handle each time, so we only expect
// this to be called once.
sp<IBinder> getHandle();
const std::string& getName() const { return mName; }
- bool getPremultipledAlpha() const;
void setInputInfo(const gui::WindowInfo& info);
- struct InputDisplayArgs {
- const ui::Transform* transform = nullptr;
- bool isSecure = false;
- };
- gui::WindowInfo fillInputInfo(const InputDisplayArgs& displayArgs);
-
- /**
- * Returns whether this layer has an explicitly set input-info.
- */
- bool hasInputInfo() const;
-
virtual uid_t getOwnerUid() const { return mOwnerUid; }
pid_t getOwnerPid() { return mOwnerPid; }
int32_t getOwnerAppId() { return mOwnerAppId; }
- // This layer is not a clone, but it's the parent to the cloned hierarchy. The
- // variable mClonedChild represents the top layer that will be cloned so this
- // layer will be the parent of mClonedChild.
- // The layers in the cloned hierarchy will match the lifetime of the real layers. That is
- // if the real layer is destroyed, then the clone layer will also be destroyed.
- sp<Layer> mClonedChild;
- bool mHadClonedChild = false;
- void setClonedChild(const sp<Layer>& mClonedChild);
-
- mutable bool contentDirty{false};
- Region surfaceDamageRegion;
-
- // True when the surfaceDamageRegion is recognized as a small area update.
- bool mSmallDirty{false};
// Used to check if mUsedVsyncIdForRefreshRateSelection should be expired when it stop updating.
nsecs_t mMaxTimeForUseVsyncId = 0;
// True when DrawState.useVsyncIdForRefreshRateSelection previously set to true during updating
@@ -850,40 +433,11 @@
bool mPendingHWCDestroy{false};
- bool backpressureEnabled() const {
- return mDrawingState.flags & layer_state_t::eEnableBackpressure;
- }
-
- bool setStretchEffect(const StretchEffect& effect);
- StretchEffect getStretchEffect() const;
-
bool setBufferCrop(const Rect& /* bufferCrop */);
- bool setDestinationFrame(const Rect& /* destinationFrame */);
// See mPendingBufferTransactions
void decrementPendingBufferCount();
std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBufferTransactions; }
std::string getPendingBufferCounterName() { return mBlastTransactionName; }
- bool updateGeometry();
-
- bool isSimpleBufferUpdate(const layer_state_t& s) const;
-
- static bool isOpaqueFormat(PixelFormat format);
-
- // Updates the LayerSnapshot. This must be called prior to sending layer data to
- // CompositionEngine or RenderEngine (i.e. before calling CompositionEngine::present or
- // LayerFE::prepareClientComposition).
- //
- // TODO(b/238781169) Remove direct calls to RenderEngine::drawLayers that don't go through
- // CompositionEngine to create a single path for composing layers.
- void updateSnapshot(bool updateGeometry);
- void updateChildrenSnapshots(bool updateGeometry);
- sp<Layer> getClonedFrom() const {
- return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr;
- }
- bool isClone() { return mClonedFrom != nullptr; }
-
- bool willPresentCurrentTransaction() const;
-
void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, uint64_t framenumber,
const sp<Fence>& releaseFence);
@@ -929,7 +483,6 @@
const sp<SurfaceFlinger> mFlinger;
// Check if the damage region is a small dirty.
- void setIsSmallDirty(const Region& damageRegion, const ui::Transform& layerToDisplayTransform);
void setIsSmallDirty(frontend::LayerSnapshot* snapshot);
protected:
@@ -941,62 +494,16 @@
friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
- void preparePerFrameCompositionState();
- void preparePerFrameBufferCompositionState();
- void preparePerFrameEffectsCompositionState();
void gatherBufferInfo();
- bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
-
- void cloneDrawingState(const Layer* from);
- void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
- void updateClonedChildren(const sp<Layer>& mirrorRoot,
- std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
- void updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
- void addChildToDrawing(const sp<Layer>&);
- void updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
-
- void prepareBasicGeometryCompositionState();
- void prepareGeometryCompositionState();
- void prepareCursorCompositionState();
-
- uint32_t getEffectiveUsage(uint32_t usage) const;
-
- /**
- * Setup rounded corners coordinates of this layer, taking into account the layer bounds and
- * crop coordinates, transforming them into layer space.
- */
- void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const;
- void setParent(const sp<Layer>&);
- LayerVector makeTraversalList(LayerVector::StateSet, bool* outSkipRelativeZUsers);
- void addZOrderRelative(const wp<Layer>& relative);
- void removeZOrderRelative(const wp<Layer>& relative);
compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const;
compositionengine::OutputLayer* findOutputLayerForDisplay(
const DisplayDevice*, const frontend::LayerHierarchy::TraversalPath& path) const;
- bool usingRelativeZ(LayerVector::StateSet) const;
- virtual ui::Transform getInputTransform() const;
- /**
- * Get the bounds in layer space within which this layer can receive input.
- *
- * These bounds are used to:
- * - Determine the input frame for the layer to be used for occlusion detection; and
- * - Determine the coordinate space within which the layer will receive input. The top-left of
- * this rect will be the origin of the coordinate space that the input events sent to the
- * layer will be in (prior to accounting for surface insets).
- *
- * The layer can still receive touch input if these bounds are invalid if
- * "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input
- * in this layer's space, regardless of the specified crop layer.
- */
- std::pair<FloatRect, bool> getInputBounds(bool fillParentBounds) const;
-
- bool mPremultipliedAlpha{true};
const std::string mName;
const std::string mTransactionName{"TX - " + mName};
- // These are only accessed by the main thread or the tracing thread.
+ // These are only accessed by the main thread.
State mDrawingState;
TrustedPresentationThresholds mTrustedPresentationThresholds;
@@ -1016,34 +523,16 @@
// main thread
sp<NativeHandle> mSidebandStream;
- // False if the buffer and its contents have been previously used for GPU
- // composition, true otherwise.
- bool mIsActiveBufferUpdatedForGpu = true;
// We encode unset as -1.
std::atomic<uint64_t> mCurrentFrameNumber{0};
- // Whether filtering is needed b/c of the drawingstate
- bool mNeedsFiltering{false};
-
- std::atomic<bool> mRemovedFromDrawingState{false};
-
- // page-flip thread (currently main thread)
- bool mProtectedByApp{false}; // application requires protected path to external sink
// protected by mLock
mutable Mutex mLock;
- const wp<Client> mClientRef;
-
// This layer can be a cursor on some displays.
bool mPotentialCursor{false};
- LayerVector mCurrentChildren{LayerVector::StateSet::Current};
- LayerVector mDrawingChildren{LayerVector::StateSet::Drawing};
-
- wp<Layer> mCurrentParent;
- wp<Layer> mDrawingParent;
-
// Window types from WindowManager.LayoutParams
const gui::WindowInfo::Type mWindowType;
@@ -1061,8 +550,6 @@
// Used in buffer stuffing analysis in FrameTimeline.
nsecs_t mLastLatchTime = 0;
- mutable bool mDrawingStateModified = false;
-
sp<Fence> mLastClientCompositionFence;
bool mClearClientCompositionFenceOnLayerDisplayed = false;
private:
@@ -1074,61 +561,20 @@
friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
- bool getAutoRefresh() const { return mDrawingState.autoRefresh; }
bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
std::atomic<bool> mSidebandStreamChanged{false};
- // Returns true if the layer can draw shadows on its border.
- virtual bool canDrawShadows() const { return true; }
-
aidl::android::hardware::graphics::composer3::Composition getCompositionType(
const DisplayDevice&) const;
aidl::android::hardware::graphics::composer3::Composition getCompositionType(
const compositionengine::OutputLayer*) const;
- /**
- * Returns an unsorted vector of all layers that are part of this tree.
- * That includes the current layer and all its descendants.
- */
- std::vector<Layer*> getLayersInTree(LayerVector::StateSet);
- /**
- * Traverses layers that are part of this tree in the correct z order.
- * layersInTree must be sorted before calling this method.
- */
- void traverseChildrenInZOrderInner(const std::vector<Layer*>& layersInTree,
- LayerVector::StateSet, const LayerVector::Visitor&);
- LayerVector makeChildrenTraversalList(LayerVector::StateSet,
- const std::vector<Layer*>& layersInTree);
-
- bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overrideChildren,
- bool* transactionNeeded);
- void setZOrderRelativeOf(const wp<Layer>& relativeOf);
- bool isTrustedOverlay() const;
- gui::DropInputMode getDropInputMode() const;
- void handleDropInputMode(gui::WindowInfo& info) const;
-
- // Find the root of the cloned hierarchy, this means the first non cloned parent.
- // This will return null if first non cloned parent is not found.
- sp<Layer> getClonedRoot();
-
- // Finds the top most layer in the hierarchy. This will find the root Layer where the parent is
- // null.
- sp<Layer> getRootLayer();
-
- // Fills in the touch occlusion mode of the first parent (including this layer) that
- // hasInputInfo() or no-op if no such parent is found.
- void fillTouchOcclusionMode(gui::WindowInfo& info);
-
- // Fills in the frame and transform info for the gui::WindowInfo.
- void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& screenToDisplay);
inline void tracePendingBufferCount(int32_t pendingBuffers);
// Latch sideband stream and returns true if the dirty region should be updated.
bool latchSidebandStream(bool& recomputeVisibleRegions);
- bool hasFrameUpdate() const;
-
void updateTexImage(nsecs_t latchTime, bool bgColorOnly = false);
// Crop that applies to the buffer
@@ -1139,15 +585,6 @@
const sp<Fence>& releaseFence,
uint32_t currentMaxAcquiredBufferCount);
- // Returns true if the transformed buffer size does not match the layer size and we need
- // to apply filtering.
- bool bufferNeedsFiltering() const;
-
- // Returns true if there is a valid color to fill.
- bool fillsColor() const;
- // Returns true if this layer has a blur value.
- bool hasBlur() const;
- bool hasEffect() const { return fillsColor() || drawShadows() || hasBlur(); }
bool hasBufferOrSidebandStream() const {
return ((mSidebandStream != nullptr) || (mBufferInfo.mBuffer != nullptr));
}
@@ -1156,41 +593,8 @@
return ((mDrawingState.sidebandStream != nullptr) || (mDrawingState.buffer != nullptr));
}
- bool hasSomethingToDraw() const { return hasEffect() || hasBufferOrSidebandStream(); }
-
- bool shouldOverrideChildrenFrameRate() const {
- return getDrawingState().frameRateSelectionStrategy ==
- FrameRateSelectionStrategy::OverrideChildren;
- }
-
- bool shouldPropagateFrameRate() const {
- return getDrawingState().frameRateSelectionStrategy != FrameRateSelectionStrategy::Self;
- }
-
- // Cached properties computed from drawing state
- // Effective transform taking into account parent transforms and any parent scaling, which is
- // a transform from the current layer coordinate space to display(screen) coordinate space.
- ui::Transform mEffectiveTransform;
-
- // Bounds of the layer before any transformation is applied and before it has been cropped
- // by its parents.
- FloatRect mSourceBounds;
-
- // Bounds of the layer in layer space. This is the mSourceBounds cropped by its layer crop and
- // its parent bounds.
- FloatRect mBounds;
-
- // Layer bounds in screen space.
- FloatRect mScreenBounds;
-
bool mGetHandleCalled = false;
- // The current layer is a clone of mClonedFrom. This means that this layer will update it's
- // properties based on mClonedFrom. When mClonedFrom latches a new buffer for BufferLayers,
- // this layer will update it's buffer. When mClonedFrom updates it's drawing state, children,
- // and relatives, this layer will update as well.
- wp<Layer> mClonedFrom;
-
// The inherited shadow radius after taking into account the layer hierarchy. This is the
// final shadow radius for this layer. If a shadow is specified for a layer, then effective
// shadow radius is the set shadow radius, otherwise its the parent's shadow radius.
@@ -1199,15 +603,10 @@
// Game mode for the layer. Set by WindowManagerShell and recorded by SurfaceFlingerStats.
gui::GameMode mGameMode = gui::GameMode::Unsupported;
- // A list of regions on this layer that should have blurs.
- const std::vector<BlurRegion> getBlurRegions() const;
-
bool mIsAtRoot = false;
uint32_t mLayerCreationFlags;
- bool findInHierarchy(const sp<Layer>&);
-
void releasePreviousBuffer();
void resetDrawingStateBufferInfo();
@@ -1240,10 +639,7 @@
// not specify a destination frame.
ui::Transform mRequestedTransform;
- sp<LayerFE> mLegacyLayerFE;
std::vector<std::pair<frontend::LayerHierarchy::TraversalPath, sp<LayerFE>>> mLayerFEs;
- std::unique_ptr<frontend::LayerSnapshot> mSnapshot =
- std::make_unique<frontend::LayerSnapshot>();
bool mHandleAlive = false;
};
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 0d2987c..5eea45b 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -178,7 +178,7 @@
}
void LayerProtoHelper::writeToProto(
- const WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+ const WindowInfo& inputInfo,
std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto) {
if (inputInfo.token == nullptr) {
return;
@@ -208,13 +208,6 @@
proto->set_global_scale_factor(inputInfo.globalScaleFactor);
LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform());
proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop);
- auto cropLayer = touchableRegionBounds.promote();
- if (cropLayer != nullptr) {
- proto->set_crop_layer_id(cropLayer->sequence);
- LayerProtoHelper::writeToProto(cropLayer->getScreenBounds(
- false /* reduceTransparentRegion */),
- [&]() { return proto->mutable_touchable_region_crop(); });
- }
}
void LayerProtoHelper::writeToProto(const mat4 matrix,
@@ -263,7 +256,7 @@
outRegion.bottom = proto.bottom();
}
-perfetto::protos::LayersProto LayerProtoFromSnapshotGenerator::generate(
+LayerProtoFromSnapshotGenerator& LayerProtoFromSnapshotGenerator::with(
const frontend::LayerHierarchy& root) {
mLayersProto.clear_layers();
mVisitedLayers.clear();
@@ -305,9 +298,40 @@
}
}
- mDefaultSnapshots.clear();
- mChildToRelativeParent.clear();
- return std::move(mLayersProto);
+ return *this;
+}
+
+LayerProtoFromSnapshotGenerator& LayerProtoFromSnapshotGenerator::withOffscreenLayers(
+ const frontend::LayerHierarchy& offscreenRoot) {
+ // Add a fake invisible root layer to the proto output and parent all the offscreen layers to
+ // it.
+ perfetto::protos::LayerProto* rootProto = mLayersProto.add_layers();
+ const int32_t offscreenRootLayerId = INT32_MAX - 2;
+ rootProto->set_id(offscreenRootLayerId);
+ rootProto->set_name("Offscreen Root");
+ rootProto->set_parent(-1);
+
+ perfetto::protos::LayersProto offscreenLayers =
+ LayerProtoFromSnapshotGenerator(mSnapshotBuilder, mDisplayInfos, mLegacyLayers,
+ mTraceFlags)
+ .with(offscreenRoot)
+ .generate();
+
+ for (int i = 0; i < offscreenLayers.layers_size(); i++) {
+ perfetto::protos::LayerProto* layerProto = offscreenLayers.mutable_layers()->Mutable(i);
+ if (layerProto->parent() == -1) {
+ layerProto->set_parent(offscreenRootLayerId);
+ // Add layer as child of the fake root
+ rootProto->add_children(layerProto->id());
+ }
+ }
+
+ mLayersProto.mutable_layers()->Reserve(mLayersProto.layers_size() +
+ offscreenLayers.layers_size());
+ std::copy(offscreenLayers.layers().begin(), offscreenLayers.layers().end(),
+ RepeatedFieldBackInserter(mLayersProto.mutable_layers()));
+
+ return *this;
}
frontend::LayerSnapshot* LayerProtoFromSnapshotGenerator::getSnapshot(
@@ -451,7 +475,7 @@
layerInfo->set_owner_uid(requestedState.ownerUid.val());
if ((traceFlags & LayerTracing::TRACE_INPUT) && snapshot.hasInputInfo()) {
- LayerProtoHelper::writeToProto(snapshot.inputInfo, {},
+ LayerProtoHelper::writeToProto(snapshot.inputInfo,
[&]() { return layerInfo->mutable_input_window_info(); });
}
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index d672012..41ea684 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -62,7 +62,7 @@
const renderengine::ExternalTexture& buffer,
std::function<perfetto::protos::ActiveBufferProto*()> getActiveBufferProto);
static void writeToProto(
- const gui::WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+ const gui::WindowInfo& inputInfo,
std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto);
static void writeToProto(const mat4 matrix,
perfetto::protos::ColorTransformProto* colorTransformProto);
@@ -88,7 +88,12 @@
mLegacyLayers(legacyLayers),
mDisplayInfos(displayInfos),
mTraceFlags(traceFlags) {}
- perfetto::protos::LayersProto generate(const frontend::LayerHierarchy& root);
+ LayerProtoFromSnapshotGenerator& with(const frontend::LayerHierarchy& root);
+ // Creates a fake root and adds all offscreen layers from the passed in hierarchy to the fake
+ // root
+ LayerProtoFromSnapshotGenerator& withOffscreenLayers(
+ const frontend::LayerHierarchy& offscreenRoot);
+ perfetto::protos::LayersProto generate() { return mLayersProto; };
private:
void writeHierarchyToProto(const frontend::LayerHierarchy& root,
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index f52e60d..13e054e 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -45,51 +45,12 @@
const auto& lState = l->getDrawingState();
const auto& rState = r->getDrawingState();
- const auto ls = lState.layerStack;
- const auto rs = rState.layerStack;
- if (ls != rs)
- return (ls > rs) ? 1 : -1;
-
- int32_t lz = lState.z;
- int32_t rz = rState.z;
- if (lz != rz)
- return (lz > rz) ? 1 : -1;
-
if (l->sequence == r->sequence)
return 0;
return (l->sequence > r->sequence) ? 1 : -1;
}
-void LayerVector::traverseInZOrder(StateSet stateSet, const Visitor& visitor) const {
- for (size_t i = 0; i < size(); i++) {
- const auto& layer = (*this)[i];
- auto& state = layer->getDrawingState();
- if (state.isRelativeOf) {
- continue;
- }
- layer->traverseInZOrder(stateSet, visitor);
- }
-}
-
-void LayerVector::traverseInReverseZOrder(StateSet stateSet, const Visitor& visitor) const {
- for (auto i = static_cast<int64_t>(size()) - 1; i >= 0; i--) {
- const auto& layer = (*this)[i];
- auto& state = layer->getDrawingState();
- if (state.isRelativeOf) {
- continue;
- }
- layer->traverseInReverseZOrder(stateSet, visitor);
- }
-}
-
-void LayerVector::traverse(const Visitor& visitor) const {
- for (auto i = static_cast<int64_t>(size()) - 1; i >= 0; i--) {
- const auto& layer = (*this)[i];
- layer->traverse(mStateSet, visitor);
- }
-}
-
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/LayerVector.h b/services/surfaceflinger/LayerVector.h
index a531f4f..38dc11d 100644
--- a/services/surfaceflinger/LayerVector.h
+++ b/services/surfaceflinger/LayerVector.h
@@ -46,11 +46,8 @@
// Sorts layer by layer-stack, Z order, and finally creation order (sequence).
int do_compare(const void* lhs, const void* rhs) const override;
-
using Visitor = std::function<void(Layer*)>;
- void traverseInReverseZOrder(StateSet stateSet, const Visitor& visitor) const;
- void traverseInZOrder(StateSet stateSet, const Visitor& visitor) const;
- void traverse(const Visitor& visitor) const;
+
private:
const StateSet mStateSet;
};
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 034e467..aa66ccf 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -39,21 +39,6 @@
mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill) {}
- static std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> fromTraverseLayersLambda(
- std::function<void(const LayerVector::Visitor&)> traverseLayers) {
- return [traverseLayers = std::move(traverseLayers)]() {
- std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
- traverseLayers([&](Layer* layer) {
- // Layer::prepareClientComposition uses the layer's snapshot to populate the
- // resulting LayerSettings. Calling Layer::updateSnapshot ensures that LayerSettings
- // are generated with the layer's current buffer and geometry.
- layer->updateSnapshot(true /* updateGeometry */);
- layers.emplace_back(layer, layer->copyCompositionEngineLayerFE());
- });
- return layers;
- };
- }
-
virtual ~RenderArea() = default;
// Returns true if the render area is secure. A secure layer should be
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index d31fcea..218c56e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -320,7 +320,8 @@
mVsyncRegistration.update({.workDuration = mWorkDuration.get().count(),
.readyDuration = mReadyDuration.count(),
- .lastVsync = mLastVsyncCallbackTime.ns()});
+ .lastVsync = mLastVsyncCallbackTime.ns(),
+ .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
}
sp<EventThreadConnection> EventThread::createEventConnection(
@@ -527,10 +528,11 @@
}
if (mState == State::VSync) {
- const auto scheduleResult =
- mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
- .readyDuration = mReadyDuration.count(),
- .lastVsync = mLastVsyncCallbackTime.ns()});
+ const auto scheduleResult = mVsyncRegistration.schedule(
+ {.workDuration = mWorkDuration.get().count(),
+ .readyDuration = mReadyDuration.count(),
+ .lastVsync = mLastVsyncCallbackTime.ns(),
+ .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
LOG_ALWAYS_FATAL_IF(!scheduleResult, "Error scheduling callback");
} else {
mVsyncRegistration.cancel();
@@ -725,8 +727,9 @@
}
if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC &&
FlagManager::getInstance().vrr_config()) {
- mCallback.onExpectedPresentTimePosted(
- TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime()));
+ mLastCommittedVsyncTime =
+ TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime());
+ mCallback.onExpectedPresentTimePosted(mLastCommittedVsyncTime);
}
}
@@ -744,9 +747,12 @@
const auto relativeLastCallTime =
ticks<std::milli, float>(mLastVsyncCallbackTime - TimePoint::now());
+ const auto relativeLastCommittedTime =
+ ticks<std::milli, float>(mLastCommittedVsyncTime - TimePoint::now());
StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
mWorkDuration.get().count() / 1e6f, mReadyDuration.count() / 1e6f);
StringAppendF(&result, "%.2fms relative to now\n", relativeLastCallTime);
+ StringAppendF(&result, " with vsync committed at %.2fms", relativeLastCommittedTime);
StringAppendF(&result, " pending events (count=%zu):\n", mPendingEvents.size());
for (const auto& event : mPendingEvents) {
@@ -794,7 +800,8 @@
if (reschedule) {
mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
.readyDuration = mReadyDuration.count(),
- .lastVsync = mLastVsyncCallbackTime.ns()});
+ .lastVsync = mLastVsyncCallbackTime.ns(),
+ .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
}
return oldRegistration;
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index f772126..bbe4f9d 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -220,6 +220,7 @@
std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex);
std::shared_ptr<scheduler::VsyncSchedule> mVsyncSchedule GUARDED_BY(mMutex);
TimePoint mLastVsyncCallbackTime GUARDED_BY(mMutex) = TimePoint::now();
+ TimePoint mLastCommittedVsyncTime GUARDED_BY(mMutex) = TimePoint::now();
scheduler::VSyncCallbackRegistration mVsyncRegistration GUARDED_BY(mMutex);
frametimeline::TokenManager* const mTokenManager;
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index dbc458c..ff1926e 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -595,8 +595,7 @@
return true;
}
- if (FlagManager::getInstance().view_set_requested_frame_rate_mrr() &&
- category == FrameRateCategory::NoPreference && vote.rate.isValid() &&
+ if (category == FrameRateCategory::NoPreference && vote.rate.isValid() &&
vote.type == FrameRateCompatibility::ExactOrMultiple) {
return true;
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 9f6eab2..ab9014e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -841,7 +841,8 @@
return score.overallScore == 0;
});
- if (policy->primaryRangeIsSingleRate()) {
+ // TODO(b/364651864): Evaluate correctness of primaryRangeIsSingleRate.
+ if (!mIsVrrDevice.load() && policy->primaryRangeIsSingleRate()) {
// If we never scored any layers, then choose the rate from the primary
// range instead of picking a random score from the app range.
if (noLayerScore) {
@@ -887,8 +888,8 @@
const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
using fps_approx_ops::operator<;
- if (scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) {
- ALOGV("Touch Boost");
+ if (scores.front().frameRateMode.fps <= touchRefreshRates.front().frameRateMode.fps) {
+ ALOGV("Touch Boost [late]");
SFTRACE_FORMAT_INSTANT("%s (Touch Boost [late])",
to_string(touchRefreshRates.front().frameRateMode.fps).c_str());
return {touchRefreshRates, GlobalSignals{.touch = true}};
@@ -1394,13 +1395,14 @@
const auto& idleScreenConfigOpt = getCurrentPolicyLocked()->idleScreenConfigOpt;
if (idleScreenConfigOpt != oldPolicy.idleScreenConfigOpt) {
if (!idleScreenConfigOpt.has_value()) {
- // fallback to legacy timer if existed, otherwise pause the old timer
- LOG_ALWAYS_FATAL_IF(!mIdleTimer);
- if (mConfig.legacyIdleTimerTimeout > 0ms) {
- mIdleTimer->setInterval(mConfig.legacyIdleTimerTimeout);
- mIdleTimer->resume();
- } else {
- mIdleTimer->pause();
+ if (mIdleTimer) {
+ // fallback to legacy timer if existed, otherwise pause the old timer
+ if (mConfig.legacyIdleTimerTimeout > 0ms) {
+ mIdleTimer->setInterval(mConfig.legacyIdleTimerTimeout);
+ mIdleTimer->resume();
+ } else {
+ mIdleTimer->pause();
+ }
}
} else if (idleScreenConfigOpt->timeoutMillis > 0) {
// create a new timer or reconfigure
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 566bb8e..be00079 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -127,7 +127,7 @@
mVsyncModulator->cancelRefreshRateChange();
mVsyncConfiguration->reset();
- updatePhaseConfiguration(pacesetterSelectorPtr()->getActiveMode().fps);
+ updatePhaseConfiguration(pacesetterId, pacesetterSelectorPtr()->getActiveMode().fps);
}
void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
@@ -487,7 +487,12 @@
}
}
-void Scheduler::updatePhaseConfiguration(Fps refreshRate) {
+void Scheduler::updatePhaseConfiguration(PhysicalDisplayId displayId, Fps refreshRate) {
+ const bool isPacesetter =
+ FTL_FAKE_GUARD(kMainThreadContext,
+ (std::scoped_lock(mDisplayLock), displayId == mPacesetterDisplayId));
+ if (!isPacesetter) return;
+
mRefreshRateStats->setRefreshRate(refreshRate);
mVsyncConfiguration->setRefreshRateFps(refreshRate);
setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()),
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 88f0e94..1367ec3 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -187,7 +187,7 @@
}
}
- void updatePhaseConfiguration(Fps);
+ void updatePhaseConfiguration(PhysicalDisplayId, Fps);
const VsyncConfiguration& getVsyncConfiguration() const { return *mVsyncConfiguration; }
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 0c43ffb..8993c38 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -93,6 +93,8 @@
* readyDuration will typically be 0.
* @lastVsync: The targeted display time. This will be snapped to the closest
* predicted vsync time after lastVsync.
+ * @committedVsyncOpt: The display time that is committed to the callback as the
+ * target vsync time.
*
* callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync
* event.
@@ -101,10 +103,11 @@
nsecs_t workDuration = 0;
nsecs_t readyDuration = 0;
nsecs_t lastVsync = 0;
+ std::optional<nsecs_t> committedVsyncOpt;
bool operator==(const ScheduleTiming& other) const {
return workDuration == other.workDuration && readyDuration == other.readyDuration &&
- lastVsync == other.lastVsync;
+ lastVsync == other.lastVsync && committedVsyncOpt == other.committedVsyncOpt;
}
bool operator!=(const ScheduleTiming& other) const { return !(*this == other); }
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 900bce0..1925f11 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -103,7 +103,8 @@
tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
now + timing.workDuration +
timing.readyDuration),
- timing.lastVsync);
+ timing.committedVsyncOpt.value_or(
+ timing.lastVsync));
auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
bool const wouldSkipAVsyncTarget =
@@ -208,9 +209,12 @@
const auto workDelta = mWorkloadUpdateInfo->workDuration - mScheduleTiming.workDuration;
const auto readyDelta = mWorkloadUpdateInfo->readyDuration - mScheduleTiming.readyDuration;
const auto lastVsyncDelta = mWorkloadUpdateInfo->lastVsync - mScheduleTiming.lastVsync;
+ const auto lastCommittedVsyncDelta =
+ mWorkloadUpdateInfo->committedVsyncOpt.value_or(mWorkloadUpdateInfo->lastVsync) -
+ mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync);
SFTRACE_FORMAT_INSTANT("Workload updated workDelta=%" PRId64 " readyDelta=%" PRId64
- " lastVsyncDelta=%" PRId64,
- workDelta, readyDelta, lastVsyncDelta);
+ " lastVsyncDelta=%" PRId64 " committedVsyncDelta=%" PRId64,
+ workDelta, readyDelta, lastVsyncDelta, lastCommittedVsyncDelta);
mScheduleTiming = *mWorkloadUpdateInfo;
mWorkloadUpdateInfo.reset();
}
@@ -261,10 +265,14 @@
StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
mRunning ? "(in callback function)" : "", armedInfo.c_str());
StringAppendF(&result,
- "\t\t\tworkDuration: %.2fms readyDuration: %.2fms lastVsync: %.2fms relative "
- "to now\n",
+ "\t\t\tworkDuration: %.2fms readyDuration: %.2fms "
+ "lastVsync: %.2fms relative to now "
+ "committedVsync: %.2fms relative to now\n",
mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
- (mScheduleTiming.lastVsync - systemTime()) / 1e6f);
+ (mScheduleTiming.lastVsync - systemTime()) / 1e6f,
+ (mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync) -
+ systemTime()) /
+ 1e6f);
if (mLastDispatchTime) {
StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 4a7cff5..6e36f02 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -695,9 +695,12 @@
if (lastFrameMissed) {
// If the last frame missed is the last vsync, we already shifted the timeline. Depends
// on whether we skipped the frame (onFrameMissed) or not (onFrameBegin) we apply a
- // different fixup. There is no need to to shift the vsync timeline again.
- vsyncTime += missedVsync.fixup.ns();
- SFTRACE_FORMAT_INSTANT("lastFrameMissed");
+ // different fixup if we are violating the minFramePeriod.
+ // There is no need to shift the vsync timeline again.
+ if (vsyncTime - missedVsync.vsync.ns() < minFramePeriodOpt->ns()) {
+ vsyncTime += missedVsync.fixup.ns();
+ SFTRACE_FORMAT_INSTANT("lastFrameMissed");
+ }
} else if (mightBackpressure && lastVsyncOpt) {
if (!FlagManager::getInstance().vrr_bugfix_24q4()) {
// lastVsyncOpt does not need to be corrected with the new rate, and
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7590d98..c794a7b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -532,9 +532,6 @@
mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
// These are set by the HWC implementation to indicate that they will use the workarounds.
- mIsHotplugErrViaNegVsync =
- base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false);
-
mIsHdcpViaNegVsync = base::GetBoolProperty("debug.sf.hwc_hdcp_via_neg_vsync"s, false);
}
@@ -1280,20 +1277,14 @@
return BAD_VALUE;
}
+ // TODO: b/277364366 - Require a display token from clients and remove fallback to pacesetter.
std::optional<PhysicalDisplayId> displayIdOpt;
- {
+ if (displayToken) {
Mutex::Autolock lock(mStateLock);
- if (displayToken) {
- displayIdOpt = getPhysicalDisplayIdLocked(displayToken);
- if (!displayIdOpt) {
- ALOGW("%s: Invalid physical display token %p", __func__, displayToken.get());
- return NAME_NOT_FOUND;
- }
- } else {
- // TODO (b/277364366): Clients should be updated to pass in the display they
- // want, rather than us picking an arbitrary one (the active display, in this
- // case).
- displayIdOpt = mActiveDisplayId;
+ displayIdOpt = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayIdOpt) {
+ ALOGW("%s: Invalid physical display token %p", __func__, displayToken.get());
+ return NAME_NOT_FOUND;
}
}
@@ -1340,19 +1331,13 @@
// VsyncController model is locked.
mScheduler->modulateVsync(displayId, &VsyncModulator::onRefreshRateChangeInitiated);
- if (displayId == mActiveDisplayId) {
- mScheduler->updatePhaseConfiguration(mode.fps);
- }
-
+ mScheduler->updatePhaseConfiguration(displayId, mode.fps);
mScheduler->setModeChangePending(true);
break;
}
case DesiredModeAction::InitiateRenderRateSwitch:
mScheduler->setRenderRate(displayId, mode.fps, /*applyImmediately*/ false);
-
- if (displayId == mActiveDisplayId) {
- mScheduler->updatePhaseConfiguration(mode.fps);
- }
+ mScheduler->updatePhaseConfiguration(displayId, mode.fps);
if (emitEvent) {
mScheduler->onDisplayModeChanged(displayId, mode);
@@ -1447,9 +1432,7 @@
mDisplayModeController.finalizeModeChange(displayId, activeMode.modePtr->getId(),
activeMode.modePtr->getVsyncRate(), activeMode.fps);
- if (displayId == mActiveDisplayId) {
- mScheduler->updatePhaseConfiguration(activeMode.fps);
- }
+ mScheduler->updatePhaseConfiguration(displayId, activeMode.fps);
if (pendingModeOpt->emitEvent) {
mScheduler->onDisplayModeChanged(displayId, activeMode);
@@ -1473,11 +1456,9 @@
constexpr bool kAllowToEnable = true;
mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, std::move(activeModePtr).take());
- mScheduler->setRenderRate(displayId, renderFps, /*applyImmediately*/ true);
- if (displayId == mActiveDisplayId) {
- mScheduler->updatePhaseConfiguration(renderFps);
- }
+ mScheduler->setRenderRate(displayId, renderFps, /*applyImmediately*/ true);
+ mScheduler->updatePhaseConfiguration(displayId, renderFps);
}
void SurfaceFlinger::initiateDisplayModeChanges() {
@@ -2188,21 +2169,13 @@
std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
if (FlagManager::getInstance().connected_display() && timestamp < 0 &&
vsyncPeriod.has_value()) {
- // use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32
- if (mIsHotplugErrViaNegVsync && vsyncPeriod.value() == ~0) {
- const auto errorCode = static_cast<int32_t>(-timestamp);
- ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId);
- mScheduler->dispatchHotplugError(errorCode);
- return;
- }
-
if (mIsHdcpViaNegVsync && vsyncPeriod.value() == ~1) {
const int32_t value = static_cast<int32_t>(-timestamp);
// one byte is good enough to encode android.hardware.drm.HdcpLevel
const int32_t maxLevel = (value >> 8) & 0xFF;
const int32_t connectedLevel = value & 0xFF;
- ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for display %" PRIu64, __func__,
- connectedLevel, maxLevel, hwcDisplayId);
+ ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for hwcDisplayId %" PRIu64,
+ __func__, connectedLevel, maxLevel, hwcDisplayId);
updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel);
return;
}
@@ -2242,7 +2215,7 @@
if (FlagManager::getInstance().hotplug2()) {
// TODO(b/311403559): use enum type instead of int
const auto errorCode = static_cast<int32_t>(event);
- ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId);
+ ALOGD("%s: Hotplug error %d for hwcDisplayId %" PRIu64, __func__, errorCode, hwcDisplayId);
mScheduler->dispatchHotplugError(errorCode);
}
}
@@ -2292,6 +2265,18 @@
}));
}
+void SurfaceFlinger::onComposerHalHdcpLevelsChanged(hal::HWDisplayId hwcDisplayId,
+ const HdcpLevels& levels) {
+ if (FlagManager::getInstance().hdcp_level_hal()) {
+ // TODO(b/362270040): propagate enum constants
+ const int32_t maxLevel = static_cast<int32_t>(levels.maxLevel);
+ const int32_t connectedLevel = static_cast<int32_t>(levels.connectedLevel);
+ ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for hwcDisplayId %" PRIu64, __func__,
+ connectedLevel, maxLevel, hwcDisplayId);
+ updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel);
+ }
+}
+
void SurfaceFlinger::configure() {
Mutex::Autolock lock(mStateLock);
if (configureLocked()) {
@@ -2387,7 +2372,7 @@
{
// TODO(b/238781169) lockless queue this and keep order.
std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
- update.layerCreatedStates = std::move(mCreatedLayers);
+ update.legacyLayers = std::move(mCreatedLayers);
mCreatedLayers.clear();
update.newLayers = std::move(mNewLayers);
mNewLayers.clear();
@@ -2406,11 +2391,8 @@
}
mLayerLifecycleManager.applyTransactions(update.transactions);
mLayerLifecycleManager.onHandlesDestroyed(update.destroyedHandles);
- for (auto& legacyLayer : update.layerCreatedStates) {
- sp<Layer> layer = legacyLayer.layer.promote();
- if (layer) {
- mLegacyLayers[layer->sequence] = layer;
- }
+ for (auto& legacyLayer : update.legacyLayers) {
+ mLegacyLayers[legacyLayer->sequence] = legacyLayer;
}
mLayerHierarchyBuilder.update(mLayerLifecycleManager);
}
@@ -2467,7 +2449,7 @@
bool newDataLatched = false;
SFTRACE_NAME("DisplayCallbackAndStatsUpdates");
- mustComposite |= applyTransactionsLocked(update.transactions, vsyncId);
+ mustComposite |= applyTransactionsLocked(update.transactions);
traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); });
const nsecs_t latchTime = systemTime();
bool unused = false;
@@ -2757,7 +2739,8 @@
if (!FlagManager::getInstance().ce_fence_promise()) {
refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
for (auto& [layer, _] : mLayersWithQueuedFrames) {
- if (const auto& layerFE = layer->getCompositionEngineLayerFE())
+ if (const auto& layerFE = layer->getCompositionEngineLayerFE(
+ {static_cast<uint32_t>(layer->sequence)}))
refreshArgs.layersWithQueuedFrames.push_back(layerFE);
}
}
@@ -2833,7 +2816,8 @@
refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
for (auto& [layer, _] : mLayersWithQueuedFrames) {
- if (const auto& layerFE = layer->getCompositionEngineLayerFE()) {
+ if (const auto& layerFE = layer->getCompositionEngineLayerFE(
+ {static_cast<uint32_t>(layer->sequence)})) {
refreshArgs.layersWithQueuedFrames.push_back(layerFE);
// Some layers are not displayed and do not yet have a future release fence
if (layerFE->getReleaseFencePromiseStatus() ==
@@ -2864,9 +2848,7 @@
for (auto [layer, layerFE] : layers) {
CompositionResult compositionResult{layerFE->stealCompositionResult()};
for (auto& [releaseFence, layerStack] : compositionResult.releaseFences) {
- Layer* clonedFrom = layer->getClonedFrom().get();
- auto owningLayer = clonedFrom ? clonedFrom : layer;
- owningLayer->onLayerDisplayed(std::move(releaseFence), layerStack);
+ layer->onLayerDisplayed(std::move(releaseFence), layerStack);
}
if (compositionResult.lastClientCompositionFence) {
layer->setWasClientComposed(compositionResult.lastClientCompositionFence);
@@ -3835,7 +3817,8 @@
mDisplays.erase(displayToken);
if (const auto& physical = currentState.physical) {
- getHwComposer().allocatePhysicalDisplay(physical->hwcDisplayId, physical->id);
+ getHwComposer().allocatePhysicalDisplay(physical->hwcDisplayId, physical->id,
+ /*physicalSize=*/std::nullopt);
}
processDisplayAdded(displayToken, currentState);
@@ -3931,7 +3914,6 @@
// Commit display transactions.
const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
mFrontEndDisplayInfosChanged = displayTransactionNeeded;
- mForceTransactionDisplayChange = displayTransactionNeeded;
if (mSomeChildrenChanged) {
mVisibleRegionsDirty = true;
@@ -4252,6 +4234,8 @@
if (data.hintStatus.compare_exchange_strong(scheduleHintOnTx,
NotifyExpectedPresentHintStatus::Sent)) {
sendHint();
+ constexpr bool kAllowToEnable = true;
+ mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable);
}
}));
}
@@ -4352,55 +4336,8 @@
void SurfaceFlinger::doCommitTransactions() {
SFTRACE_CALL();
-
- if (!mLayersPendingRemoval.isEmpty()) {
- // Notify removed layers now that they can't be drawn from
- for (const auto& l : mLayersPendingRemoval) {
- // Ensure any buffers set to display on any children are released.
- if (l->isRemovedFromCurrentState()) {
- l->latchAndReleaseBuffer();
- }
-
- // If a layer has a parent, we allow it to out-live it's handle
- // with the idea that the parent holds a reference and will eventually
- // be cleaned up. However no one cleans up the top-level so we do so
- // here.
- if (l->isAtRoot()) {
- l->setIsAtRoot(false);
- mCurrentState.layersSortedByZ.remove(l);
- }
- }
- mLayersPendingRemoval.clear();
- }
-
mDrawingState = mCurrentState;
mCurrentState.colorMatrixChanged = false;
-
- if (mVisibleRegionsDirty) {
- for (const auto& rootLayer : mDrawingState.layersSortedByZ) {
- rootLayer->commitChildList();
- }
- }
-
- if (mLayerMirrorRoots.size() > 0) {
- std::deque<Layer*> pendingUpdates;
- pendingUpdates.insert(pendingUpdates.end(), mLayerMirrorRoots.begin(),
- mLayerMirrorRoots.end());
- std::vector<Layer*> needsUpdating;
- for (Layer* cloneRoot : mLayerMirrorRoots) {
- pendingUpdates.pop_front();
- if (cloneRoot->isRemovedFromCurrentState()) {
- continue;
- }
- if (cloneRoot->updateMirrorInfo(pendingUpdates)) {
- } else {
- needsUpdating.push_back(cloneRoot);
- }
- }
- for (Layer* cloneRoot : needsUpdating) {
- cloneRoot->updateMirrorInfo({});
- }
- }
}
void SurfaceFlinger::invalidateLayerStack(const ui::LayerFilter& layerFilter, const Region& dirty) {
@@ -4443,7 +4380,7 @@
args.layerIdToMirror = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
{
std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
- mCreatedLayers.emplace_back(layer, parent, args.addToRoot);
+ mCreatedLayers.emplace_back(layer);
mNewLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args));
args.mirrorLayerHandle.clear();
args.parentHandle.clear();
@@ -4638,20 +4575,18 @@
}
// For tests only
-bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) {
+bool SurfaceFlinger::flushTransactionQueues() {
mTransactionHandler.collectTransactions();
std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions();
- return applyTransactions(transactions, vsyncId);
+ return applyTransactions(transactions);
}
-bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
- VsyncId vsyncId) {
+bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) {
Mutex::Autolock lock(mStateLock);
- return applyTransactionsLocked(transactions, vsyncId);
+ return applyTransactionsLocked(transactions);
}
-bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions,
- VsyncId vsyncId) {
+bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions) {
bool needsTraversal = false;
// Now apply all transactions.
for (auto& transaction : transactions) {
@@ -5131,6 +5066,10 @@
}
}
+ if (what & layer_state_t::eBufferReleaseChannelChanged) {
+ layer->setBufferReleaseChannel(s.bufferReleaseChannel);
+ }
+
const auto& requestedLayerState = mLayerLifecycleManager.getLayerFromId(layer->getSequence());
bool willPresentCurrentTransaction = requestedLayerState &&
(requestedLayerState->hasReadyFrame() ||
@@ -5169,8 +5108,6 @@
if (result != NO_ERROR) {
return result;
}
-
- mirrorLayer->setClonedChild(mirrorFrom->createClone());
}
outResult.layerId = mirrorLayer->sequence;
@@ -5284,33 +5221,22 @@
return NO_ERROR;
}
-void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
- mLayersPendingRemoval.add(layer);
- mLayersRemoved = true;
- setTransactionFlags(eTransactionNeeded);
-}
-
void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32_t layerId) {
{
- std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
- mDestroyedHandles.emplace_back(layerId, layer->getDebugName());
- }
-
- {
// Used to remove stalled transactions which uses an internal lock.
ftl::FakeGuard guard(kMainThreadContext);
mTransactionHandler.onLayerDestroyed(layerId);
}
-
JankTracker::flushJankData(layerId);
- Mutex::Autolock lock(mStateLock);
- markLayerPendingRemovalLocked(layer);
+ std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
+ mDestroyedHandles.emplace_back(layerId, layer->getDebugName());
+
+ Mutex::Autolock stateLock(mStateLock);
layer->onHandleDestroyed();
mBufferCountTracker.remove(handle);
layer.clear();
-
- setTransactionFlags(eTransactionFlushNeeded);
+ setTransactionFlags(eTransactionFlushNeeded | eTransactionNeeded);
}
void SurfaceFlinger::initializeDisplays() {
@@ -5879,9 +5805,16 @@
}
}
- return LayerProtoFromSnapshotGenerator(mLayerSnapshotBuilder, mFrontEndDisplayInfos,
- mLegacyLayers, traceFlags)
- .generate(mLayerHierarchyBuilder.getHierarchy());
+ auto traceGenerator =
+ LayerProtoFromSnapshotGenerator(mLayerSnapshotBuilder, mFrontEndDisplayInfos,
+ mLegacyLayers, traceFlags)
+ .with(mLayerHierarchyBuilder.getHierarchy());
+
+ if (traceFlags & LayerTracing::Flag::TRACE_EXTRA) {
+ traceGenerator.withOffscreenLayers(mLayerHierarchyBuilder.getOffscreenHierarchy());
+ }
+
+ return traceGenerator.generate();
}
google::protobuf::RepeatedPtrField<perfetto::protos::DisplayProto>
@@ -5915,36 +5848,6 @@
getHwComposer().dump(result);
}
-void SurfaceFlinger::dumpOffscreenLayersProto(perfetto::protos::LayersProto& layersProto,
- uint32_t traceFlags) const {
- // Add a fake invisible root layer to the proto output and parent all the offscreen layers to
- // it.
- perfetto::protos::LayerProto* rootProto = layersProto.add_layers();
- const int32_t offscreenRootLayerId = INT32_MAX - 2;
- rootProto->set_id(offscreenRootLayerId);
- rootProto->set_name("Offscreen Root");
- rootProto->set_parent(-1);
-
- perfetto::protos::LayersProto offscreenLayers =
- LayerProtoFromSnapshotGenerator(mLayerSnapshotBuilder, mFrontEndDisplayInfos,
- mLegacyLayers, traceFlags)
- .generate(mLayerHierarchyBuilder.getOffscreenHierarchy());
-
- for (int i = 0; i < offscreenLayers.layers_size(); i++) {
- perfetto::protos::LayerProto* layerProto = offscreenLayers.mutable_layers()->Mutable(i);
- if (layerProto->parent() == -1) {
- layerProto->set_parent(offscreenRootLayerId);
- // Add layer as child of the fake root
- rootProto->add_children(layerProto->id());
- }
- }
-
- layersProto.mutable_layers()->Reserve(layersProto.layers_size() +
- offscreenLayers.layers_size());
- std::copy(offscreenLayers.layers().begin(), offscreenLayers.layers().end(),
- RepeatedFieldBackInserter(layersProto.mutable_layers()));
-}
-
perfetto::protos::LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
return mScheduler
->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) {
@@ -6898,7 +6801,8 @@
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- if (uid == AID_GRAPHICS || PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+ if (uid == AID_GRAPHICS || uid == AID_SYSTEM ||
+ PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
return OK;
}
@@ -7239,9 +7143,7 @@
void SurfaceFlinger::attachReleaseFenceFutureToLayer(Layer* layer, LayerFE* layerFE,
ui::LayerStack layerStack) {
ftl::Future<FenceResult> futureFence = layerFE->createReleaseFenceFuture();
- Layer* clonedFrom = layer->getClonedFrom().get();
- auto owningLayer = clonedFrom ? clonedFrom : layer;
- owningLayer->prepareReleaseCallbacks(std::move(futureFence), layerStack);
+ layer->prepareReleaseCallbacks(std::move(futureFence), layerStack);
}
// Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -7778,18 +7680,6 @@
// ---------------------------------------------------------------------------
-void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const {
- layersSortedByZ.traverse(visitor);
-}
-
-void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const {
- layersSortedByZ.traverseInZOrder(stateSet, visitor);
-}
-
-void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& visitor) const {
- layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
-}
-
ftl::Optional<scheduler::FrameRateMode> SurfaceFlinger::getPreferredDisplayMode(
PhysicalDisplayId displayId, DisplayModeId defaultModeId) const {
if (const auto schedulerMode = mScheduler->getPreferredDisplayMode();
@@ -7958,16 +7848,12 @@
void SurfaceFlinger::onLayerFirstRef(Layer* layer) {
mNumLayers++;
- if (!layer->isRemovedFromCurrentState()) {
- mScheduler->registerLayer(layer, scheduler::FrameRateCompatibility::Default);
- }
+ mScheduler->registerLayer(layer, scheduler::FrameRateCompatibility::Default);
}
void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
mNumLayers--;
- if (!layer->isRemovedFromCurrentState()) {
- mScheduler->deregisterLayer(layer);
- }
+ mScheduler->deregisterLayer(layer);
if (mTransactionTracing) {
mTransactionTracing->onLayerRemoved(layer->getSequence());
}
@@ -8120,37 +8006,6 @@
return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
}
-void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, VsyncId vsyncId) {
- sp<Layer> layer = state.layer.promote();
- if (!layer) {
- ALOGD("Layer was destroyed soon after creation %p", state.layer.unsafe_get());
- return;
- }
- MUTEX_ALIAS(mStateLock, layer->mFlinger->mStateLock);
-
- sp<Layer> parent;
- bool addToRoot = state.addToRoot;
- if (state.initialParent != nullptr) {
- parent = state.initialParent.promote();
- if (parent == nullptr) {
- ALOGD("Parent was destroyed soon after creation %p", state.initialParent.unsafe_get());
- addToRoot = false;
- }
- }
-
- if (parent == nullptr && addToRoot) {
- layer->setIsAtRoot(true);
- mCurrentState.layersSortedByZ.add(layer);
- } else if (parent == nullptr) {
- layer->onRemovedFromCurrentState();
- } else if (parent->isRemovedFromCurrentState()) {
- parent->addChild(layer);
- layer->onRemovedFromCurrentState();
- } else {
- parent->addChild(layer);
- }
-}
-
void SurfaceFlinger::sample() {
if (!mLumaSampling || !mRegionSamplingThread) {
return;
@@ -8518,9 +8373,6 @@
0);
auto layers = dumpDrawingStateProto(traceFlags);
- if (traceFlags & LayerTracing::Flag::TRACE_EXTRA) {
- dumpOffscreenLayersProto(layers);
- }
*snapshot.mutable_layers() = std::move(layers);
if (traceFlags & LayerTracing::Flag::TRACE_HWC) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7fb5c36..3eb72cc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -135,6 +135,7 @@
class ScreenCapturer;
class WindowInfosListenerInvoker;
+using ::aidl::android::hardware::drm::HdcpLevels;
using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
using frontend::TransactionHandler;
@@ -297,8 +298,6 @@
// the client can no longer modify this layer directly.
void onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32_t layerId);
- std::vector<Layer*> mLayerMirrorRoots;
-
TransactionCallbackInvoker& getTransactionCallbackInvoker() {
return mTransactionCallbackInvoker;
}
@@ -389,11 +388,10 @@
class State {
public:
- explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {}
+ explicit State(LayerVector::StateSet set) : stateSet(set) {}
State& operator=(const State& other) {
// We explicitly don't copy stateSet so that, e.g., mDrawingState
// always uses the Drawing StateSet.
- layersSortedByZ = other.layersSortedByZ;
displays = other.displays;
colorMatrixChanged = other.colorMatrixChanged;
if (colorMatrixChanged) {
@@ -405,7 +403,6 @@
}
const LayerVector::StateSet stateSet = LayerVector::StateSet::Invalid;
- LayerVector layersSortedByZ;
// TODO(b/241285876): Replace deprecated DefaultKeyedVector with ftl::SmallMap.
DefaultKeyedVector<wp<IBinder>, DisplayDeviceState> displays;
@@ -425,10 +422,6 @@
mat4 colorMatrix;
ShadowSettings globalShadowSettings;
-
- void traverse(const LayerVector::Visitor& visitor) const;
- void traverseInZOrder(const LayerVector::Visitor& visitor) const;
- void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
};
// Keeps track of pending buffers per layer handle in the transaction queue or current/drawing
@@ -679,6 +672,7 @@
void onComposerHalSeamlessPossible(hal::HWDisplayId) override;
void onComposerHalVsyncIdle(hal::HWDisplayId) override;
void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) override;
+ void onComposerHalHdcpLevelsChanged(hal::HWDisplayId, const HdcpLevels& levels) override;
// ICompositor overrides:
void configure() override REQUIRES(kMainThreadContext);
@@ -791,9 +785,9 @@
REQUIRES(mStateLock, kMainThreadContext);
// Flush pending transactions that were presented after desiredPresentTime.
// For test only
- bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext);
+ bool flushTransactionQueues() REQUIRES(kMainThreadContext);
- bool applyTransactions(std::vector<TransactionState>&, VsyncId) REQUIRES(kMainThreadContext);
+ bool applyTransactions(std::vector<TransactionState>&) REQUIRES(kMainThreadContext);
bool applyAndCommitDisplayTransactionStatesLocked(std::vector<TransactionState>& transactions)
REQUIRES(kMainThreadContext, mStateLock);
@@ -823,7 +817,7 @@
static LatchUnsignaledConfig getLatchUnsignaledConfig();
bool shouldLatchUnsignaled(const layer_state_t&, size_t numStates, bool firstTransaction) const;
- bool applyTransactionsLocked(std::vector<TransactionState>& transactions, VsyncId)
+ bool applyTransactionsLocked(std::vector<TransactionState>& transactions)
REQUIRES(mStateLock, kMainThreadContext);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
@@ -847,8 +841,6 @@
status_t mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args,
gui::CreateSurfaceResult& outResult);
- void markLayerPendingRemovalLocked(const sp<Layer>& layer) REQUIRES(mStateLock);
-
// add a layer to SurfaceFlinger
status_t addClientLayer(LayerCreationArgs& args, const sp<IBinder>& handle,
const sp<Layer>& layer, const wp<Layer>& parentLayer,
@@ -1129,9 +1121,6 @@
perfetto::protos::LayersProto dumpDrawingStateProto(uint32_t traceFlags) const
REQUIRES(kMainThreadContext);
- void dumpOffscreenLayersProto(perfetto::protos::LayersProto& layersProto,
- uint32_t traceFlags = LayerTracing::TRACE_ALL) const
- REQUIRES(kMainThreadContext);
google::protobuf::RepeatedPtrField<perfetto::protos::DisplayProto> dumpDisplayProto() const;
void doActiveLayersTracingIfNeeded(bool isCompositionComputed, bool visibleRegionDirty,
TimePoint, VsyncId) REQUIRES(kMainThreadContext);
@@ -1203,7 +1192,6 @@
State mCurrentState{LayerVector::StateSet::Current};
std::atomic<int32_t> mTransactionFlags = 0;
std::atomic<uint32_t> mUniqueTransactionId = 1;
- SortedVector<sp<Layer>> mLayersPendingRemoval;
// Buffers that have been discarded by clients and need to be evicted from per-layer caches so
// the graphics memory can be immediately freed.
@@ -1243,7 +1231,6 @@
// TODO: Also move visibleRegions over to a boolean system.
bool mUpdateInputInfo = false;
bool mSomeChildrenChanged;
- bool mForceTransactionDisplayChange = false;
bool mUpdateAttachedChoreographer = false;
struct LayerIntHash {
@@ -1274,7 +1261,6 @@
};
bool mIsHdcpViaNegVsync = false;
- bool mIsHotplugErrViaNegVsync = false;
std::mutex mHotplugMutex;
std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex);
@@ -1393,13 +1379,6 @@
std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners
GUARDED_BY(mStateLock);
- mutable std::mutex mCreatedLayersLock;
-
- // A temporay pool that store the created layers and will be added to current state in main
- // thread.
- std::vector<LayerCreatedState> mCreatedLayers GUARDED_BY(mCreatedLayersLock);
- void handleLayerCreatedLocked(const LayerCreatedState&, VsyncId) REQUIRES(mStateLock);
-
std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
// Must only be accessed on the main thread.
@@ -1440,6 +1419,8 @@
frontend::LayerHierarchyBuilder mLayerHierarchyBuilder GUARDED_BY(kMainThreadContext);
frontend::LayerSnapshotBuilder mLayerSnapshotBuilder GUARDED_BY(kMainThreadContext);
+ mutable std::mutex mCreatedLayersLock;
+ std::vector<sp<Layer>> mCreatedLayers GUARDED_BY(mCreatedLayersLock);
std::vector<std::pair<uint32_t, std::string>> mDestroyedHandles GUARDED_BY(mCreatedLayersLock);
std::vector<std::unique_ptr<frontend::RequestedLayerState>> mNewLayers
GUARDED_BY(mCreatedLayersLock);
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 617ea2c..1dba175 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -162,7 +162,10 @@
auto layersProto =
LayerProtoFromSnapshotGenerator(snapshotBuilder, displayInfos, {}, traceFlags)
- .generate(hierarchyBuilder.getHierarchy());
+ .with(hierarchyBuilder.getHierarchy())
+ .withOffscreenLayers(hierarchyBuilder.getOffscreenHierarchy())
+ .generate();
+
auto displayProtos = LayerProtoHelper::writeDisplayInfoToProto(displayInfos);
if (!onlyLastEntry || (i == traceFile.entry_size() - 1)) {
perfetto::protos::LayersSnapshotProto snapshotProto{};
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 881bf35..c6856ae 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -149,6 +149,13 @@
handle->transformHint,
handle->currentMaxAcquiredBufferCount,
eventStats, handle->previousReleaseCallbackId);
+ if (handle->bufferReleaseChannel &&
+ handle->previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) {
+ mBufferReleases.emplace_back(handle->bufferReleaseChannel,
+ handle->previousReleaseCallbackId,
+ handle->previousReleaseFence,
+ handle->currentMaxAcquiredBufferCount);
+ }
}
return NO_ERROR;
}
@@ -158,6 +165,12 @@
}
void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
+ for (const auto& bufferRelease : mBufferReleases) {
+ bufferRelease.channel->writeReleaseFence(bufferRelease.callbackId, bufferRelease.fence,
+ bufferRelease.currentMaxAcquiredBufferCount);
+ }
+ mBufferReleases.clear();
+
// For each listener
auto completedTransactionsItr = mCompletedTransactions.begin();
ftl::SmallVector<ListenerStats, 10> listenerStatsToSend;
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 7853a9f..14a7487 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -16,18 +16,14 @@
#pragma once
-#include <condition_variable>
#include <deque>
-#include <mutex>
#include <optional>
-#include <queue>
-#include <thread>
#include <unordered_map>
-#include <unordered_set>
#include <android-base/thread_annotations.h>
#include <binder/IBinder.h>
#include <ftl/future.h>
+#include <gui/BufferReleaseChannel.h>
#include <gui/ITransactionCompletedListener.h>
#include <ui/Fence.h>
#include <ui/FenceResult.h>
@@ -59,6 +55,7 @@
uint64_t frameNumber = 0;
uint64_t previousFrameNumber = 0;
ReleaseCallbackId previousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
+ std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> bufferReleaseChannel;
};
class TransactionCallbackInvoker {
@@ -86,6 +83,14 @@
std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash>
mCompletedTransactions;
+ struct BufferRelease {
+ std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> channel;
+ ReleaseCallbackId callbackId;
+ sp<Fence> fence;
+ uint32_t currentMaxAcquiredBufferCount;
+ };
+ std::vector<BufferRelease> mBufferReleases;
+
sp<Fence> mPresentFence;
};
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 8ec908f..12d6138 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -119,7 +119,6 @@
DUMP_READ_ONLY_FLAG(connected_display);
DUMP_READ_ONLY_FLAG(enable_small_area_detection);
DUMP_READ_ONLY_FLAG(frame_rate_category_mrr);
- DUMP_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr);
DUMP_READ_ONLY_FLAG(misc1);
DUMP_READ_ONLY_FLAG(vrr_config);
DUMP_READ_ONLY_FLAG(hotplug2);
@@ -144,11 +143,13 @@
DUMP_READ_ONLY_FLAG(ce_fence_promise);
DUMP_READ_ONLY_FLAG(idle_screen_refresh_rate_timeout);
DUMP_READ_ONLY_FLAG(graphite_renderengine);
+ DUMP_READ_ONLY_FLAG(filter_frames_before_trace_starts);
DUMP_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed);
DUMP_READ_ONLY_FLAG(deprecate_vsync_sf);
DUMP_READ_ONLY_FLAG(allow_n_vsyncs_in_targeter);
DUMP_READ_ONLY_FLAG(detached_mirror);
DUMP_READ_ONLY_FLAG(commit_not_composited);
+ DUMP_READ_ONLY_FLAG(correct_dpi_with_display_size);
DUMP_READ_ONLY_FLAG(local_tonemap_screenshots);
DUMP_READ_ONLY_FLAG(override_trusted_overlay);
DUMP_READ_ONLY_FLAG(flush_buffer_slots_to_uncache);
@@ -224,8 +225,6 @@
FLAG_MANAGER_READ_ONLY_FLAG(connected_display, "")
FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "")
FLAG_MANAGER_READ_ONLY_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr")
-FLAG_MANAGER_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr,
- "debug.sf.view_set_requested_frame_rate_mrr")
FLAG_MANAGER_READ_ONLY_FLAG(misc1, "")
FLAG_MANAGER_READ_ONLY_FLAG(vrr_config, "debug.sf.enable_vrr_config")
FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "")
@@ -250,11 +249,13 @@
FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_dropped_frame, "")
FLAG_MANAGER_READ_ONLY_FLAG(ce_fence_promise, "");
FLAG_MANAGER_READ_ONLY_FLAG(graphite_renderengine, "debug.renderengine.graphite")
+FLAG_MANAGER_READ_ONLY_FLAG(filter_frames_before_trace_starts, "")
FLAG_MANAGER_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed, "");
FLAG_MANAGER_READ_ONLY_FLAG(deprecate_vsync_sf, "");
FLAG_MANAGER_READ_ONLY_FLAG(allow_n_vsyncs_in_targeter, "");
FLAG_MANAGER_READ_ONLY_FLAG(detached_mirror, "");
FLAG_MANAGER_READ_ONLY_FLAG(commit_not_composited, "");
+FLAG_MANAGER_READ_ONLY_FLAG(correct_dpi_with_display_size, "");
FLAG_MANAGER_READ_ONLY_FLAG(local_tonemap_screenshots, "debug.sf.local_tonemap_screenshots");
FLAG_MANAGER_READ_ONLY_FLAG(override_trusted_overlay, "");
FLAG_MANAGER_READ_ONLY_FLAG(flush_buffer_slots_to_uncache, "");
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 473e564..a1be194 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -56,7 +56,6 @@
/// Trunk stable readonly flags ///
bool connected_display() const;
bool frame_rate_category_mrr() const;
- bool view_set_requested_frame_rate_mrr() const;
bool enable_small_area_detection() const;
bool misc1() const;
bool vrr_config() const;
@@ -82,11 +81,13 @@
bool ce_fence_promise() const;
bool idle_screen_refresh_rate_timeout() const;
bool graphite_renderengine() const;
+ bool filter_frames_before_trace_starts() const;
bool latch_unsignaled_with_auto_refresh_changed() const;
bool deprecate_vsync_sf() const;
bool allow_n_vsyncs_in_targeter() const;
bool detached_mirror() const;
bool commit_not_composited() const;
+ bool correct_dpi_with_display_size() const;
bool local_tonemap_screenshots() const;
bool override_trusted_overlay() const;
bool flush_buffer_slots_to_uncache() const;
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index 0ff846e7..102e2b6 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -4,10 +4,10 @@
container: "system"
flag {
- name: "adpf_gpu_sf"
- namespace: "game"
- description: "Guards use of the sending ADPF GPU duration hint and load hints from SurfaceFlinger to Power HAL"
- bug: "284324521"
+ name: "adpf_gpu_sf"
+ namespace: "game"
+ description: "Guards use of the sending ADPF GPU duration hint and load hints from SurfaceFlinger to Power HAL"
+ bug: "284324521"
} # adpf_gpu_sf
flag {
@@ -21,18 +21,29 @@
}
} # ce_fence_promise
- flag {
- name: "commit_not_composited"
- namespace: "core_graphics"
- description: "mark frames as non janky if the transaction resulted in no composition"
- bug: "340633280"
- is_fixed_read_only: true
- metadata {
- purpose: PURPOSE_BUGFIX
- }
- } # commit_not_composited
+flag {
+ name: "commit_not_composited"
+ namespace: "core_graphics"
+ description: "mark frames as non janky if the transaction resulted in no composition"
+ bug: "340633280"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} # commit_not_composited
- flag {
+flag {
+ name: "correct_dpi_with_display_size"
+ namespace: "core_graphics"
+ description: "indicate whether missing or likely incorrect dpi should be corrected using the display size."
+ bug: "328425848"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} # correct_dpi_with_display_size
+
+flag {
name: "deprecate_vsync_sf"
namespace: "core_graphics"
description: "Depracate eVsyncSourceSurfaceFlinger and use vsync_app everywhere"
@@ -43,7 +54,7 @@
}
} # deprecate_vsync_sf
- flag {
+flag {
name: "detached_mirror"
namespace: "window_surfaces"
description: "Ignore local transform when mirroring a partial hierarchy"
@@ -55,6 +66,17 @@
} # detached_mirror
flag {
+ name: "filter_frames_before_trace_starts"
+ namespace: "core_graphics"
+ description: "Do not trace FrameTimeline events for frames started before the trace started"
+ bug: "364194637"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} # filter_frames_before_trace_starts
+
+flag {
name: "flush_buffer_slots_to_uncache"
namespace: "core_graphics"
description: "Flush DisplayCommands for disabled displays in order to uncache requested buffers."
@@ -96,11 +118,11 @@
} # latch_unsignaled_with_auto_refresh_changed
flag {
- name: "local_tonemap_screenshots"
- namespace: "core_graphics"
- description: "Enables local tonemapping when capturing screenshots"
- bug: "329464641"
- is_fixed_read_only: true
+ name: "local_tonemap_screenshots"
+ namespace: "core_graphics"
+ description: "Enables local tonemapping when capturing screenshots"
+ bug: "329464641"
+ is_fixed_read_only: true
} # local_tonemap_screenshots
flag {
@@ -115,11 +137,11 @@
} # single_hop_screenshot
flag {
- name: "true_hdr_screenshots"
- namespace: "core_graphics"
- description: "Enables screenshotting display content in HDR, sans tone mapping"
- bug: "329470026"
- is_fixed_read_only: true
+ name: "true_hdr_screenshots"
+ namespace: "core_graphics"
+ description: "Enables screenshotting display content in HDR, sans tone mapping"
+ bug: "329470026"
+ is_fixed_read_only: true
} # true_hdr_screenshots
flag {
@@ -134,11 +156,11 @@
} # override_trusted_overlay
flag {
- name: "view_set_requested_frame_rate_mrr"
- namespace: "core_graphics"
- description: "Enable to use frame rate category NoPreference with fixed frame rate vote on MRR devices"
- bug: "352206100"
- is_fixed_read_only: true
+ name: "view_set_requested_frame_rate_mrr"
+ namespace: "core_graphics"
+ description: "Enable to use frame rate category NoPreference with fixed frame rate vote on MRR devices"
+ bug: "352206100"
+ is_fixed_read_only: true
} # view_set_requested_frame_rate_mrr
flag {
diff --git a/services/surfaceflinger/tests/OWNERS b/services/surfaceflinger/tests/OWNERS
index 56f2f1b..7857961 100644
--- a/services/surfaceflinger/tests/OWNERS
+++ b/services/surfaceflinger/tests/OWNERS
@@ -4,5 +4,5 @@
per-file Layer* = set noparent
per-file Layer* = pdwilliams@google.com, vishnun@google.com, melodymhsu@google.com
-per-file LayerHistoryTest.cpp = file:/services/surfaceflinger/OWNERS
+per-file LayerHistoryIntegrationTest.cpp = file:/services/surfaceflinger/OWNERS
per-file LayerInfoTest.cpp = file:/services/surfaceflinger/OWNERS
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index 3104dd4..ae380ad 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -515,6 +515,23 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setEdgeExtensionEffect(uint32_t id, int edge) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.what |= layer_state_t::eEdgeExtensionChanged;
+ transactions.back().states.front().state.edgeExtensionParameters =
+ gui::EdgeExtensionParameters();
+ transactions.back().states.front().state.edgeExtensionParameters.extendLeft = edge & LEFT;
+ transactions.back().states.front().state.edgeExtensionParameters.extendRight = edge & RIGHT;
+ transactions.back().states.front().state.edgeExtensionParameters.extendTop = edge & TOP;
+ transactions.back().states.front().state.edgeExtensionParameters.extendBottom =
+ edge & BOTTOM;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
private:
LayerLifecycleManager& mLifecycleManager;
};
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 9be0fc3..0dfbd61 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -84,9 +84,11 @@
void SetUp() override {
constexpr bool kUseBootTimeClock = true;
+ constexpr bool kFilterFramesBeforeTraceStarts = false;
mTimeStats = std::make_shared<mock::TimeStats>();
mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid,
- kTestThresholds, !kUseBootTimeClock);
+ kTestThresholds, !kUseBootTimeClock,
+ kFilterFramesBeforeTraceStarts);
mFrameTimeline->registerDataSource();
mTokenManager = &mFrameTimeline->mTokenManager;
mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 2cff2f2..e0753a3 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -58,6 +58,7 @@
using Hwc2::Config;
+using ::aidl::android::hardware::drm::HdcpLevels;
using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent;
using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
using hal::IComposerClient;
@@ -165,6 +166,7 @@
expectHotplugConnect(kHwcDisplayId);
const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED);
ASSERT_TRUE(info);
+ ASSERT_TRUE(info->preferredDetailedTimingDescriptor.has_value());
EXPECT_CALL(*mHal, isVrrSupported()).WillRepeatedly(Return(false));
@@ -178,6 +180,10 @@
constexpr int32_t kHeight = 720;
constexpr int32_t kConfigGroup = 1;
constexpr int32_t kVsyncPeriod = 16666667;
+ constexpr float kMmPerInch = 25.4f;
+ const ui::Size size = info->preferredDetailedTimingDescriptor->physicalSizeInMm;
+ const float expectedDpiX = (kWidth * kMmPerInch / size.width);
+ const float expectedDpiY = (kHeight * kMmPerInch / size.height);
EXPECT_CALL(*mHal,
getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::WIDTH,
@@ -217,8 +223,13 @@
EXPECT_EQ(modes.front().height, kHeight);
EXPECT_EQ(modes.front().configGroup, kConfigGroup);
EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
- EXPECT_EQ(modes.front().dpiX, -1);
- EXPECT_EQ(modes.front().dpiY, -1);
+ if (!FlagManager::getInstance().correct_dpi_with_display_size()) {
+ EXPECT_EQ(modes.front().dpiX, -1);
+ EXPECT_EQ(modes.front().dpiY, -1);
+ } else {
+ EXPECT_EQ(modes.front().dpiX, expectedDpiX);
+ EXPECT_EQ(modes.front().dpiY, expectedDpiY);
+ }
// Optional parameters are supported
constexpr int32_t kDpi = 320;
@@ -270,6 +281,10 @@
constexpr int32_t kHeight = 720;
constexpr int32_t kConfigGroup = 1;
constexpr int32_t kVsyncPeriod = 16666667;
+ constexpr float kMmPerInch = 25.4f;
+ const ui::Size size = info->preferredDetailedTimingDescriptor->physicalSizeInMm;
+ const float expectedDpiX = (kWidth * kMmPerInch / size.width);
+ const float expectedDpiY = (kHeight * kMmPerInch / size.height);
EXPECT_CALL(*mHal,
getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::WIDTH,
@@ -309,8 +324,13 @@
EXPECT_EQ(modes.front().height, kHeight);
EXPECT_EQ(modes.front().configGroup, kConfigGroup);
EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
- EXPECT_EQ(modes.front().dpiX, -1);
- EXPECT_EQ(modes.front().dpiY, -1);
+ if (!FlagManager::getInstance().correct_dpi_with_display_size()) {
+ EXPECT_EQ(modes.front().dpiX, -1);
+ EXPECT_EQ(modes.front().dpiY, -1);
+ } else {
+ EXPECT_EQ(modes.front().dpiX, expectedDpiX);
+ EXPECT_EQ(modes.front().dpiY, expectedDpiY);
+ }
// Optional parameters are supported
constexpr int32_t kDpi = 320;
@@ -360,6 +380,10 @@
constexpr int32_t kHeight = 720;
constexpr int32_t kConfigGroup = 1;
constexpr int32_t kVsyncPeriod = 16666667;
+ constexpr float kMmPerInch = 25.4f;
+ const ui::Size size = info->preferredDetailedTimingDescriptor->physicalSizeInMm;
+ const float expectedDpiX = (kWidth * kMmPerInch / size.width);
+ const float expectedDpiY = (kHeight * kMmPerInch / size.height);
const hal::VrrConfig vrrConfig =
hal::VrrConfig{.minFrameIntervalNs = static_cast<Fps>(120_Hz).getPeriodNsecs(),
.notifyExpectedPresentConfig = hal::VrrConfig::
@@ -386,8 +410,13 @@
EXPECT_EQ(modes.front().configGroup, kConfigGroup);
EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
EXPECT_EQ(modes.front().vrrConfig, vrrConfig);
- EXPECT_EQ(modes.front().dpiX, -1);
- EXPECT_EQ(modes.front().dpiY, -1);
+ if (!FlagManager::getInstance().correct_dpi_with_display_size()) {
+ EXPECT_EQ(modes.front().dpiX, -1);
+ EXPECT_EQ(modes.front().dpiY, -1);
+ } else {
+ EXPECT_EQ(modes.front().dpiX, expectedDpiX);
+ EXPECT_EQ(modes.front().dpiY, expectedDpiY);
+ }
// Supports optional dpi parameter
constexpr int32_t kDpi = 320;
@@ -454,6 +483,8 @@
MOCK_METHOD1(onComposerHalSeamlessPossible, void(hal::HWDisplayId));
MOCK_METHOD1(onComposerHalVsyncIdle, void(hal::HWDisplayId));
MOCK_METHOD(void, onRefreshRateChangedDebug, (const RefreshRateChangedDebugData&), (override));
+ MOCK_METHOD(void, onComposerHalHdcpLevelsChanged, (hal::HWDisplayId, const HdcpLevels&),
+ (override));
};
struct HWComposerSetCallbackTest : HWComposerTest {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
index 7e84408..de37b63 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -894,7 +894,6 @@
TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithFixedSourceAndNoPreferenceCategory) {
SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false);
- SET_FLAG_FOR_TEST(flags::view_set_requested_frame_rate_mrr, true);
auto layer = createLegacyAndFrontedEndLayer(1);
setFrameRate(1, (45.6_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 2860345..9020723 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -27,6 +27,7 @@
#include "LayerHierarchyTest.h"
#include "ui/GraphicTypes.h"
+#include <com_android_graphics_libgui_flags.h>
#include <com_android_graphics_surfaceflinger_flags.h>
#define UPDATE_AND_VERIFY(BUILDER, ...) \
@@ -1761,4 +1762,162 @@
UPDATE_AND_VERIFY(mSnapshotBuilder, {2});
EXPECT_TRUE(getSnapshot(1)->isHiddenByPolicy());
}
+TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) {
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ setCrop(1, Rect(0, 0, 20, 20));
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(20 /* width */,
+ 20 /* height */,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ setEdgeExtensionEffect(12, LEFT);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(LEFT));
+ EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(LEFT));
+ EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(LEFT));
+
+ setEdgeExtensionEffect(12, RIGHT);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(RIGHT));
+ EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(RIGHT));
+ EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(RIGHT));
+
+ setEdgeExtensionEffect(12, TOP);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(TOP));
+ EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(TOP));
+ EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(TOP));
+
+ setEdgeExtensionEffect(12, BOTTOM);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(BOTTOM));
+ EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(BOTTOM));
+ EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(BOTTOM));
+}
+
+TEST_F(LayerSnapshotTest, leftEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The left bound is extended when shifting to the right
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ setCrop(1, Rect(0, 0, 20, 20));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = 5.0;
+ setPosition(12, translation, 0);
+ setEdgeExtensionEffect(12, LEFT);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+ EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.left, translation);
+ EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.left, 0.0);
+}
+
+TEST_F(LayerSnapshotTest, rightEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The right bound is extended when shifting to the left
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ const int crop = 20;
+ setCrop(1, Rect(0, 0, crop, crop));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = -5.0;
+ setPosition(12, translation, 0);
+ setEdgeExtensionEffect(12, RIGHT);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.left, 0);
+ EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+ EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.right, (float)crop);
+}
+
+TEST_F(LayerSnapshotTest, topEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The top bound is extended when shifting to the bottom
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ setCrop(1, Rect(0, 0, 20, 20));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = 5.0;
+ setPosition(12, 0, translation);
+ setEdgeExtensionEffect(12, TOP);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize + translation);
+ EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.top, translation);
+ EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0.0);
+}
+
+TEST_F(LayerSnapshotTest, bottomEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The bottom bound is extended when shifting to the top
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ const int crop = 20;
+ setCrop(1, Rect(0, 0, crop, crop));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = -5.0;
+ setPosition(12, 0, translation);
+ setEdgeExtensionEffect(12, BOTTOM);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.top, 0);
+ EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize - translation);
+ EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.bottom, (float)crop);
+}
+
+TEST_F(LayerSnapshotTest, multipleEdgeExtensionIncreaseBoundSizeWithinCrop) {
+ // The left bound is extended when shifting to the right
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+ }
+ const int crop = 20;
+ setCrop(1, Rect(0, 0, crop, crop));
+ const int texSize = 10;
+ setBuffer(1221,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+ texSize /* height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ const float translation = 5.0;
+ setPosition(12, translation, translation);
+ setEdgeExtensionEffect(12, LEFT | RIGHT | TOP | BOTTOM);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+ EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.right, (float)crop);
+ EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.left, translation);
+ EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.left, 0.0);
+ EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize + translation);
+ EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.bottom, (float)crop);
+ EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.top, translation);
+ EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 06c4e30..9efe73d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1837,6 +1837,43 @@
}
}
+TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_vrrHighHintTouch_primaryRangeIsSingleRate) {
+ if (GetParam() != Config::FrameRateOverride::Enabled) {
+ return;
+ }
+
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+ auto selector = createSelector(kVrrMode_120, kModeId120);
+ selector.setActiveMode(kModeId120, 60_Hz);
+
+ // Change primary physical range to be single rate, which on VRR device should not affect
+ // fps scoring.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}}));
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+ layers[0].vote = LayerVoteType::ExplicitCategory;
+ layers[0].frameRateCategory = FrameRateCategory::HighHint;
+ layers[0].name = "ExplicitCategory HighHint";
+
+ auto actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ // Expect late touch boost from HighHint.
+ EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+ EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
+
+ layers[1].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[1].desiredRefreshRate = 30_Hz;
+ layers[1].name = "ExplicitExactOrMultiple 30Hz";
+
+ actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ // Expect late touch boost from HighHint.
+ EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+ EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
+}
+
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighHint) {
auto selector = createSelector(makeModes(kMode24, kMode30, kMode60, kMode120), kModeId60);
@@ -1955,7 +1992,7 @@
// Gets touch boost
EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
- EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
}
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_TouchBoost) {
@@ -2049,7 +2086,7 @@
lr2.name = "Max";
actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true});
EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, actualRankedFrameRates.ranking.front().frameRateMode);
- EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitCategory;
lr1.frameRateCategory = FrameRateCategory::Normal;
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 358f6b0..45ca7e2 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -884,7 +884,6 @@
mScheduler->createDisplayEventConnection(Cycle::Render, {}, layer->getHandle());
layer.clear();
- mFlinger.mutableLayersPendingRemoval().clear();
EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty());
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 933d03d..352000e 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -239,7 +239,7 @@
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
ASSERT_TRUE(hwcDisplayId);
- mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId);
+ mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId, std::nullopt);
DisplayModePtr activeMode = DisplayMode::Builder(Case::Display::HWC_ACTIVE_CONFIG_ID)
.setResolution(Case::Display::RESOLUTION)
.setVsyncPeriod(DEFAULT_VSYNC_PERIOD)
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index aa9af5d..725354b 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -335,13 +335,6 @@
return mFlinger->mLegacyLayers[layerId]->findOutputLayerForDisplay(display.get());
}
- static void setLayerSidebandStream(const sp<Layer>& layer,
- const sp<NativeHandle>& sidebandStream) {
- layer->mDrawingState.sidebandStream = sidebandStream;
- layer->mSidebandStream = sidebandStream;
- layer->editLayerSnapshot()->sidebandStream = sidebandStream;
- }
-
void setLayerCompositionType(const sp<Layer>& layer,
aidl::android::hardware::graphics::composer3::Composition type) {
auto outputLayer = findOutputLayerForDisplay(static_cast<uint32_t>(layer->sequence),
@@ -352,10 +345,6 @@
(*state.hwc).hwcCompositionType = type;
}
- static void setLayerDrawingParent(const sp<Layer>& layer, const sp<Layer>& drawingParent) {
- layer->mDrawingParent = drawingParent;
- }
-
/* ------------------------------------------------------------------------
* Forwarding for functions being tested
*/
@@ -548,7 +537,7 @@
}
auto flushTransactionQueues() {
- return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId));
+ return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues());
}
auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
@@ -722,7 +711,6 @@
}
auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; }
- auto& mutableLayersPendingRemoval() { return mFlinger->mLayersPendingRemoval; }
auto& mutableLayerSnapshotBuilder() { return mFlinger->mLayerSnapshotBuilder; };
auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); }
@@ -790,7 +778,6 @@
mutableDisplays().clear();
mutableCurrentState().displays.clear();
mutableDrawingState().displays.clear();
- mFlinger->mLayersPendingRemoval.clear();
mFlinger->mScheduler.reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mRenderEngine = std::unique_ptr<renderengine::RenderEngine>();
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 7bf1674..f8f08c7 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -20,6 +20,7 @@
#include <gui/SurfaceComposerClient.h>
#include <cstdint>
#include "Client.h"
+#include "Layer.h"
#include <layerproto/LayerProtoHeader.h>
#include "FrontEnd/LayerCreationArgs.h"
diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
index 9f6065b..e27af0e 100644
--- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
@@ -128,12 +128,10 @@
NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
false);
layer->setSidebandStream(stream, FrameTimelineInfo{}, 20, gui::GameMode::Unsupported);
- mFlinger.mutableCurrentState().layersSortedByZ.add(layer);
mTunnelModeEnabledReporter->updateTunnelModeStatus();
mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener);
EXPECT_EQ(true, mTunnelModeEnabledListener->mTunnelModeEnabled);
mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener);
- mFlinger.mutableCurrentState().layersSortedByZ.remove(layer);
layer = nullptr;
mTunnelModeEnabledReporter->updateTunnelModeStatus();
@@ -154,12 +152,9 @@
layerWithSidebandStream->setSidebandStream(stream, FrameTimelineInfo{}, 20,
gui::GameMode::Unsupported);
- mFlinger.mutableCurrentState().layersSortedByZ.add(simpleLayer);
- mFlinger.mutableCurrentState().layersSortedByZ.add(layerWithSidebandStream);
mTunnelModeEnabledReporter->updateTunnelModeStatus();
EXPECT_EQ(true, mTunnelModeEnabledListener->mTunnelModeEnabled);
- mFlinger.mutableCurrentState().layersSortedByZ.remove(layerWithSidebandStream);
layerWithSidebandStream = nullptr;
mTunnelModeEnabledReporter->updateTunnelModeStatus();
EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled);
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 7c678bd..918107d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -915,7 +915,8 @@
vrrTracker.onFrameBegin(TimePoint::fromNs(7000),
{TimePoint::fromNs(6500), TimePoint::fromNs(6500)});
- EXPECT_EQ(10500, vrrTracker.nextAnticipatedVSyncTimeFrom(9000, 7000));
+ EXPECT_EQ(8500, vrrTracker.nextAnticipatedVSyncTimeFrom(8000, 7000));
+ EXPECT_EQ(9500, vrrTracker.nextAnticipatedVSyncTimeFrom(9000, 7000));
}
TEST_F(VSyncPredictorTest, adjustsVrrTimelineTwoClients) {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index e380e19..f472d8f 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -180,8 +180,12 @@
MOCK_METHOD1(onHotplugDisconnect, void(Display));
MOCK_METHOD(Error, setRefreshRateChangedCallbackDebugEnabled, (Display, bool));
MOCK_METHOD(Error, notifyExpectedPresent, (Display, nsecs_t, int32_t));
- MOCK_METHOD(Error, getDisplayLuts,
- (Display, std::vector<aidl::android::hardware::graphics::composer3::Lut>*));
+ MOCK_METHOD(
+ Error, getRequestedLuts,
+ (Display,
+ std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*));
+ MOCK_METHOD(Error, setLayerLuts,
+ (Display, Layer, std::vector<aidl::android::hardware::graphics::composer3::Lut>&));
};
} // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 1eda358..5edd2cd 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -35,6 +35,7 @@
(const, override));
MOCK_METHOD(bool, isVsyncPeriodSwitchSupported, (), (const, override));
MOCK_METHOD(void, onLayerDestroyed, (hal::HWLayerId), (override));
+ MOCK_METHOD(std::optional<ui::Size>, getPhysicalSizeInMm, (), (const override));
MOCK_METHOD(hal::Error, acceptChanges, (), (override));
MOCK_METHOD((base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>), createLayer, (),
@@ -109,8 +110,9 @@
MOCK_METHOD(hal::Error, getOverlaySupport,
(aidl::android::hardware::graphics::composer3::OverlayProperties *),
(const override));
- MOCK_METHOD(hal::Error, getDisplayLuts,
- (std::vector<aidl::android::hardware::graphics::composer3::Lut>*), (override));
+ MOCK_METHOD(hal::Error, getRequestedLuts,
+ (std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*),
+ (override));
};
class Layer : public HWC2::Layer {
@@ -145,6 +147,8 @@
(const std::string &, bool, const std::vector<uint8_t> &), (override));
MOCK_METHOD(hal::Error, setBrightness, (float), (override));
MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override));
+ MOCK_METHOD(hal::Error, setLuts,
+ (std::vector<aidl::android::hardware::graphics::composer3::Lut>&), (override));
};
} // namespace android::HWC2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index fdb6f4d..45f86fa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -31,15 +31,11 @@
explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
- MOCK_CONST_METHOD0(getType, const char*());
MOCK_METHOD0(getFrameSelectionPriority, int32_t());
- MOCK_CONST_METHOD0(isVisible, bool());
MOCK_METHOD0(createClone, sp<Layer>());
MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, scheduler::FrameRateCompatibility());
MOCK_CONST_METHOD0(getOwnerUid, uid_t());
- MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace());
- MOCK_METHOD(bool, isFrontBuffered, (), (const, override));
};
} // namespace android::mock
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 3d8124b..4ac1618 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -96,6 +96,17 @@
if (mInfoCache.mMaxAmplitudes.isFailed()) {
mInfoCache.mMaxAmplitudes = getMaxAmplitudesInternal();
}
+ if (mInfoCache.mMaxEnvelopeEffectSize.isFailed()) {
+ mInfoCache.mMaxEnvelopeEffectSize = getMaxEnvelopeEffectSizeInternal();
+ }
+ if (mInfoCache.mMinEnvelopeEffectControlPointDuration.isFailed()) {
+ mInfoCache.mMinEnvelopeEffectControlPointDuration =
+ getMinEnvelopeEffectControlPointDurationInternal();
+ }
+ if (mInfoCache.mMaxEnvelopeEffectControlPointDuration.isFailed()) {
+ mInfoCache.mMaxEnvelopeEffectControlPointDuration =
+ getMaxEnvelopeEffectControlPointDurationInternal();
+ }
return mInfoCache.get();
}
@@ -210,6 +221,23 @@
ALOGV("Skipped getMaxAmplitudes because it's not available in Vibrator HAL");
return HalResult<std::vector<float>>::unsupported();
}
+HalResult<int32_t> HalWrapper::getMaxEnvelopeEffectSizeInternal() {
+ ALOGV("Skipped getMaxEnvelopeEffectSizeInternal because it's not available "
+ "in Vibrator HAL");
+ return HalResult<int32_t>::unsupported();
+}
+
+HalResult<milliseconds> HalWrapper::getMinEnvelopeEffectControlPointDurationInternal() {
+ ALOGV("Skipped getMinEnvelopeEffectControlPointDurationInternal because it's not "
+ "available in Vibrator HAL");
+ return HalResult<milliseconds>::unsupported();
+}
+
+HalResult<milliseconds> HalWrapper::getMaxEnvelopeEffectControlPointDurationInternal() {
+ ALOGV("Skipped getMaxEnvelopeEffectControlPointDurationInternal because it's not "
+ "available in Vibrator HAL");
+ return HalResult<milliseconds>::unsupported();
+}
// -------------------------------------------------------------------------------------------------
@@ -441,6 +469,24 @@
return HalResultFactory::fromStatus<std::vector<float>>(std::move(status), amplitudes);
}
+HalResult<int32_t> AidlHalWrapper::getMaxEnvelopeEffectSizeInternal() {
+ int32_t size = 0;
+ auto status = getHal()->getPwleV2CompositionSizeMax(&size);
+ return HalResultFactory::fromStatus<int32_t>(std::move(status), size);
+}
+
+HalResult<milliseconds> AidlHalWrapper::getMinEnvelopeEffectControlPointDurationInternal() {
+ int32_t durationMs = 0;
+ auto status = getHal()->getPwleV2PrimitiveDurationMinMillis(&durationMs);
+ return HalResultFactory::fromStatus<milliseconds>(std::move(status), milliseconds(durationMs));
+}
+
+HalResult<milliseconds> AidlHalWrapper::getMaxEnvelopeEffectControlPointDurationInternal() {
+ int32_t durationMs = 0;
+ auto status = getHal()->getPwleV2PrimitiveDurationMaxMillis(&durationMs);
+ return HalResultFactory::fromStatus<milliseconds>(std::move(status), milliseconds(durationMs));
+}
+
std::shared_ptr<Aidl::IVibrator> AidlHalWrapper::getHal() {
std::lock_guard<std::mutex> lock(mHandleMutex);
return mHandle;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index ae0d9ab..4938b15 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -258,6 +258,9 @@
const HalResult<float> frequencyResolution;
const HalResult<float> qFactor;
const HalResult<std::vector<float>> maxAmplitudes;
+ const HalResult<int32_t> maxEnvelopeEffectSize;
+ const HalResult<std::chrono::milliseconds> minEnvelopeEffectControlPointDuration;
+ const HalResult<std::chrono::milliseconds> maxEnvelopeEffectControlPointDuration;
void logFailures() const {
logFailure<Capabilities>(capabilities, "getCapabilities");
@@ -276,6 +279,11 @@
logFailure<float>(frequencyResolution, "getFrequencyResolution");
logFailure<float>(qFactor, "getQFactor");
logFailure<std::vector<float>>(maxAmplitudes, "getMaxAmplitudes");
+ logFailure<int32_t>(maxEnvelopeEffectSize, "getMaxEnvelopeEffectSize");
+ logFailure<std::chrono::milliseconds>(minEnvelopeEffectControlPointDuration,
+ "getMinEnvelopeEffectControlPointDuration");
+ logFailure<std::chrono::milliseconds>(maxEnvelopeEffectControlPointDuration,
+ "getMaxEnvelopeEffectControlPointDuration");
}
bool shouldRetry() const {
@@ -285,7 +293,10 @@
pwlePrimitiveDurationMax.shouldRetry() || compositionSizeMax.shouldRetry() ||
pwleSizeMax.shouldRetry() || minFrequency.shouldRetry() ||
resonantFrequency.shouldRetry() || frequencyResolution.shouldRetry() ||
- qFactor.shouldRetry() || maxAmplitudes.shouldRetry();
+ qFactor.shouldRetry() || maxAmplitudes.shouldRetry() ||
+ maxEnvelopeEffectSize.shouldRetry() ||
+ minEnvelopeEffectControlPointDuration.shouldRetry() ||
+ maxEnvelopeEffectControlPointDuration.shouldRetry();
}
private:
@@ -313,7 +324,10 @@
mResonantFrequency,
mFrequencyResolution,
mQFactor,
- mMaxAmplitudes};
+ mMaxAmplitudes,
+ mMaxEnvelopeEffectSize,
+ mMinEnvelopeEffectControlPointDuration,
+ mMaxEnvelopeEffectControlPointDuration};
}
private:
@@ -340,6 +354,11 @@
HalResult<float> mQFactor = HalResult<float>::transactionFailed(MSG);
HalResult<std::vector<float>> mMaxAmplitudes =
HalResult<std::vector<float>>::transactionFailed(MSG);
+ HalResult<int32_t> mMaxEnvelopeEffectSize = HalResult<int>::transactionFailed(MSG);
+ HalResult<std::chrono::milliseconds> mMinEnvelopeEffectControlPointDuration =
+ HalResult<std::chrono::milliseconds>::transactionFailed(MSG);
+ HalResult<std::chrono::milliseconds> mMaxEnvelopeEffectControlPointDuration =
+ HalResult<std::chrono::milliseconds>::transactionFailed(MSG);
friend class HalWrapper;
};
@@ -420,6 +439,9 @@
virtual HalResult<float> getFrequencyResolutionInternal();
virtual HalResult<float> getQFactorInternal();
virtual HalResult<std::vector<float>> getMaxAmplitudesInternal();
+ virtual HalResult<int32_t> getMaxEnvelopeEffectSizeInternal();
+ virtual HalResult<std::chrono::milliseconds> getMinEnvelopeEffectControlPointDurationInternal();
+ virtual HalResult<std::chrono::milliseconds> getMaxEnvelopeEffectControlPointDurationInternal();
private:
std::mutex mInfoMutex;
@@ -495,6 +517,13 @@
HalResult<float> getFrequencyResolutionInternal() override final;
HalResult<float> getQFactorInternal() override final;
HalResult<std::vector<float>> getMaxAmplitudesInternal() override final;
+ HalResult<int32_t> getMaxEnvelopeEffectSizeInternal() override final;
+
+ HalResult<std::chrono::milliseconds> getMinEnvelopeEffectControlPointDurationInternal()
+ override final;
+
+ HalResult<std::chrono::milliseconds> getMaxEnvelopeEffectControlPointDurationInternal()
+ override final;
private:
const reconnect_fn mReconnectFn;
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index ba7e1f0..17f384d 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -235,6 +235,9 @@
constexpr int32_t PWLE_SIZE_MAX = 20;
constexpr int32_t PRIMITIVE_DELAY_MAX = 100;
constexpr int32_t PWLE_DURATION_MAX = 200;
+ constexpr int32_t PWLE_V2_COMPOSITION_SIZE_MAX = 16;
+ constexpr int32_t PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20;
+ constexpr int32_t PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000;
std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK};
std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::CLICK};
std::vector<Braking> supportedBraking = {Braking::CLAB};
@@ -305,6 +308,21 @@
.Times(Exactly(2))
.WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY)))
.WillOnce(DoAll(SetArgPointee<0>(amplitudes), Return(ndk::ScopedAStatus::ok())));
+ EXPECT_CALL(*mMockHal.get(), getPwleV2CompositionSizeMax(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY)))
+ .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_COMPOSITION_SIZE_MAX),
+ Return(ndk::ScopedAStatus::ok())));
+ EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMinMillis(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY)))
+ .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS),
+ Return(ndk::ScopedAStatus::ok())));
+ EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMaxMillis(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY)))
+ .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS),
+ Return(ndk::ScopedAStatus::ok())));
vibrator::Info failed = mWrapper->getInfo();
ASSERT_TRUE(failed.capabilities.isFailed());
@@ -321,6 +339,9 @@
ASSERT_TRUE(failed.frequencyResolution.isFailed());
ASSERT_TRUE(failed.qFactor.isFailed());
ASSERT_TRUE(failed.maxAmplitudes.isFailed());
+ ASSERT_TRUE(failed.maxEnvelopeEffectSize.isFailed());
+ ASSERT_TRUE(failed.minEnvelopeEffectControlPointDuration.isFailed());
+ ASSERT_TRUE(failed.maxEnvelopeEffectControlPointDuration.isFailed());
vibrator::Info successful = mWrapper->getInfo();
ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, successful.capabilities.value());
@@ -338,6 +359,11 @@
ASSERT_EQ(F_RESOLUTION, successful.frequencyResolution.value());
ASSERT_EQ(Q_FACTOR, successful.qFactor.value());
ASSERT_EQ(amplitudes, successful.maxAmplitudes.value());
+ ASSERT_EQ(PWLE_V2_COMPOSITION_SIZE_MAX, successful.maxEnvelopeEffectSize.value());
+ ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS),
+ successful.minEnvelopeEffectControlPointDuration.value());
+ ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS),
+ successful.maxEnvelopeEffectControlPointDuration.value());
}
TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) {
@@ -347,6 +373,9 @@
constexpr int32_t PWLE_SIZE_MAX = 20;
constexpr int32_t PRIMITIVE_DELAY_MAX = 100;
constexpr int32_t PWLE_DURATION_MAX = 200;
+ constexpr int32_t PWLE_V2_COMPOSITION_SIZE_MAX = 16;
+ constexpr int32_t PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20;
+ constexpr int32_t PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000;
std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK};
EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
@@ -391,6 +420,18 @@
EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_))
.Times(Exactly(1))
.WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), getPwleV2CompositionSizeMax(_))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_COMPOSITION_SIZE_MAX),
+ Return(ndk::ScopedAStatus::ok())));
+ EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMinMillis(_))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS),
+ Return(ndk::ScopedAStatus::ok())));
+ EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMaxMillis(_))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS),
+ Return(ndk::ScopedAStatus::ok())));
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
@@ -414,6 +455,11 @@
ASSERT_TRUE(info.frequencyResolution.isUnsupported());
ASSERT_TRUE(info.qFactor.isUnsupported());
ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
+ ASSERT_EQ(PWLE_V2_COMPOSITION_SIZE_MAX, info.maxEnvelopeEffectSize.value());
+ ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS),
+ info.minEnvelopeEffectControlPointDuration.value());
+ ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS),
+ info.maxEnvelopeEffectControlPointDuration.value());
}
TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) {
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index 83430d7..a09ddec 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -220,6 +220,9 @@
ASSERT_TRUE(info.frequencyResolution.isUnsupported());
ASSERT_TRUE(info.qFactor.isUnsupported());
ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
+ ASSERT_TRUE(info.maxEnvelopeEffectSize.isUnsupported());
+ ASSERT_TRUE(info.minEnvelopeEffectControlPointDuration.isUnsupported());
+ ASSERT_TRUE(info.maxEnvelopeEffectControlPointDuration.isUnsupported());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoWithoutAmplitudeControl) {
@@ -253,6 +256,9 @@
ASSERT_TRUE(info.frequencyResolution.isUnsupported());
ASSERT_TRUE(info.qFactor.isUnsupported());
ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
+ ASSERT_TRUE(info.maxEnvelopeEffectSize.isUnsupported());
+ ASSERT_TRUE(info.minEnvelopeEffectControlPointDuration.isUnsupported());
+ ASSERT_TRUE(info.maxEnvelopeEffectControlPointDuration.isUnsupported());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffect) {
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 436e6c6..879d2d0 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -27,9 +27,18 @@
symbol_file: "libvulkan.map.txt",
first_version: "24",
unversioned_until: "current",
- export_header_libs: [
- "ndk_vulkan_headers",
- ],
+}
+
+aconfig_declarations {
+ name: "libvulkan_flags",
+ package: "com.android.graphics.libvulkan.flags",
+ container: "system",
+ srcs: ["libvulkan_flags.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "libvulkanflags",
+ aconfig_declarations: "libvulkan_flags",
}
cc_library_shared {
@@ -113,5 +122,8 @@
"android.hardware.graphics.common@1.0",
"libSurfaceFlingerProp",
],
- static_libs: ["libgrallocusage"],
+ static_libs: [
+ "libgrallocusage",
+ "libvulkanflags",
+ ],
}
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index a3fe33e..9ff0b46 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -25,6 +25,9 @@
#undef VK_NO_PROTOTYPES
#include "api.h"
+/*
+ * This file is autogenerated by api_generator.py. Do not edit directly.
+ */
namespace vulkan {
namespace api {
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 4998018..b468a89 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -25,6 +25,9 @@
#include "driver_gen.h"
+/*
+ * This file is autogenerated by api_generator.py. Do not edit directly.
+ */
namespace vulkan {
namespace api {
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index ef213f0..01436db 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -41,10 +41,12 @@
#include <new>
#include <vector>
+#include <com_android_graphics_libvulkan_flags.h>
#include "stubhal.h"
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+using namespace com::android::graphics::libvulkan;
extern "C" android_namespace_t* android_get_exported_namespace(const char*);
@@ -688,6 +690,7 @@
case ProcHook::KHR_incremental_present:
case ProcHook::KHR_shared_presentable_image:
case ProcHook::KHR_swapchain:
+ case ProcHook::KHR_swapchain_mutable_format:
case ProcHook::EXT_hdr_metadata:
case ProcHook::EXT_swapchain_maintenance1:
case ProcHook::ANDROID_external_memory_android_hardware_buffer:
@@ -740,6 +743,7 @@
break;
case ProcHook::ANDROID_external_memory_android_hardware_buffer:
case ProcHook::KHR_external_fence_fd:
+ case ProcHook::KHR_swapchain_mutable_format:
case ProcHook::EXTENSION_UNKNOWN:
// Extensions we don't need to do anything about at this level
break;
@@ -1251,6 +1255,15 @@
VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION});
}
+ VkPhysicalDeviceProperties pDeviceProperties;
+ data.driver.GetPhysicalDeviceProperties(physicalDevice, &pDeviceProperties);
+ if (flags::swapchain_mutable_format_ext() &&
+ pDeviceProperties.apiVersion >= VK_API_VERSION_1_2) {
+ loader_extensions.push_back(
+ {VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
+ VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION});
+ }
+
// enumerate our extensions first
if (!pLayerName && pProperties) {
uint32_t count = std::min(
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 8f09008..f741977 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -26,6 +26,9 @@
namespace vulkan {
namespace driver {
+/*
+ * This file is autogenerated by driver_generator.py. Do not edit directly.
+ */
namespace {
// clang-format off
@@ -613,6 +616,7 @@
if (strcmp(name, "VK_KHR_external_semaphore_capabilities") == 0) return ProcHook::KHR_external_semaphore_capabilities;
if (strcmp(name, "VK_KHR_external_fence_capabilities") == 0) return ProcHook::KHR_external_fence_capabilities;
if (strcmp(name, "VK_KHR_external_fence_fd") == 0) return ProcHook::KHR_external_fence_fd;
+ if (strcmp(name, "VK_KHR_swapchain_mutable_format") == 0) return ProcHook::KHR_swapchain_mutable_format;
// clang-format on
return ProcHook::EXTENSION_UNKNOWN;
}
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 4527214..649c0f1 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -26,6 +26,9 @@
#include <optional>
#include <vector>
+/*
+ * This file is autogenerated by driver_generator.py. Do not edit directly.
+ */
namespace vulkan {
namespace driver {
@@ -59,6 +62,7 @@
KHR_external_semaphore_capabilities,
KHR_external_fence_capabilities,
KHR_external_fence_fd,
+ KHR_swapchain_mutable_format,
EXTENSION_CORE_1_0,
EXTENSION_CORE_1_1,
diff --git a/vulkan/libvulkan/libvulkan_flags.aconfig b/vulkan/libvulkan/libvulkan_flags.aconfig
new file mode 100644
index 0000000..891bc02
--- /dev/null
+++ b/vulkan/libvulkan/libvulkan_flags.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.graphics.libvulkan.flags"
+container: "system"
+
+flag {
+ name: "swapchain_mutable_format_ext"
+ namespace: "core_graphics"
+ description: "Enable the VK_KHR_swapchain_mutable_format vulkan extension"
+ bug: "341978292"
+ is_fixed_read_only: true
+}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 00e987f..09b0a14 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1215,8 +1215,15 @@
surfaceCompressionProps
->imageCompressionFixedRateFlags =
compressionProps.imageCompressionFixedRateFlags;
- } else {
+ } else if (compressionRes ==
+ VK_ERROR_OUT_OF_HOST_MEMORY ||
+ compressionRes ==
+ VK_ERROR_OUT_OF_DEVICE_MEMORY) {
return compressionRes;
+ } else {
+ // For any of the *_NOT_SUPPORTED errors we continue
+ // onto the next format
+ continue;
}
}
} break;
@@ -1465,6 +1472,12 @@
.flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
};
+ // If supporting mutable format swapchain add the mutable format flag
+ if (create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
+ image_format_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+ image_format_info.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR;
+ }
+
VkAndroidHardwareBufferUsageANDROID ahb_usage;
ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
ahb_usage.pNext = nullptr;
@@ -1883,6 +1896,11 @@
num_images = 1;
}
+ VkImageFormatListCreateInfo extra_mutable_formats = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
+ };
+ VkImageFormatListCreateInfo* extra_mutable_formats_ptr;
+
// Look through the create_info pNext chain passed to createSwapchainKHR
// for an image compression control struct.
// if one is found AND the appropriate extensions are enabled, create a
@@ -1901,7 +1919,29 @@
image_compression.pNext = nullptr;
usage_info_pNext = &image_compression;
} break;
-
+ case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: {
+ const VkImageFormatListCreateInfo* format_list =
+ reinterpret_cast<const VkImageFormatListCreateInfo*>(
+ create_infos);
+ if (create_info->flags &
+ VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
+ if (format_list && format_list->viewFormatCount > 0 &&
+ format_list->pViewFormats) {
+ extra_mutable_formats.viewFormatCount =
+ format_list->viewFormatCount;
+ extra_mutable_formats.pViewFormats =
+ format_list->pViewFormats;
+ extra_mutable_formats_ptr = &extra_mutable_formats;
+ } else {
+ ALOGE(
+ "vk_swapchain_create_mutable_format_bit_khr was "
+ "set during swapchain creation but no valid "
+ "vkimageformatlistcreateinfo was found in the "
+ "pnext chain");
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ }
+ } break;
default:
// Ignore all other info structs
break;
@@ -1997,6 +2037,11 @@
.pQueueFamilyIndices = create_info->pQueueFamilyIndices,
};
+ if (create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
+ image_create.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+ image_create.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR;
+ }
+
// Note: don't do deferred allocation for shared present modes. There's only one buffer
// involved so very little benefit.
if ((create_info->flags & VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT) &&
@@ -2006,7 +2051,7 @@
// AcquireNextImage.
VkImageSwapchainCreateInfoKHR image_swapchain_create = {
.sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
- .pNext = nullptr,
+ .pNext = extra_mutable_formats_ptr,
.swapchain = HandleFromSwapchain(swapchain),
};
image_create.pNext = &image_swapchain_create;
@@ -2058,6 +2103,11 @@
ANativeWindowBuffer_getHardwareBuffer(img.buffer.get());
image_create.pNext = &image_native_buffer;
+ if (extra_mutable_formats_ptr) {
+ extra_mutable_formats_ptr->pNext = image_create.pNext;
+ image_create.pNext = extra_mutable_formats_ptr;
+ }
+
ATRACE_BEGIN("CreateImage");
result =
dispatch.CreateImage(device, &image_create, nullptr, &img.image);
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index d34851e..40a45af 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -24,6 +24,9 @@
using namespace null_driver;
+/*
+ * This file is autogenerated by null_generator.py. Do not edit directly.
+ */
namespace {
struct NameProc {
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index fb3bd05..0d1e223 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -22,6 +22,9 @@
#include <vulkan/vk_android_native_buffer.h>
#include <vulkan/vulkan.h>
+/*
+ * This file is autogenerated by null_generator.py. Do not edit directly.
+ */
namespace null_driver {
PFN_vkVoidFunction GetGlobalProcAddr(const char* name);
diff --git a/vulkan/scripts/api_generator.py b/vulkan/scripts/api_generator.py
index be24172..001af20 100644
--- a/vulkan/scripts/api_generator.py
+++ b/vulkan/scripts/api_generator.py
@@ -61,6 +61,9 @@
#include "driver_gen.h"
+/*
+ * This file is autogenerated by api_generator.py. Do not edit directly.
+ */
namespace vulkan {
namespace api {
@@ -283,6 +286,9 @@
#undef VK_NO_PROTOTYPES
#include "api.h"
+/*
+ * This file is autogenerated by api_generator.py. Do not edit directly.
+ */
namespace vulkan {
namespace api {
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
index 48c0ae9..6159599 100644
--- a/vulkan/scripts/driver_generator.py
+++ b/vulkan/scripts/driver_generator.py
@@ -49,6 +49,7 @@
'VK_KHR_external_semaphore_capabilities',
'VK_KHR_external_fence_capabilities',
'VK_KHR_external_fence_fd',
+ 'VK_KHR_swapchain_mutable_format',
]
# Functions needed at vulkan::driver level.
@@ -224,6 +225,9 @@
#include <optional>
#include <vector>
+/*
+ * This file is autogenerated by driver_generator.py. Do not edit directly.
+ */
namespace vulkan {
namespace driver {
@@ -503,6 +507,9 @@
namespace vulkan {
namespace driver {
+/*
+ * This file is autogenerated by driver_generator.py. Do not edit directly.
+ */
namespace {
// clang-format off\n\n""")
diff --git a/vulkan/scripts/null_generator.py b/vulkan/scripts/null_generator.py
index 3624c1d..5c5bea3 100644
--- a/vulkan/scripts/null_generator.py
+++ b/vulkan/scripts/null_generator.py
@@ -55,6 +55,9 @@
#include <vulkan/vk_android_native_buffer.h>
#include <vulkan/vulkan.h>
+/*
+ * This file is autogenerated by null_generator.py. Do not edit directly.
+ */
namespace null_driver {
PFN_vkVoidFunction GetGlobalProcAddr(const char* name);
@@ -97,6 +100,9 @@
using namespace null_driver;
+/*
+ * This file is autogenerated by null_generator.py. Do not edit directly.
+ */
namespace {
struct NameProc {