diff options
578 files changed, 5166 insertions, 4596 deletions
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc index fa7be1816a..041ffe1c10 100644 --- a/cmds/atrace/atrace_userdebug.rc +++ b/cmds/atrace/atrace_userdebug.rc @@ -24,3 +24,7 @@ on post-fs 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 28bd7932a2..b7ad33144b 100644 --- a/cmds/installd/otapreopt_script.sh +++ b/cmds/installd/otapreopt_script.sh @@ -50,6 +50,37 @@ else 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 Binary files differnew file mode 100644 index 0000000000..a09fc84fc5 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-0 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-1 b/cmds/installd/tests/corpus/seed-2024-08-29-1 Binary files differnew file mode 100644 index 0000000000..c96616aa29 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-1 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-10 b/cmds/installd/tests/corpus/seed-2024-08-29-10 Binary files differnew file mode 100644 index 0000000000..0b21bd157d --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-10 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-100 b/cmds/installd/tests/corpus/seed-2024-08-29-100 Binary files differnew file mode 100644 index 0000000000..225d123966 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-100 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-101 b/cmds/installd/tests/corpus/seed-2024-08-29-101 Binary files differnew file mode 100644 index 0000000000..c507b576cc --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-101 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-102 b/cmds/installd/tests/corpus/seed-2024-08-29-102 Binary files differnew file mode 100644 index 0000000000..e75ef89ad3 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-102 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-103 b/cmds/installd/tests/corpus/seed-2024-08-29-103 Binary files differnew file mode 100644 index 0000000000..fb28f4d712 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-103 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-104 b/cmds/installd/tests/corpus/seed-2024-08-29-104 Binary files differnew file mode 100644 index 0000000000..b5a22222e0 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-104 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-105 b/cmds/installd/tests/corpus/seed-2024-08-29-105 Binary files differnew file mode 100644 index 0000000000..a126c0eb6a --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-105 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-106 b/cmds/installd/tests/corpus/seed-2024-08-29-106 Binary files differnew file mode 100644 index 0000000000..ad84e5788e --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-106 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-107 b/cmds/installd/tests/corpus/seed-2024-08-29-107 Binary files differnew file mode 100644 index 0000000000..6a2bc6f35a --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-107 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-108 b/cmds/installd/tests/corpus/seed-2024-08-29-108 Binary files differnew file mode 100644 index 0000000000..578b55ad17 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-108 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-109 b/cmds/installd/tests/corpus/seed-2024-08-29-109 Binary files differnew file mode 100644 index 0000000000..44f853d014 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-109 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-11 b/cmds/installd/tests/corpus/seed-2024-08-29-11 Binary files differnew file mode 100644 index 0000000000..28fd841c63 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-11 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-110 b/cmds/installd/tests/corpus/seed-2024-08-29-110 Binary files differnew file mode 100644 index 0000000000..a013ee8997 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-110 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-111 b/cmds/installd/tests/corpus/seed-2024-08-29-111 Binary files differnew file mode 100644 index 0000000000..1bb6185965 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-111 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-112 b/cmds/installd/tests/corpus/seed-2024-08-29-112 Binary files differnew file mode 100644 index 0000000000..83008e956d --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-112 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-113 b/cmds/installd/tests/corpus/seed-2024-08-29-113 Binary files differnew file mode 100644 index 0000000000..c9460cbbc6 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-113 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-114 b/cmds/installd/tests/corpus/seed-2024-08-29-114 Binary files differnew file mode 100644 index 0000000000..feb0384a92 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-114 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-115 b/cmds/installd/tests/corpus/seed-2024-08-29-115 Binary files differnew file mode 100644 index 0000000000..cd28076566 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-115 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-116 b/cmds/installd/tests/corpus/seed-2024-08-29-116 Binary files differnew file mode 100644 index 0000000000..c48730ee76 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-116 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-117 b/cmds/installd/tests/corpus/seed-2024-08-29-117 Binary files differnew file mode 100644 index 0000000000..bde1be0c10 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-117 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-118 b/cmds/installd/tests/corpus/seed-2024-08-29-118 Binary files differnew file mode 100644 index 0000000000..0d86d18c97 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-118 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-119 b/cmds/installd/tests/corpus/seed-2024-08-29-119 Binary files differnew file mode 100644 index 0000000000..de358941fe --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-119 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-12 b/cmds/installd/tests/corpus/seed-2024-08-29-12 Binary files differnew file mode 100644 index 0000000000..5565f811bb --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-12 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-120 b/cmds/installd/tests/corpus/seed-2024-08-29-120 Binary files differnew file mode 100644 index 0000000000..51c05261f9 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-120 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-121 b/cmds/installd/tests/corpus/seed-2024-08-29-121 Binary files differnew file mode 100644 index 0000000000..2d84c76377 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-121 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-122 b/cmds/installd/tests/corpus/seed-2024-08-29-122 Binary files differnew file mode 100644 index 0000000000..f25a7c48e4 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-122 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-123 b/cmds/installd/tests/corpus/seed-2024-08-29-123 Binary files differnew file mode 100644 index 0000000000..fe8eb342bf --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-123 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-124 b/cmds/installd/tests/corpus/seed-2024-08-29-124 Binary files differnew file mode 100644 index 0000000000..170e8ec1a2 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-124 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-125 b/cmds/installd/tests/corpus/seed-2024-08-29-125 Binary files differnew file mode 100644 index 0000000000..24e8bb8b72 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-125 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-126 b/cmds/installd/tests/corpus/seed-2024-08-29-126 Binary files differnew file mode 100644 index 0000000000..92536a3515 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-126 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-127 b/cmds/installd/tests/corpus/seed-2024-08-29-127 Binary files differnew file mode 100644 index 0000000000..3a5436a0e7 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-127 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-128 b/cmds/installd/tests/corpus/seed-2024-08-29-128 Binary files differnew file mode 100644 index 0000000000..93d131da9e --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-128 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-129 b/cmds/installd/tests/corpus/seed-2024-08-29-129 Binary files differnew file mode 100644 index 0000000000..842dae41c3 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-129 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-13 b/cmds/installd/tests/corpus/seed-2024-08-29-13 Binary files differnew file mode 100644 index 0000000000..bc0ec3d94f --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-13 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-130 b/cmds/installd/tests/corpus/seed-2024-08-29-130 Binary files differnew file mode 100644 index 0000000000..9b6ed59902 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-130 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-131 b/cmds/installd/tests/corpus/seed-2024-08-29-131 Binary files differnew file mode 100644 index 0000000000..82a5d2f34f --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-131 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-132 b/cmds/installd/tests/corpus/seed-2024-08-29-132 Binary files differnew file mode 100644 index 0000000000..445fdc5880 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-132 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-133 b/cmds/installd/tests/corpus/seed-2024-08-29-133 Binary files differnew file mode 100644 index 0000000000..0a6e9caac7 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-133 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-134 b/cmds/installd/tests/corpus/seed-2024-08-29-134 Binary files differnew file mode 100644 index 0000000000..a359603e95 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-134 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-135 b/cmds/installd/tests/corpus/seed-2024-08-29-135 Binary files differnew file mode 100644 index 0000000000..c16b303dba --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-135 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-136 b/cmds/installd/tests/corpus/seed-2024-08-29-136 Binary files differnew file mode 100644 index 0000000000..f7a360ffb9 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-136 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-137 b/cmds/installd/tests/corpus/seed-2024-08-29-137 Binary files differnew file mode 100644 index 0000000000..38a113486b --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-137 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-138 b/cmds/installd/tests/corpus/seed-2024-08-29-138 Binary files differnew file mode 100644 index 0000000000..b9db4a7d09 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-138 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-139 b/cmds/installd/tests/corpus/seed-2024-08-29-139 Binary files differnew file mode 100644 index 0000000000..eb1cf938f3 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-139 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-14 b/cmds/installd/tests/corpus/seed-2024-08-29-14 Binary files differnew file mode 100644 index 0000000000..74f9ad0440 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-14 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-140 b/cmds/installd/tests/corpus/seed-2024-08-29-140 Binary files differnew file mode 100644 index 0000000000..0cf217c041 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-140 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-141 b/cmds/installd/tests/corpus/seed-2024-08-29-141 Binary files differnew file mode 100644 index 0000000000..82763f0b3c --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-141 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-142 b/cmds/installd/tests/corpus/seed-2024-08-29-142 Binary files differnew file mode 100644 index 0000000000..fa1d65665f --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-142 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-15 b/cmds/installd/tests/corpus/seed-2024-08-29-15 Binary files differnew file mode 100644 index 0000000000..729c604230 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-15 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-16 b/cmds/installd/tests/corpus/seed-2024-08-29-16 Binary files differnew file mode 100644 index 0000000000..4dc08793c2 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-16 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-17 b/cmds/installd/tests/corpus/seed-2024-08-29-17 Binary files differnew file mode 100644 index 0000000000..ac7ff13e52 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-17 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-18 b/cmds/installd/tests/corpus/seed-2024-08-29-18 Binary files differnew file mode 100644 index 0000000000..2b240f46fb --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-18 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-19 b/cmds/installd/tests/corpus/seed-2024-08-29-19 Binary files differnew file mode 100644 index 0000000000..a0c881b37f --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-19 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-2 b/cmds/installd/tests/corpus/seed-2024-08-29-2 Binary files differnew file mode 100644 index 0000000000..2593acb6e4 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-2 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-20 b/cmds/installd/tests/corpus/seed-2024-08-29-20 Binary files differnew file mode 100644 index 0000000000..c55dc7f245 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-20 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-21 b/cmds/installd/tests/corpus/seed-2024-08-29-21 Binary files differnew file mode 100644 index 0000000000..63d7a1455b --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-21 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-22 b/cmds/installd/tests/corpus/seed-2024-08-29-22 Binary files differnew file mode 100644 index 0000000000..209f426a01 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-22 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-23 b/cmds/installd/tests/corpus/seed-2024-08-29-23 Binary files differnew file mode 100644 index 0000000000..8e1775f382 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-23 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-24 b/cmds/installd/tests/corpus/seed-2024-08-29-24 Binary files differnew file mode 100644 index 0000000000..4c40f3cffa --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-24 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-25 b/cmds/installd/tests/corpus/seed-2024-08-29-25 Binary files differnew file mode 100644 index 0000000000..d006b202f6 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-25 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-26 b/cmds/installd/tests/corpus/seed-2024-08-29-26 Binary files differnew file mode 100644 index 0000000000..26893b0118 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-26 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-27 b/cmds/installd/tests/corpus/seed-2024-08-29-27 Binary files differnew file mode 100644 index 0000000000..ac81138dfa --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-27 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-28 b/cmds/installd/tests/corpus/seed-2024-08-29-28 Binary files differnew file mode 100644 index 0000000000..71f074b7a0 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-28 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-29 b/cmds/installd/tests/corpus/seed-2024-08-29-29 Binary files differnew file mode 100644 index 0000000000..65dbb6dff7 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-29 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-3 b/cmds/installd/tests/corpus/seed-2024-08-29-3 Binary files differnew file mode 100644 index 0000000000..28ab83fbfd --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-3 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-30 b/cmds/installd/tests/corpus/seed-2024-08-29-30 Binary files differnew file mode 100644 index 0000000000..3b96286573 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-30 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-31 b/cmds/installd/tests/corpus/seed-2024-08-29-31 Binary files differnew file mode 100644 index 0000000000..76101b36ec --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-31 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-32 b/cmds/installd/tests/corpus/seed-2024-08-29-32 Binary files differnew file mode 100644 index 0000000000..79a44523e0 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-32 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-33 b/cmds/installd/tests/corpus/seed-2024-08-29-33 Binary files differnew file mode 100644 index 0000000000..e6a1306838 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-33 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-34 b/cmds/installd/tests/corpus/seed-2024-08-29-34 Binary files differnew file mode 100644 index 0000000000..4a7247f888 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-34 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-35 b/cmds/installd/tests/corpus/seed-2024-08-29-35 Binary files differnew file mode 100644 index 0000000000..f420b34fce --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-35 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-36 b/cmds/installd/tests/corpus/seed-2024-08-29-36 Binary files differnew file mode 100644 index 0000000000..83a33acecb --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-36 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-37 b/cmds/installd/tests/corpus/seed-2024-08-29-37 Binary files differnew file mode 100644 index 0000000000..687bf06ea7 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-37 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-38 b/cmds/installd/tests/corpus/seed-2024-08-29-38 Binary files differnew file mode 100644 index 0000000000..40ab0ad591 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-38 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-39 b/cmds/installd/tests/corpus/seed-2024-08-29-39 Binary files differnew file mode 100644 index 0000000000..3e13978d87 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-39 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-4 b/cmds/installd/tests/corpus/seed-2024-08-29-4 Binary files differnew file mode 100644 index 0000000000..8c47ea3f96 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-4 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-40 b/cmds/installd/tests/corpus/seed-2024-08-29-40 Binary files differnew file mode 100644 index 0000000000..f71791862a --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-40 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-41 b/cmds/installd/tests/corpus/seed-2024-08-29-41 Binary files differnew file mode 100644 index 0000000000..d9c51b93d6 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-41 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-42 b/cmds/installd/tests/corpus/seed-2024-08-29-42 Binary files differnew file mode 100644 index 0000000000..d806e5ee39 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-42 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-43 b/cmds/installd/tests/corpus/seed-2024-08-29-43 Binary files differnew file mode 100644 index 0000000000..3bc2708f12 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-43 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-44 b/cmds/installd/tests/corpus/seed-2024-08-29-44 Binary files differnew file mode 100644 index 0000000000..230839af36 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-44 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-45 b/cmds/installd/tests/corpus/seed-2024-08-29-45 Binary files differnew file mode 100644 index 0000000000..40726b9f5d --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-45 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-46 b/cmds/installd/tests/corpus/seed-2024-08-29-46 Binary files differnew file mode 100644 index 0000000000..bf56bd4a47 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-46 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-47 b/cmds/installd/tests/corpus/seed-2024-08-29-47 Binary files differnew file mode 100644 index 0000000000..80cabaf62b --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-47 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-48 b/cmds/installd/tests/corpus/seed-2024-08-29-48 Binary files differnew file mode 100644 index 0000000000..8f2c5f5dd6 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-48 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-49 b/cmds/installd/tests/corpus/seed-2024-08-29-49 Binary files differnew file mode 100644 index 0000000000..f93fbcdfc5 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-49 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-5 b/cmds/installd/tests/corpus/seed-2024-08-29-5 Binary files differnew file mode 100644 index 0000000000..b3f49d1659 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-5 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-50 b/cmds/installd/tests/corpus/seed-2024-08-29-50 Binary files differnew file mode 100644 index 0000000000..68912aeb94 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-50 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-51 b/cmds/installd/tests/corpus/seed-2024-08-29-51 Binary files differnew file mode 100644 index 0000000000..27b315dec6 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-51 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-52 b/cmds/installd/tests/corpus/seed-2024-08-29-52 Binary files differnew file mode 100644 index 0000000000..159eee6ac0 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-52 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-53 b/cmds/installd/tests/corpus/seed-2024-08-29-53 Binary files differnew file mode 100644 index 0000000000..b07cb3c699 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-53 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-54 b/cmds/installd/tests/corpus/seed-2024-08-29-54 Binary files differnew file mode 100644 index 0000000000..a5e7f2cc4d --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-54 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-55 b/cmds/installd/tests/corpus/seed-2024-08-29-55 Binary files differnew file mode 100644 index 0000000000..bd038adc84 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-55 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-56 b/cmds/installd/tests/corpus/seed-2024-08-29-56 Binary files differnew file mode 100644 index 0000000000..8166cb8cb3 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-56 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-57 b/cmds/installd/tests/corpus/seed-2024-08-29-57 Binary files differnew file mode 100644 index 0000000000..fba1e2f35f --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-57 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-58 b/cmds/installd/tests/corpus/seed-2024-08-29-58 Binary files differnew file mode 100644 index 0000000000..f7af8f8e12 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-58 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-59 b/cmds/installd/tests/corpus/seed-2024-08-29-59 Binary files differnew file mode 100644 index 0000000000..2fd68d7c40 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-59 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-6 b/cmds/installd/tests/corpus/seed-2024-08-29-6 Binary files differnew file mode 100644 index 0000000000..9b02a47877 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-6 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-60 b/cmds/installd/tests/corpus/seed-2024-08-29-60 Binary files differnew file mode 100644 index 0000000000..b4c11292ef --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-60 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-61 b/cmds/installd/tests/corpus/seed-2024-08-29-61 Binary files differnew file mode 100644 index 0000000000..46989aa11a --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-61 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-62 b/cmds/installd/tests/corpus/seed-2024-08-29-62 Binary files differnew file mode 100644 index 0000000000..9298d0c33d --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-62 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-63 b/cmds/installd/tests/corpus/seed-2024-08-29-63 Binary files differnew file mode 100644 index 0000000000..326098c31e --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-63 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-64 b/cmds/installd/tests/corpus/seed-2024-08-29-64 Binary files differnew file mode 100644 index 0000000000..61daf4facb --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-64 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-65 b/cmds/installd/tests/corpus/seed-2024-08-29-65 Binary files differnew file mode 100644 index 0000000000..a993900ff5 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-65 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-66 b/cmds/installd/tests/corpus/seed-2024-08-29-66 Binary files differnew file mode 100644 index 0000000000..85e857bae8 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-66 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-67 b/cmds/installd/tests/corpus/seed-2024-08-29-67 Binary files differnew file mode 100644 index 0000000000..b7754838fc --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-67 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-68 b/cmds/installd/tests/corpus/seed-2024-08-29-68 Binary files differnew file mode 100644 index 0000000000..161e7ab41a --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-68 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-69 b/cmds/installd/tests/corpus/seed-2024-08-29-69 Binary files differnew file mode 100644 index 0000000000..6a45dfe0ff --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-69 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-7 b/cmds/installd/tests/corpus/seed-2024-08-29-7 Binary files differnew file mode 100644 index 0000000000..33f61b0fbc --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-7 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-70 b/cmds/installd/tests/corpus/seed-2024-08-29-70 Binary files differnew file mode 100644 index 0000000000..4c16b49151 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-70 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-71 b/cmds/installd/tests/corpus/seed-2024-08-29-71 Binary files differnew file mode 100644 index 0000000000..1534ce12d1 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-71 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-72 b/cmds/installd/tests/corpus/seed-2024-08-29-72 Binary files differnew file mode 100644 index 0000000000..eaa5831917 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-72 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-73 b/cmds/installd/tests/corpus/seed-2024-08-29-73 Binary files differnew file mode 100644 index 0000000000..9df4a75b88 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-73 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-74 b/cmds/installd/tests/corpus/seed-2024-08-29-74 Binary files differnew file mode 100644 index 0000000000..9558ac019d --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-74 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-75 b/cmds/installd/tests/corpus/seed-2024-08-29-75 Binary files differnew file mode 100644 index 0000000000..a399271250 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-75 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-76 b/cmds/installd/tests/corpus/seed-2024-08-29-76 Binary files differnew file mode 100644 index 0000000000..866541d038 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-76 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-77 b/cmds/installd/tests/corpus/seed-2024-08-29-77 Binary files differnew file mode 100644 index 0000000000..e3940d9af6 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-77 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-78 b/cmds/installd/tests/corpus/seed-2024-08-29-78 Binary files differnew file mode 100644 index 0000000000..8122306d16 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-78 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-79 b/cmds/installd/tests/corpus/seed-2024-08-29-79 Binary files differnew file mode 100644 index 0000000000..0f23dfd2f9 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-79 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-8 b/cmds/installd/tests/corpus/seed-2024-08-29-8 Binary files differnew file mode 100644 index 0000000000..7390735a93 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-8 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-80 b/cmds/installd/tests/corpus/seed-2024-08-29-80 Binary files differnew file mode 100644 index 0000000000..e3c36405e7 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-80 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-81 b/cmds/installd/tests/corpus/seed-2024-08-29-81 Binary files differnew file mode 100644 index 0000000000..6c42b9e72f --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-81 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-82 b/cmds/installd/tests/corpus/seed-2024-08-29-82 Binary files differnew file mode 100644 index 0000000000..09184c98d0 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-82 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-83 b/cmds/installd/tests/corpus/seed-2024-08-29-83 Binary files differnew file mode 100644 index 0000000000..734570af84 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-83 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-84 b/cmds/installd/tests/corpus/seed-2024-08-29-84 Binary files differnew file mode 100644 index 0000000000..1a32561b37 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-84 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-85 b/cmds/installd/tests/corpus/seed-2024-08-29-85 Binary files differnew file mode 100644 index 0000000000..5315dfcab3 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-85 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-86 b/cmds/installd/tests/corpus/seed-2024-08-29-86 Binary files differnew file mode 100644 index 0000000000..5f798b9a15 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-86 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-87 b/cmds/installd/tests/corpus/seed-2024-08-29-87 Binary files differnew file mode 100644 index 0000000000..dd1ebe16bb --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-87 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-88 b/cmds/installd/tests/corpus/seed-2024-08-29-88 Binary files differnew file mode 100644 index 0000000000..45cf713628 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-88 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-89 b/cmds/installd/tests/corpus/seed-2024-08-29-89 Binary files differnew file mode 100644 index 0000000000..1053b71f9e --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-89 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-9 b/cmds/installd/tests/corpus/seed-2024-08-29-9 Binary files differnew file mode 100644 index 0000000000..86d511df98 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-9 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-90 b/cmds/installd/tests/corpus/seed-2024-08-29-90 Binary files differnew file mode 100644 index 0000000000..7ce82a08d0 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-90 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-91 b/cmds/installd/tests/corpus/seed-2024-08-29-91 Binary files differnew file mode 100644 index 0000000000..57c43d0803 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-91 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-92 b/cmds/installd/tests/corpus/seed-2024-08-29-92 Binary files differnew file mode 100644 index 0000000000..32a0f3a72c --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-92 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-93 b/cmds/installd/tests/corpus/seed-2024-08-29-93 Binary files differnew file mode 100644 index 0000000000..56dcb66521 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-93 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-94 b/cmds/installd/tests/corpus/seed-2024-08-29-94 Binary files differnew file mode 100644 index 0000000000..17b5a651e1 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-94 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-95 b/cmds/installd/tests/corpus/seed-2024-08-29-95 Binary files differnew file mode 100644 index 0000000000..09630392b0 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-95 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-96 b/cmds/installd/tests/corpus/seed-2024-08-29-96 Binary files differnew file mode 100644 index 0000000000..1c9590579f --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-96 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-97 b/cmds/installd/tests/corpus/seed-2024-08-29-97 Binary files differnew file mode 100644 index 0000000000..518910e7ef --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-97 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-98 b/cmds/installd/tests/corpus/seed-2024-08-29-98 Binary files differnew file mode 100644 index 0000000000..520feb29f2 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-98 diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-99 b/cmds/installd/tests/corpus/seed-2024-08-29-99 Binary files differnew file mode 100644 index 0000000000..c1da923585 --- /dev/null +++ b/cmds/installd/tests/corpus/seed-2024-08-29-99 diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index ee91d80a3b..e89543e46f 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -1449,7 +1449,7 @@ TEST_F(ProfileTest, CopySystemProfileFailWrongProfileName) { 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 910cd630f3..19201b2c89 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -101,6 +101,9 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) { 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 ffc082d5b2..b05c655517 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -1040,25 +1040,30 @@ static int validate_path(const std::string& dir, const std::string& path, int ma 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 Binary files differnew file mode 100644 index 0000000000..fe4942e53c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-0 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-1 b/cmds/servicemanager/corpus/seed-2024-08-29-1 Binary files differnew file mode 100644 index 0000000000..05c8be2f8a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-1 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-10 b/cmds/servicemanager/corpus/seed-2024-08-29-10 Binary files differnew file mode 100644 index 0000000000..427dc45ddd --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-10 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-100 b/cmds/servicemanager/corpus/seed-2024-08-29-100 Binary files differnew file mode 100644 index 0000000000..92584e3ac6 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-100 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-101 b/cmds/servicemanager/corpus/seed-2024-08-29-101 Binary files differnew file mode 100644 index 0000000000..4dd73ac592 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-101 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-102 b/cmds/servicemanager/corpus/seed-2024-08-29-102 Binary files differnew file mode 100644 index 0000000000..30c37a0d0e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-102 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-103 b/cmds/servicemanager/corpus/seed-2024-08-29-103 Binary files differnew file mode 100644 index 0000000000..76ae112ef3 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-103 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-104 b/cmds/servicemanager/corpus/seed-2024-08-29-104 Binary files differnew file mode 100644 index 0000000000..8ca22015ab --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-104 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-105 b/cmds/servicemanager/corpus/seed-2024-08-29-105 Binary files differnew file mode 100644 index 0000000000..987fcc1969 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-105 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-106 b/cmds/servicemanager/corpus/seed-2024-08-29-106 Binary files differnew file mode 100644 index 0000000000..9f09e29cd1 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-106 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-107 b/cmds/servicemanager/corpus/seed-2024-08-29-107 Binary files differnew file mode 100644 index 0000000000..8f9518d1e4 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-107 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-108 b/cmds/servicemanager/corpus/seed-2024-08-29-108 Binary files differnew file mode 100644 index 0000000000..decb38a8be --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-108 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-109 b/cmds/servicemanager/corpus/seed-2024-08-29-109 Binary files differnew file mode 100644 index 0000000000..e3b4426d4e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-109 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-11 b/cmds/servicemanager/corpus/seed-2024-08-29-11 Binary files differnew file mode 100644 index 0000000000..177a1cdedd --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-11 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-110 b/cmds/servicemanager/corpus/seed-2024-08-29-110 Binary files differnew file mode 100644 index 0000000000..35de9ca395 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-110 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-111 b/cmds/servicemanager/corpus/seed-2024-08-29-111 Binary files differnew file mode 100644 index 0000000000..ae6076fc14 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-111 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-112 b/cmds/servicemanager/corpus/seed-2024-08-29-112 Binary files differnew file mode 100644 index 0000000000..3d64f37139 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-112 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-113 b/cmds/servicemanager/corpus/seed-2024-08-29-113 Binary files differnew file mode 100644 index 0000000000..2b14f1d91f --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-113 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-114 b/cmds/servicemanager/corpus/seed-2024-08-29-114 Binary files differnew file mode 100644 index 0000000000..180831f25c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-114 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-115 b/cmds/servicemanager/corpus/seed-2024-08-29-115 Binary files differnew file mode 100644 index 0000000000..71184d205d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-115 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-116 b/cmds/servicemanager/corpus/seed-2024-08-29-116 Binary files differnew file mode 100644 index 0000000000..98c6163e2d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-116 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-117 b/cmds/servicemanager/corpus/seed-2024-08-29-117 Binary files differnew file mode 100644 index 0000000000..e6dd7bbdfb --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-117 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-118 b/cmds/servicemanager/corpus/seed-2024-08-29-118 Binary files differnew file mode 100644 index 0000000000..dd181ae4a4 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-118 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-119 b/cmds/servicemanager/corpus/seed-2024-08-29-119 Binary files differnew file mode 100644 index 0000000000..25de1b262f --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-119 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-12 b/cmds/servicemanager/corpus/seed-2024-08-29-12 Binary files differnew file mode 100644 index 0000000000..1312d2c9be --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-12 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-120 b/cmds/servicemanager/corpus/seed-2024-08-29-120 Binary files differnew file mode 100644 index 0000000000..cef973d8e9 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-120 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-121 b/cmds/servicemanager/corpus/seed-2024-08-29-121 Binary files differnew file mode 100644 index 0000000000..7fd1df2620 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-121 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-122 b/cmds/servicemanager/corpus/seed-2024-08-29-122 Binary files differnew file mode 100644 index 0000000000..5fefc4b95e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-122 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-123 b/cmds/servicemanager/corpus/seed-2024-08-29-123 Binary files differnew file mode 100644 index 0000000000..714b6b5f10 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-123 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-124 b/cmds/servicemanager/corpus/seed-2024-08-29-124 Binary files differnew file mode 100644 index 0000000000..925bfcc657 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-124 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-125 b/cmds/servicemanager/corpus/seed-2024-08-29-125 Binary files differnew file mode 100644 index 0000000000..6dbec24c18 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-125 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-126 b/cmds/servicemanager/corpus/seed-2024-08-29-126 Binary files differnew file mode 100644 index 0000000000..d5cdcaa6ab --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-126 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-127 b/cmds/servicemanager/corpus/seed-2024-08-29-127 Binary files differnew file mode 100644 index 0000000000..13d0eb544a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-127 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-128 b/cmds/servicemanager/corpus/seed-2024-08-29-128 Binary files differnew file mode 100644 index 0000000000..471371c657 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-128 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-129 b/cmds/servicemanager/corpus/seed-2024-08-29-129 Binary files differnew file mode 100644 index 0000000000..29087958c4 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-129 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-13 b/cmds/servicemanager/corpus/seed-2024-08-29-13 Binary files differnew file mode 100644 index 0000000000..6c8bd0ac60 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-13 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-130 b/cmds/servicemanager/corpus/seed-2024-08-29-130 Binary files differnew file mode 100644 index 0000000000..3a64ac5eb4 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-130 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-131 b/cmds/servicemanager/corpus/seed-2024-08-29-131 Binary files differnew file mode 100644 index 0000000000..d1da2ea61d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-131 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-132 b/cmds/servicemanager/corpus/seed-2024-08-29-132 Binary files differnew file mode 100644 index 0000000000..6de377e760 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-132 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-133 b/cmds/servicemanager/corpus/seed-2024-08-29-133 Binary files differnew file mode 100644 index 0000000000..38ffcb922d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-133 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-134 b/cmds/servicemanager/corpus/seed-2024-08-29-134 Binary files differnew file mode 100644 index 0000000000..6e828ae599 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-134 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-135 b/cmds/servicemanager/corpus/seed-2024-08-29-135 Binary files differnew file mode 100644 index 0000000000..c3eb8275aa --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-135 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-136 b/cmds/servicemanager/corpus/seed-2024-08-29-136 Binary files differnew file mode 100644 index 0000000000..9b1fafb22a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-136 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-137 b/cmds/servicemanager/corpus/seed-2024-08-29-137 Binary files differnew file mode 100644 index 0000000000..059b55ba8b --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-137 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-138 b/cmds/servicemanager/corpus/seed-2024-08-29-138 Binary files differnew file mode 100644 index 0000000000..391bd8c2c5 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-138 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-139 b/cmds/servicemanager/corpus/seed-2024-08-29-139 Binary files differnew file mode 100644 index 0000000000..8ea28db180 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-139 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-14 b/cmds/servicemanager/corpus/seed-2024-08-29-14 Binary files differnew file mode 100644 index 0000000000..2c704b4f47 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-14 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-140 b/cmds/servicemanager/corpus/seed-2024-08-29-140 Binary files differnew file mode 100644 index 0000000000..621c5365b7 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-140 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-141 b/cmds/servicemanager/corpus/seed-2024-08-29-141 Binary files differnew file mode 100644 index 0000000000..1d8532475f --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-141 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-142 b/cmds/servicemanager/corpus/seed-2024-08-29-142 Binary files differnew file mode 100644 index 0000000000..1df0205b6d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-142 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-143 b/cmds/servicemanager/corpus/seed-2024-08-29-143 Binary files differnew file mode 100644 index 0000000000..be5ddea45e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-143 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-144 b/cmds/servicemanager/corpus/seed-2024-08-29-144 Binary files differnew file mode 100644 index 0000000000..dd7eedfecf --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-144 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-145 b/cmds/servicemanager/corpus/seed-2024-08-29-145 Binary files differnew file mode 100644 index 0000000000..a9c28f91db --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-145 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-146 b/cmds/servicemanager/corpus/seed-2024-08-29-146 Binary files differnew file mode 100644 index 0000000000..8e64a65134 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-146 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-147 b/cmds/servicemanager/corpus/seed-2024-08-29-147 Binary files differnew file mode 100644 index 0000000000..f65abe0cf6 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-147 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-148 b/cmds/servicemanager/corpus/seed-2024-08-29-148 Binary files differnew file mode 100644 index 0000000000..174e50a2f8 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-148 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-149 b/cmds/servicemanager/corpus/seed-2024-08-29-149 Binary files differnew file mode 100644 index 0000000000..3d58671f16 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-149 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-15 b/cmds/servicemanager/corpus/seed-2024-08-29-15 Binary files differnew file mode 100644 index 0000000000..a1c47d31d5 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-15 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-150 b/cmds/servicemanager/corpus/seed-2024-08-29-150 Binary files differnew file mode 100644 index 0000000000..a41c9c84b4 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-150 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-151 b/cmds/servicemanager/corpus/seed-2024-08-29-151 Binary files differnew file mode 100644 index 0000000000..013f84d92a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-151 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-152 b/cmds/servicemanager/corpus/seed-2024-08-29-152 Binary files differnew file mode 100644 index 0000000000..ada2ead1e2 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-152 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-153 b/cmds/servicemanager/corpus/seed-2024-08-29-153 Binary files differnew file mode 100644 index 0000000000..1b565618e9 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-153 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-154 b/cmds/servicemanager/corpus/seed-2024-08-29-154 Binary files differnew file mode 100644 index 0000000000..8fea50f9a3 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-154 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-155 b/cmds/servicemanager/corpus/seed-2024-08-29-155 Binary files differnew file mode 100644 index 0000000000..ddcd8f31c1 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-155 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-156 b/cmds/servicemanager/corpus/seed-2024-08-29-156 Binary files differnew file mode 100644 index 0000000000..19ab7aec2c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-156 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-157 b/cmds/servicemanager/corpus/seed-2024-08-29-157 Binary files differnew file mode 100644 index 0000000000..bc89bf5b68 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-157 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-158 b/cmds/servicemanager/corpus/seed-2024-08-29-158 Binary files differnew file mode 100644 index 0000000000..64867f1c2a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-158 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-159 b/cmds/servicemanager/corpus/seed-2024-08-29-159 Binary files differnew file mode 100644 index 0000000000..fe77d0b3f8 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-159 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-16 b/cmds/servicemanager/corpus/seed-2024-08-29-16 Binary files differnew file mode 100644 index 0000000000..f1002d7d06 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-16 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-160 b/cmds/servicemanager/corpus/seed-2024-08-29-160 Binary files differnew file mode 100644 index 0000000000..9c2123f2b9 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-160 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-161 b/cmds/servicemanager/corpus/seed-2024-08-29-161 Binary files differnew file mode 100644 index 0000000000..0fc8e863c5 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-161 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-162 b/cmds/servicemanager/corpus/seed-2024-08-29-162 Binary files differnew file mode 100644 index 0000000000..a13408506c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-162 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-163 b/cmds/servicemanager/corpus/seed-2024-08-29-163 Binary files differnew file mode 100644 index 0000000000..c23e78c02f --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-163 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-164 b/cmds/servicemanager/corpus/seed-2024-08-29-164 Binary files differnew file mode 100644 index 0000000000..d4feab0651 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-164 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-165 b/cmds/servicemanager/corpus/seed-2024-08-29-165 Binary files differnew file mode 100644 index 0000000000..9cbdc4f4cb --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-165 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-166 b/cmds/servicemanager/corpus/seed-2024-08-29-166 Binary files differnew file mode 100644 index 0000000000..d4cf647d8e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-166 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-167 b/cmds/servicemanager/corpus/seed-2024-08-29-167 Binary files differnew file mode 100644 index 0000000000..5023909539 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-167 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-168 b/cmds/servicemanager/corpus/seed-2024-08-29-168 Binary files differnew file mode 100644 index 0000000000..846d0ec5bc --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-168 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-169 b/cmds/servicemanager/corpus/seed-2024-08-29-169 Binary files differnew file mode 100644 index 0000000000..cf6d882330 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-169 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-17 b/cmds/servicemanager/corpus/seed-2024-08-29-17 Binary files differnew file mode 100644 index 0000000000..6c21de860e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-17 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-170 b/cmds/servicemanager/corpus/seed-2024-08-29-170 Binary files differnew file mode 100644 index 0000000000..d9707cb129 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-170 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-171 b/cmds/servicemanager/corpus/seed-2024-08-29-171 Binary files differnew file mode 100644 index 0000000000..ea947f6b3f --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-171 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-172 b/cmds/servicemanager/corpus/seed-2024-08-29-172 Binary files differnew file mode 100644 index 0000000000..2754437308 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-172 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-173 b/cmds/servicemanager/corpus/seed-2024-08-29-173 Binary files differnew file mode 100644 index 0000000000..96e8d563a2 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-173 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-174 b/cmds/servicemanager/corpus/seed-2024-08-29-174 Binary files differnew file mode 100644 index 0000000000..aa6472e7e5 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-174 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-175 b/cmds/servicemanager/corpus/seed-2024-08-29-175 Binary files differnew file mode 100644 index 0000000000..41e789479b --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-175 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-176 b/cmds/servicemanager/corpus/seed-2024-08-29-176 Binary files differnew file mode 100644 index 0000000000..b94712aefe --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-176 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-177 b/cmds/servicemanager/corpus/seed-2024-08-29-177 Binary files differnew file mode 100644 index 0000000000..4925e6254a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-177 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-178 b/cmds/servicemanager/corpus/seed-2024-08-29-178 Binary files differnew file mode 100644 index 0000000000..9ec943d9fe --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-178 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-179 b/cmds/servicemanager/corpus/seed-2024-08-29-179 Binary files differnew file mode 100644 index 0000000000..e173bd3331 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-179 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-18 b/cmds/servicemanager/corpus/seed-2024-08-29-18 Binary files differnew file mode 100644 index 0000000000..aa0b101ecd --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-18 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-180 b/cmds/servicemanager/corpus/seed-2024-08-29-180 Binary files differnew file mode 100644 index 0000000000..f6f4ba780b --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-180 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-181 b/cmds/servicemanager/corpus/seed-2024-08-29-181 Binary files differnew file mode 100644 index 0000000000..2ca01e693d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-181 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-182 b/cmds/servicemanager/corpus/seed-2024-08-29-182 Binary files differnew file mode 100644 index 0000000000..18966c0ad7 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-182 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-183 b/cmds/servicemanager/corpus/seed-2024-08-29-183 Binary files differnew file mode 100644 index 0000000000..887de1013d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-183 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-184 b/cmds/servicemanager/corpus/seed-2024-08-29-184 Binary files differnew file mode 100644 index 0000000000..fee8cdb6a3 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-184 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-185 b/cmds/servicemanager/corpus/seed-2024-08-29-185 Binary files differnew file mode 100644 index 0000000000..10dd34d8eb --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-185 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-186 b/cmds/servicemanager/corpus/seed-2024-08-29-186 Binary files differnew file mode 100644 index 0000000000..6ad247bec0 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-186 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-187 b/cmds/servicemanager/corpus/seed-2024-08-29-187 Binary files differnew file mode 100644 index 0000000000..613456daef --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-187 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-188 b/cmds/servicemanager/corpus/seed-2024-08-29-188 Binary files differnew file mode 100644 index 0000000000..851b25fee7 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-188 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-189 b/cmds/servicemanager/corpus/seed-2024-08-29-189 Binary files differnew file mode 100644 index 0000000000..c4cebe91fd --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-189 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-19 b/cmds/servicemanager/corpus/seed-2024-08-29-19 Binary files differnew file mode 100644 index 0000000000..c0792c09c3 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-19 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-190 b/cmds/servicemanager/corpus/seed-2024-08-29-190 Binary files differnew file mode 100644 index 0000000000..4370a318b4 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-190 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-191 b/cmds/servicemanager/corpus/seed-2024-08-29-191 Binary files differnew file mode 100644 index 0000000000..09704284ee --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-191 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-192 b/cmds/servicemanager/corpus/seed-2024-08-29-192 Binary files differnew file mode 100644 index 0000000000..6cec4004da --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-192 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-193 b/cmds/servicemanager/corpus/seed-2024-08-29-193 Binary files differnew file mode 100644 index 0000000000..15a766167d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-193 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-194 b/cmds/servicemanager/corpus/seed-2024-08-29-194 Binary files differnew file mode 100644 index 0000000000..3cabe77e6d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-194 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-195 b/cmds/servicemanager/corpus/seed-2024-08-29-195 Binary files differnew file mode 100644 index 0000000000..4c5274bca9 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-195 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-196 b/cmds/servicemanager/corpus/seed-2024-08-29-196 Binary files differnew file mode 100644 index 0000000000..9d7a3d6a76 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-196 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-197 b/cmds/servicemanager/corpus/seed-2024-08-29-197 Binary files differnew file mode 100644 index 0000000000..4e69238bf3 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-197 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-198 b/cmds/servicemanager/corpus/seed-2024-08-29-198 Binary files differnew file mode 100644 index 0000000000..5f6df994be --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-198 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-199 b/cmds/servicemanager/corpus/seed-2024-08-29-199 Binary files differnew file mode 100644 index 0000000000..a902bba205 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-199 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-2 b/cmds/servicemanager/corpus/seed-2024-08-29-2 Binary files differnew file mode 100644 index 0000000000..ffa97196a9 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-2 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-20 b/cmds/servicemanager/corpus/seed-2024-08-29-20 Binary files differnew file mode 100644 index 0000000000..2090ef620a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-20 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-200 b/cmds/servicemanager/corpus/seed-2024-08-29-200 Binary files differnew file mode 100644 index 0000000000..2c91da6f3e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-200 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-201 b/cmds/servicemanager/corpus/seed-2024-08-29-201 Binary files differnew file mode 100644 index 0000000000..eb77655ce1 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-201 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-202 b/cmds/servicemanager/corpus/seed-2024-08-29-202 Binary files differnew file mode 100644 index 0000000000..bcbe3b7619 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-202 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-203 b/cmds/servicemanager/corpus/seed-2024-08-29-203 Binary files differnew file mode 100644 index 0000000000..7c3dc94e42 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-203 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-204 b/cmds/servicemanager/corpus/seed-2024-08-29-204 Binary files differnew file mode 100644 index 0000000000..a4b660e5f7 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-204 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-205 b/cmds/servicemanager/corpus/seed-2024-08-29-205 Binary files differnew file mode 100644 index 0000000000..aee1c21fae --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-205 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-206 b/cmds/servicemanager/corpus/seed-2024-08-29-206 Binary files differnew file mode 100644 index 0000000000..6863c2ef0a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-206 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-207 b/cmds/servicemanager/corpus/seed-2024-08-29-207 Binary files differnew file mode 100644 index 0000000000..bf2c59f084 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-207 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-208 b/cmds/servicemanager/corpus/seed-2024-08-29-208 Binary files differnew file mode 100644 index 0000000000..78081b969e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-208 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-209 b/cmds/servicemanager/corpus/seed-2024-08-29-209 Binary files differnew file mode 100644 index 0000000000..76df969df6 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-209 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-21 b/cmds/servicemanager/corpus/seed-2024-08-29-21 Binary files differnew file mode 100644 index 0000000000..510b9cf365 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-21 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-210 b/cmds/servicemanager/corpus/seed-2024-08-29-210 Binary files differnew file mode 100644 index 0000000000..b5174e0966 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-210 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-211 b/cmds/servicemanager/corpus/seed-2024-08-29-211 Binary files differnew file mode 100644 index 0000000000..51af471916 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-211 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-212 b/cmds/servicemanager/corpus/seed-2024-08-29-212 Binary files differnew file mode 100644 index 0000000000..f260df4564 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-212 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-213 b/cmds/servicemanager/corpus/seed-2024-08-29-213 Binary files differnew file mode 100644 index 0000000000..2d322b9584 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-213 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-214 b/cmds/servicemanager/corpus/seed-2024-08-29-214 Binary files differnew file mode 100644 index 0000000000..8df3af4716 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-214 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-215 b/cmds/servicemanager/corpus/seed-2024-08-29-215 Binary files differnew file mode 100644 index 0000000000..b82d03b171 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-215 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-216 b/cmds/servicemanager/corpus/seed-2024-08-29-216 Binary files differnew file mode 100644 index 0000000000..16f6d4d6ae --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-216 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-217 b/cmds/servicemanager/corpus/seed-2024-08-29-217 Binary files differnew file mode 100644 index 0000000000..d4c2bb36c6 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-217 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-218 b/cmds/servicemanager/corpus/seed-2024-08-29-218 Binary files differnew file mode 100644 index 0000000000..d0c1970146 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-218 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-219 b/cmds/servicemanager/corpus/seed-2024-08-29-219 Binary files differnew file mode 100644 index 0000000000..75edd86eef --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-219 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-22 b/cmds/servicemanager/corpus/seed-2024-08-29-22 Binary files differnew file mode 100644 index 0000000000..aa87441e0d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-22 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-220 b/cmds/servicemanager/corpus/seed-2024-08-29-220 Binary files differnew file mode 100644 index 0000000000..b3b6788f9d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-220 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-221 b/cmds/servicemanager/corpus/seed-2024-08-29-221 Binary files differnew file mode 100644 index 0000000000..429da0ef05 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-221 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-222 b/cmds/servicemanager/corpus/seed-2024-08-29-222 Binary files differnew file mode 100644 index 0000000000..be8e3f30fd --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-222 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-223 b/cmds/servicemanager/corpus/seed-2024-08-29-223 Binary files differnew file mode 100644 index 0000000000..a5a6d9c9da --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-223 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-224 b/cmds/servicemanager/corpus/seed-2024-08-29-224 Binary files differnew file mode 100644 index 0000000000..9a7d07e60c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-224 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-225 b/cmds/servicemanager/corpus/seed-2024-08-29-225 Binary files differnew file mode 100644 index 0000000000..39a5644d71 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-225 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-226 b/cmds/servicemanager/corpus/seed-2024-08-29-226 Binary files differnew file mode 100644 index 0000000000..c32f26ad65 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-226 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-227 b/cmds/servicemanager/corpus/seed-2024-08-29-227 Binary files differnew file mode 100644 index 0000000000..5af105be86 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-227 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-23 b/cmds/servicemanager/corpus/seed-2024-08-29-23 Binary files differnew file mode 100644 index 0000000000..4399c39593 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-23 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-24 b/cmds/servicemanager/corpus/seed-2024-08-29-24 Binary files differnew file mode 100644 index 0000000000..133c59a8ae --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-24 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-25 b/cmds/servicemanager/corpus/seed-2024-08-29-25 Binary files differnew file mode 100644 index 0000000000..ec1ac02447 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-25 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-26 b/cmds/servicemanager/corpus/seed-2024-08-29-26 Binary files differnew file mode 100644 index 0000000000..55397b96d5 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-26 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-27 b/cmds/servicemanager/corpus/seed-2024-08-29-27 Binary files differnew file mode 100644 index 0000000000..517af0b887 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-27 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-28 b/cmds/servicemanager/corpus/seed-2024-08-29-28 Binary files differnew file mode 100644 index 0000000000..0401668a65 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-28 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-29 b/cmds/servicemanager/corpus/seed-2024-08-29-29 Binary files differnew file mode 100644 index 0000000000..05ad4ecbb5 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-29 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-3 b/cmds/servicemanager/corpus/seed-2024-08-29-3 Binary files differnew file mode 100644 index 0000000000..14dcdd0c0d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-3 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-30 b/cmds/servicemanager/corpus/seed-2024-08-29-30 Binary files differnew file mode 100644 index 0000000000..d941024dab --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-30 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-31 b/cmds/servicemanager/corpus/seed-2024-08-29-31 Binary files differnew file mode 100644 index 0000000000..e93a19271e --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-31 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-32 b/cmds/servicemanager/corpus/seed-2024-08-29-32 Binary files differnew file mode 100644 index 0000000000..36f82dd1e8 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-32 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-33 b/cmds/servicemanager/corpus/seed-2024-08-29-33 Binary files differnew file mode 100644 index 0000000000..5f64227f41 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-33 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-34 b/cmds/servicemanager/corpus/seed-2024-08-29-34 Binary files differnew file mode 100644 index 0000000000..13f76344b4 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-34 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-35 b/cmds/servicemanager/corpus/seed-2024-08-29-35 Binary files differnew file mode 100644 index 0000000000..3a4476e55c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-35 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-36 b/cmds/servicemanager/corpus/seed-2024-08-29-36 Binary files differnew file mode 100644 index 0000000000..da9c20870f --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-36 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-37 b/cmds/servicemanager/corpus/seed-2024-08-29-37 Binary files differnew file mode 100644 index 0000000000..969a957c35 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-37 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-38 b/cmds/servicemanager/corpus/seed-2024-08-29-38 Binary files differnew file mode 100644 index 0000000000..ab6f1061ed --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-38 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-39 b/cmds/servicemanager/corpus/seed-2024-08-29-39 Binary files differnew file mode 100644 index 0000000000..248a549811 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-39 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-4 b/cmds/servicemanager/corpus/seed-2024-08-29-4 Binary files differnew file mode 100644 index 0000000000..0bd7cd5813 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-4 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-40 b/cmds/servicemanager/corpus/seed-2024-08-29-40 Binary files differnew file mode 100644 index 0000000000..7031a918fc --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-40 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-41 b/cmds/servicemanager/corpus/seed-2024-08-29-41 Binary files differnew file mode 100644 index 0000000000..8b8925c6e2 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-41 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-42 b/cmds/servicemanager/corpus/seed-2024-08-29-42 Binary files differnew file mode 100644 index 0000000000..c6e2167d12 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-42 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-43 b/cmds/servicemanager/corpus/seed-2024-08-29-43 Binary files differnew file mode 100644 index 0000000000..671a82172c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-43 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-44 b/cmds/servicemanager/corpus/seed-2024-08-29-44 Binary files differnew file mode 100644 index 0000000000..7c365b06c3 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-44 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-45 b/cmds/servicemanager/corpus/seed-2024-08-29-45 Binary files differnew file mode 100644 index 0000000000..a38d1382d8 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-45 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-46 b/cmds/servicemanager/corpus/seed-2024-08-29-46 Binary files differnew file mode 100644 index 0000000000..62acb777dc --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-46 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-47 b/cmds/servicemanager/corpus/seed-2024-08-29-47 Binary files differnew file mode 100644 index 0000000000..aea84c6ded --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-47 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-48 b/cmds/servicemanager/corpus/seed-2024-08-29-48 Binary files differnew file mode 100644 index 0000000000..a5bab7c63b --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-48 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-49 b/cmds/servicemanager/corpus/seed-2024-08-29-49 Binary files differnew file mode 100644 index 0000000000..4f19f09a02 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-49 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-5 b/cmds/servicemanager/corpus/seed-2024-08-29-5 Binary files differnew file mode 100644 index 0000000000..4e8a8534cf --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-5 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-50 b/cmds/servicemanager/corpus/seed-2024-08-29-50 Binary files differnew file mode 100644 index 0000000000..2f1d78b4ff --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-50 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-51 b/cmds/servicemanager/corpus/seed-2024-08-29-51 Binary files differnew file mode 100644 index 0000000000..7a44b4a5c7 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-51 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-52 b/cmds/servicemanager/corpus/seed-2024-08-29-52 Binary files differnew file mode 100644 index 0000000000..3da177b3df --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-52 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-53 b/cmds/servicemanager/corpus/seed-2024-08-29-53 Binary files differnew file mode 100644 index 0000000000..c67df718ba --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-53 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-54 b/cmds/servicemanager/corpus/seed-2024-08-29-54 Binary files differnew file mode 100644 index 0000000000..b1e8fec010 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-54 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-55 b/cmds/servicemanager/corpus/seed-2024-08-29-55 Binary files differnew file mode 100644 index 0000000000..20b268a3c1 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-55 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-56 b/cmds/servicemanager/corpus/seed-2024-08-29-56 Binary files differnew file mode 100644 index 0000000000..146192696c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-56 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-57 b/cmds/servicemanager/corpus/seed-2024-08-29-57 Binary files differnew file mode 100644 index 0000000000..fab8065815 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-57 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-58 b/cmds/servicemanager/corpus/seed-2024-08-29-58 Binary files differnew file mode 100644 index 0000000000..676f9e46d3 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-58 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-59 b/cmds/servicemanager/corpus/seed-2024-08-29-59 Binary files differnew file mode 100644 index 0000000000..a8e2c7220f --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-59 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-6 b/cmds/servicemanager/corpus/seed-2024-08-29-6 Binary files differnew file mode 100644 index 0000000000..585f1f0c04 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-6 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-60 b/cmds/servicemanager/corpus/seed-2024-08-29-60 Binary files differnew file mode 100644 index 0000000000..ef4b098b58 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-60 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-61 b/cmds/servicemanager/corpus/seed-2024-08-29-61 Binary files differnew file mode 100644 index 0000000000..5f45443fd4 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-61 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-62 b/cmds/servicemanager/corpus/seed-2024-08-29-62 Binary files differnew file mode 100644 index 0000000000..7ffd776948 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-62 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-63 b/cmds/servicemanager/corpus/seed-2024-08-29-63 Binary files differnew file mode 100644 index 0000000000..fa026cd452 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-63 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-64 b/cmds/servicemanager/corpus/seed-2024-08-29-64 Binary files differnew file mode 100644 index 0000000000..422c823386 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-64 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-65 b/cmds/servicemanager/corpus/seed-2024-08-29-65 Binary files differnew file mode 100644 index 0000000000..c811c44438 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-65 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-66 b/cmds/servicemanager/corpus/seed-2024-08-29-66 Binary files differnew file mode 100644 index 0000000000..8407da2006 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-66 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-67 b/cmds/servicemanager/corpus/seed-2024-08-29-67 Binary files differnew file mode 100644 index 0000000000..76dfdc3c95 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-67 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-68 b/cmds/servicemanager/corpus/seed-2024-08-29-68 Binary files differnew file mode 100644 index 0000000000..d93e0e3a5a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-68 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-69 b/cmds/servicemanager/corpus/seed-2024-08-29-69 Binary files differnew file mode 100644 index 0000000000..12b501b7da --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-69 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-7 b/cmds/servicemanager/corpus/seed-2024-08-29-7 Binary files differnew file mode 100644 index 0000000000..647836362d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-7 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-70 b/cmds/servicemanager/corpus/seed-2024-08-29-70 Binary files differnew file mode 100644 index 0000000000..e6206230cc --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-70 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-71 b/cmds/servicemanager/corpus/seed-2024-08-29-71 Binary files differnew file mode 100644 index 0000000000..dc32a5f830 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-71 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-72 b/cmds/servicemanager/corpus/seed-2024-08-29-72 Binary files differnew file mode 100644 index 0000000000..24217c62c6 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-72 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-73 b/cmds/servicemanager/corpus/seed-2024-08-29-73 Binary files differnew file mode 100644 index 0000000000..a9a0b2be58 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-73 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-74 b/cmds/servicemanager/corpus/seed-2024-08-29-74 Binary files differnew file mode 100644 index 0000000000..fd8a429232 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-74 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-75 b/cmds/servicemanager/corpus/seed-2024-08-29-75 Binary files differnew file mode 100644 index 0000000000..090b4894b0 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-75 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-76 b/cmds/servicemanager/corpus/seed-2024-08-29-76 Binary files differnew file mode 100644 index 0000000000..c92c45f97c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-76 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-77 b/cmds/servicemanager/corpus/seed-2024-08-29-77 Binary files differnew file mode 100644 index 0000000000..002a2336d0 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-77 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-78 b/cmds/servicemanager/corpus/seed-2024-08-29-78 Binary files differnew file mode 100644 index 0000000000..633f937341 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-78 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-79 b/cmds/servicemanager/corpus/seed-2024-08-29-79 Binary files differnew file mode 100644 index 0000000000..77782404bb --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-79 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-8 b/cmds/servicemanager/corpus/seed-2024-08-29-8 Binary files differnew file mode 100644 index 0000000000..580e20005a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-8 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-80 b/cmds/servicemanager/corpus/seed-2024-08-29-80 Binary files differnew file mode 100644 index 0000000000..90d74e44fd --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-80 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-81 b/cmds/servicemanager/corpus/seed-2024-08-29-81 Binary files differnew file mode 100644 index 0000000000..1fd76686f7 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-81 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-82 b/cmds/servicemanager/corpus/seed-2024-08-29-82 Binary files differnew file mode 100644 index 0000000000..d771501508 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-82 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-83 b/cmds/servicemanager/corpus/seed-2024-08-29-83 Binary files differnew file mode 100644 index 0000000000..6a4a1ca251 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-83 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-84 b/cmds/servicemanager/corpus/seed-2024-08-29-84 Binary files differnew file mode 100644 index 0000000000..bf8459b34c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-84 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-85 b/cmds/servicemanager/corpus/seed-2024-08-29-85 Binary files differnew file mode 100644 index 0000000000..8c88cacdc1 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-85 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-86 b/cmds/servicemanager/corpus/seed-2024-08-29-86 Binary files differnew file mode 100644 index 0000000000..62f676585a --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-86 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-87 b/cmds/servicemanager/corpus/seed-2024-08-29-87 Binary files differnew file mode 100644 index 0000000000..eb54dcbca2 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-87 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-88 b/cmds/servicemanager/corpus/seed-2024-08-29-88 Binary files differnew file mode 100644 index 0000000000..f38aaba211 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-88 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-89 b/cmds/servicemanager/corpus/seed-2024-08-29-89 Binary files differnew file mode 100644 index 0000000000..b4154aeeea --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-89 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-9 b/cmds/servicemanager/corpus/seed-2024-08-29-9 Binary files differnew file mode 100644 index 0000000000..5dca38a5a2 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-9 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-90 b/cmds/servicemanager/corpus/seed-2024-08-29-90 Binary files differnew file mode 100644 index 0000000000..2725a79022 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-90 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-91 b/cmds/servicemanager/corpus/seed-2024-08-29-91 Binary files differnew file mode 100644 index 0000000000..9140e28e10 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-91 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-92 b/cmds/servicemanager/corpus/seed-2024-08-29-92 Binary files differnew file mode 100644 index 0000000000..88dda1e85c --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-92 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-93 b/cmds/servicemanager/corpus/seed-2024-08-29-93 Binary files differnew file mode 100644 index 0000000000..6dd114e84d --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-93 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-94 b/cmds/servicemanager/corpus/seed-2024-08-29-94 Binary files differnew file mode 100644 index 0000000000..462c185d07 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-94 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-95 b/cmds/servicemanager/corpus/seed-2024-08-29-95 Binary files differnew file mode 100644 index 0000000000..4472deb9b1 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-95 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-96 b/cmds/servicemanager/corpus/seed-2024-08-29-96 Binary files differnew file mode 100644 index 0000000000..875efc5b2b --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-96 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-97 b/cmds/servicemanager/corpus/seed-2024-08-29-97 Binary files differnew file mode 100644 index 0000000000..3f0277e129 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-97 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-98 b/cmds/servicemanager/corpus/seed-2024-08-29-98 Binary files differnew file mode 100644 index 0000000000..2c66436172 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-98 diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-99 b/cmds/servicemanager/corpus/seed-2024-08-29-99 Binary files differnew file mode 100644 index 0000000000..9a6ff1dff0 --- /dev/null +++ b/cmds/servicemanager/corpus/seed-2024-08-29-99 diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h index 769670ea99..0b7e16bc7d 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 @@ public: 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 @@ public: /*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 43e9fac5e2..3d5d52e80c 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -234,7 +234,7 @@ class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<Sma } // 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 @@ template <typename T> 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 @@ class SmallVector<T, 0> final : details::ArrayTraits<T>, 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 1a3cb6a884..a8684bd19b 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -251,6 +251,8 @@ enum class InputEventType { 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 65c2914b3c..358a19158e 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 @@ public: class InputConsumerNoResampling final { public: /** + * This constructor is exclusively for test code. Any real use of InputConsumerNoResampling must + * use the constructor that takes an sp<Looper> parameter instead of + * std::shared_ptr<LooperInterface>. + */ + explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, + std::shared_ptr<LooperInterface> looper, + InputConsumerCallbacks& callbacks, + std::unique_ptr<Resampler> resampler); + + /** * @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever * the event is ready to consume. * @param looper needs to be sp and not shared_ptr because it inherits from @@ -108,7 +119,7 @@ public: 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 7d8c19e702..1a482396ee 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -389,6 +389,7 @@ enum class InputDeviceConfigurationFileType : int32_t { 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 55e058332d..5bd5070488 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 @@ public: 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 @@ private: 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 7d11f76c85..0cd87201fb 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -263,7 +263,7 @@ public: * 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 @@ public: * 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 @@ public: */ 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 0000000000..2d6719c965 --- /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 8c356d0140..e5eee340ca 100644 --- a/include/private/performance_hint_private.h +++ b/include/private/performance_hint_private.h @@ -108,6 +108,10 @@ APerformanceHintSession* APerformanceHint_createSessionInternal(APerformanceHint 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 78896ed553..d31cb3dff0 100644 --- a/libs/adbd_auth/adbd_auth.cpp +++ b/libs/adbd_auth/adbd_auth.cpp @@ -390,13 +390,16 @@ public: } } - 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 de331b79c2..379b609e9f 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -87,6 +87,11 @@ cc_library_headers { 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 54f687b280..5680798d0d 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::getService(const ::std::string& nam 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 @@ void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Se 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 @@ void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Se } }; 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 @@ sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager() { 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 8f3839fcb2..47b2ec9f2c 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 @@ public: } 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 455a4338e5..f0aa801d01 100644 --- a/libs/binder/FdTrigger.cpp +++ b/libs/binder/FdTrigger.cpp @@ -82,7 +82,9 @@ status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, 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 @@ status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, // 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 c55dd9de1b..88761d772f 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 @@ protected: } }; +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 @@ void setDefaultServiceManager(const sp<IServiceManager>& sm) { } } +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 e8fe555ab3..4b7af45739 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -1725,7 +1725,9 @@ status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) } } } - ::munmap(ptr, len); + if (::munmap(ptr, len) == -1) { + ALOGW("munmap() failed: %s", strerror(errno)); + } } ::close(fd); return status; @@ -3332,7 +3334,9 @@ Parcel::Blob::~Blob() { 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 49def82b5d..cd21a91d2c 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -589,6 +589,21 @@ status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) { 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 @@ status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, 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 @@ status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, 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 c7ba5d96a7..ee7d448c43 100644 --- a/libs/binder/RpcSocketAddress.h +++ b/libs/binder/RpcSocketAddress.h @@ -113,4 +113,11 @@ private: 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 125617363a..95a5da20ae 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 a3134a3f7c..c06e05c444 100644 --- a/libs/binder/aidl/android/os/IAccessor.aidl +++ b/libs/binder/aidl/android/os/IAccessor.aidl @@ -25,15 +25,56 @@ import android.os.ParcelFileDescriptor; */ 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 5fb73079cb..879f319c5e 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 checkCallingPermission(const String16& permission, int32 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 0000000000..ff25163ddc --- /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 4e02aceb86..5f45cb2f07 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -230,12 +230,24 @@ cc_library_headers { }, 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 @@ ndk_headers { 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 62738041ba..af56bf0da1 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 @@ class BpCInterface : public INTERFACE { 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 340014aeaa..04f1517556 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -195,7 +195,7 @@ impl PartialOrd for SpIBinder { 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 21c32acb0a..0e653af707 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -46,11 +46,35 @@ cc_test { "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 @@ cc_test { "libgmock", ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, @@ -705,7 +729,7 @@ cc_test { "libutils", ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, @@ -762,7 +786,7 @@ cc_test { ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, @@ -888,6 +912,7 @@ cc_defaults { 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 0000000000..92dab19a63 --- /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 3038de9a41..fbca35e81f 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -365,26 +365,57 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( 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 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( 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 @@ TEST_P(BinderRpc, Fds) { 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 @@ static std::vector<BinderRpc::ParamType> getBinderRpcParams() { 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 2c9646b30e..c8a8acc0a0 100644 --- a/libs/binder/tests/binderRpcTestFixture.h +++ b/libs/binder/tests/binderRpcTestFixture.h @@ -35,6 +35,12 @@ public: 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 fe44ea5e28..583ad015e1 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -42,7 +42,7 @@ public: // 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 454bdf144e..8288f9f3cf 100644 --- a/libs/bufferstreams/rust/src/stream_config.rs +++ b/libs/bufferstreams/rust/src/stream_config.rs @@ -32,10 +32,23 @@ pub struct StreamConfig { 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 @@ mod test { 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 833718213a..d9cdb59dfe 100644 --- a/libs/gralloc/types/fuzzer/Android.bp +++ b/libs/gralloc/types/fuzzer/Android.bp @@ -28,14 +28,10 @@ cc_fuzz { ], 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 4c3f4a6428..d1a56635f5 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -401,18 +401,10 @@ void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) { 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 @@ void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, 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 1db8cbe52f..4aa8fff1e2 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 7f45581da9..72f29c6b0b 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -141,7 +141,6 @@ public: 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 f065ffa611..3c1971fd81 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 @@ namespace android { 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 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati }, 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 @@ BLASTBufferQueue::~BLASTBufferQueue() { 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 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, 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 @@ static std::optional<SurfaceControlStats> findMatchingStat( 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 @@ void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, 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 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence 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 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stat.currentMaxAcquiredBufferCount, true /* fakeRelease */); } +#endif } else { BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback"); } @@ -413,23 +431,6 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence 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 @@ void BLASTBufferQueue::flushShadowQueue() { } } +// 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 @@ void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId, 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 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( applyTransaction = false; } - BLASTBufferItem bufferItem; + BufferItem bufferItem; status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false); @@ -610,9 +622,6 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( 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 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( 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 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( 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 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { } // 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 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { // 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::onFrameDequeued(const uint64_t bufferId) { }; 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 @@ public: 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 @@ public: 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 @@ bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceCon 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 da3886ccf0..66e7ddd915 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -77,9 +77,28 @@ bool isInterceptorRegistrationOp(int op) { } // 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 @@ Surface::~Surface() { 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 @@ status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer, sp<Fence>* outFence) 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 @@ void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence, #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 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { 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 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { 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,9 +1308,20 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { 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 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; mReportRemovedBuffers = reportBufferRemoval; + if (listener != nullptr) { mListenerProxy = new ProducerListenerProxy(this, listener); } @@ -2053,6 +2103,13 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu } 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 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { 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 7d3e5c166f..df58df43be 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2051,8 +2051,9 @@ SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp<Surfa 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::addTrans 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 7ea9d22ecf..ec13681182 100644 --- a/libs/gui/aidl/android/gui/JankData.aidl +++ b/libs/gui/aidl/android/gui/JankData.aidl @@ -29,7 +29,17 @@ parcelable JankData { 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 c2dcd2579c..d787d6cc45 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -103,15 +103,21 @@ public: 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 @@ private: // 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 @@ private: // 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 @@ private: 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 0f51f2dc13..e74f9ad1dc 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -66,6 +66,16 @@ public: 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 @@ public: 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 @@ private: 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 @@ public: // 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 @@ public: 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 @@ protected: 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 @@ protected: // 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 c367e75065..df9b73bfcd 100644 --- a/libs/gui/libgui_flags.aconfig +++ b/libs/gui/libgui_flags.aconfig @@ -91,3 +91,19 @@ flag { 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 2ac2550f07..8db48d2eb0 100644 --- a/libs/gui/tests/Choreographer_test.cpp +++ b/libs/gui/tests/Choreographer_test.cpp @@ -52,25 +52,23 @@ TEST_F(ChoreographerTest, InputCallbackBeforeAnimation) { 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 ab09dfc58d..88893b64ba 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 @@ private: 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 @@ TEST_F(SurfaceTest, ViewSurface_toString) { 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 99ffa683dd..eb419180e7 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 @@ namespace { const bool DEBUG_TRANSPORT_CONSUMER = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO); +/** + * RealLooper is a wrapper of Looper. All the member functions exclusively call the internal looper. + * This class' behavior is the same as Looper. + */ +class RealLooper final : public LooperInterface { +public: + RealLooper(sp<Looper> looper) : mLooper{looper} {} + + int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, + void* data) override { + return mLooper->addFd(fd, ident, events, callback, data); + } + + int removeFd(int fd) override { return mLooper->removeFd(fd); } + + sp<Looper> getLooper() const override { return mLooper; } + +private: + sp<Looper> mLooper; +}; + std::unique_ptr<KeyEvent> createKeyEvent(const InputMessage& msg) { std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>(); event->initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source, @@ -173,22 +192,20 @@ InputMessage createTimelineMessage(int32_t inputEventId, nsecs_t gpuCompletedTim 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 @@ InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<Input setFdEvents(ALOOPER_EVENT_INPUT); } +InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, + sp<Looper> looper, + InputConsumerCallbacks& callbacks, + std::unique_ptr<Resampler> resampler) + : InputConsumerNoResampling(channel, std::make_shared<RealLooper>(looper), callbacks, + std::move(resampler)) {} + InputConsumerNoResampling::~InputConsumerNoResampling() { ensureCalledOnLooperThread(__func__); consumeBatchedInputEvents(std::nullopt); @@ -513,7 +537,7 @@ bool InputConsumerNoResampling::consumeBatchedInputEvents( 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 9333ab83a6..c9030312f9 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 @@ using android::base::StringPrintf; 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 @@ std::string getInputDeviceConfigurationFilePathByName( 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 @@ std::string getInputDeviceConfigurationFilePathByName( } 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 500f7b4d8a..f1c4aed7af 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -164,3 +164,31 @@ flag { 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 008f675485..4f4ea8568b 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -24,12 +24,14 @@ mod keyboard_classifier; 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 132866bd99..43bc8948dd 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -16,6 +16,7 @@ cc_test { "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 @@ cc_test { "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 0000000000..c30f243398 --- /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 b372c0b183..7ae9a28664 100644 --- a/libs/input/tests/Resampler_test.cpp +++ b/libs/input/tests/Resampler_test.cpp @@ -70,22 +70,18 @@ struct InputSample { }; 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; - - 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; + InputMessageBuilder messageBuilder = + InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0} + .eventTime(std::chrono::nanoseconds{eventTime}.count()) + .source(AINPUT_SOURCE_TOUCHSCREEN) + .downTime(0); + + 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 0000000000..d5f00b699b --- /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 0000000000..43253ec0ef --- /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 0000000000..e0f01ed25d --- /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 0000000000..3242bc7699 --- /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 099f47dbe1..f1453bd64d 100644 --- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h +++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h @@ -98,11 +98,25 @@ public: * 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 @@ protected: 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 3a09204878..ce232cc4c7 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -35,6 +35,49 @@ namespace android { 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 @@ SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t te 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 @@ SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t te 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 @@ void SurfaceTexture::onSetFrameRate(float frameRate, int8_t compatibility, } #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 855807472e..a8a86ba1a9 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -67,9 +67,6 @@ ndk_library { // 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 97740dbcd8..d68d6ba1af 100644 --- a/libs/nativewindow/rust/Android.bp +++ b/libs/nativewindow/rust/Android.bp @@ -29,6 +29,8 @@ rust_bindgen { "--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 @@ rust_bindgen { ], shared_libs: [ "libbinder_ndk", + "libcutils", "libnativewindow", ], rustlibs: [ @@ -66,6 +69,7 @@ rust_library { 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 0000000000..a3a9dc6258 --- /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 dc3f51f7fd..931c311e65 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,31 +30,29 @@ use binder::{ 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 an opaque C `AHardwareBuffer`. -#[derive(PartialEq, Eq)] -pub struct HardwareBuffer(NonNull<AHardwareBuffer>); +/// Wrapper around a C `AHardwareBuffer_Desc`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct HardwareBufferDescription(AHardwareBuffer_Desc); -impl HardwareBuffer { - /// Test whether the given format and usage flag combination is allocatable. If this function - /// returns true, it means that a buffer with the given description can be allocated on this - /// implementation, unless resource exhaustion occurs. If this function returns false, it means - /// that the allocation of the given description will never succeed. - /// - /// Available since API 29 - pub fn is_supported( +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, - ) -> bool { - let buffer_desc = ffi::AHardwareBuffer_Desc { + ) -> Self { + Self(AHardwareBuffer_Desc { width, height, layers, @@ -60,9 +61,69 @@ impl HardwareBuffer { stride, rfu0: 0, rfu1: 0, - }; - // SAFETY: *buffer_desc will never be null. - let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; + }) + } + + /// 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>); + +impl HardwareBuffer { + /// Test whether the given format and usage flag combination is allocatable. If this function + /// returns true, it means that a buffer with the given description can be allocated on this + /// implementation, unless resource exhaustion occurs. If this function returns false, it means + /// that the allocation of the given description will never succeed. + /// + /// Available since API 29 + 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 @@ impl HardwareBuffer { /// /// 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 @@ impl HardwareBuffer { } } + /// 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 @@ impl HardwareBuffer { 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 @@ impl HardwareBuffer { }; // 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 @@ mod test { #[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 @@ mod test { // 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!( + description.format(), + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM + ); assert_eq!( - buffer.usage(), + 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 @@ mod test { #[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 @@ mod test { #[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 @@ mod test { 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 5689f7df94..5046a80095 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 6cf8291da2..937ff02241 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -50,9 +50,14 @@ protected: 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 @@ protected: 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 876f6c8e26..73a7e95149 100644 --- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -22,13 +22,14 @@ use nativewindow::*; #[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 @@ fn criterion_benchmark(c: &mut Criterion) { // 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 326d1cec1b..a9264b3914 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 @@ static void benchDrawLayers(RenderEngine& re, const std::vector<LayerSettings>& } } +/** + * 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()); - - // Now copy into GPU-only buffer for more realistic timing. - srcBuffer = copyBuffer(*re, srcBuffer, 0, "source"); - } + auto srcBuffer = createTexture(*re, kHomescreenPath); + + 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 @@ void BM_blur(benchmark::State& benchState, Args&&... args) { }; auto layers = std::vector<LayerSettings>{layer, blurLayer}; - benchDrawLayers(*re, layers, benchState, "blurred"); + benchDrawLayers(*re, layers, benchState, "homescreen_blurred"); +} + +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))); + + auto [width, height] = getDisplaySize(); + auto srcBuffer = createTexture(*re, kHomescreenPath); + + 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_blur, gaussian, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL, - RenderEngine::BlurAlgorithm::GAUSSIAN); +BENCHMARK_CAPTURE(BM_homescreen_blur, gaussian, RenderEngine::Threaded::YES, + RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::GAUSSIAN); -BENCHMARK_CAPTURE(BM_blur, kawase, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL, - RenderEngine::BlurAlgorithm::KAWASE); +BENCHMARK_CAPTURE(BM_homescreen_blur, kawase, RenderEngine::Threaded::YES, + RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE); -BENCHMARK_CAPTURE(BM_blur, kawase_dual_filter, RenderEngine::Threaded::YES, +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 74daf471fa..a570ad01a2 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 af24600ade..4ef7d5bccb 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 bd177e60ba..765103889e 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 426ccd651d..ec9d3efb88 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 faa3fb5249..b5f8898263 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 d89e818cdc..677a2b63b2 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 3fbc6ca22e..88282e7f5a 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 5cf8647801..4337df18d4 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 b121fe83eb..931f8433da 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 09877a5ede..fa12624ff7 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 9fa6fb8521..0bd8283987 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 e5af7406ed..8b13d78840 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 @@ std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) { 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::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { 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 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { 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 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { } } - 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 @@ std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData( } 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 8bc2017b55..648e024d86 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 @@ namespace android { 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 @@ struct Edid { 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 721b46688e..76e3f66e1b 100644 --- a/libs/ui/tests/DisplayIdentification_test.cpp +++ b/libs/ui/tests/DisplayIdentification_test.cpp @@ -194,6 +194,10 @@ TEST(DisplayIdentificationTest, parseEdid) { 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 @@ TEST(DisplayIdentificationTest, parseEdid) { 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 @@ TEST(DisplayIdentificationTest, parseEdid) { 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 @@ TEST(DisplayIdentificationTest, parseEdid) { 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 @@ TEST(DisplayIdentificationTest, parseEdid) { 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 @@ TEST(DisplayIdentificationTest, parseEdid) { 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 3d60a1dad6..645a578c76 100644 --- a/opengl/OWNERS +++ b/opengl/OWNERS @@ -2,5 +2,4 @@ chrisforbes@google.com 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 16de3908f8..5159ffe86b 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -40,9 +40,6 @@ ndk_library { symbol_file: "libEGL.map.txt", first_version: "9", unversioned_until: "current", - export_header_libs: [ - "libEGL_headers", - ], } ndk_library { @@ -50,9 +47,6 @@ ndk_library { symbol_file: "libGLESv1_CM.map.txt", first_version: "9", unversioned_until: "current", - export_header_libs: [ - "libGLESv1_CM_headers", - ], } ndk_library { @@ -60,9 +54,6 @@ ndk_library { symbol_file: "libGLESv2.map.txt", first_version: "9", unversioned_until: "current", - export_header_libs: [ - "libGLESv2_headers", - ], } ndk_library { @@ -70,9 +61,6 @@ ndk_library { 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 3ef5049230..da1aae2acb 100644 --- a/services/audiomanager/IAudioManager.cpp +++ b/services/audiomanager/IAudioManager.cpp @@ -152,6 +152,12 @@ public: 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 1a744abc6d..7628745537 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 @@ GpuWork::~GpuWork() { } 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 @@ AStatsManager_PullAtomCallbackReturn GpuWork::pullWorkAtoms(AStatsEventList* dat 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 @@ AStatsManager_PullAtomCallbackReturn GpuWork::pullWorkAtoms(AStatsEventList* dat } 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 @@ AStatsManager_PullAtomCallbackReturn GpuWork::pullWorkAtoms(AStatsEventList* dat // 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 e70da540b9..60cd2c703e 100644 --- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h +++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h @@ -125,7 +125,7 @@ private: 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 Binary files differnew file mode 100644 index 0000000000..120a34dc01 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-0 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-1 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-1 Binary files differnew file mode 100644 index 0000000000..92d5bdf268 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-1 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-10 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-10 Binary files differnew file mode 100644 index 0000000000..c044c844be --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-10 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-11 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-11 Binary files differnew file mode 100644 index 0000000000..430552e625 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-11 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-12 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-12 Binary files differnew file mode 100644 index 0000000000..f7849bbe02 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-12 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-13 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-13 Binary files differnew file mode 100644 index 0000000000..2f0a655224 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-13 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-14 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-14 Binary files differnew file mode 100644 index 0000000000..bd8fb017db --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-14 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-15 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-15 Binary files differnew file mode 100644 index 0000000000..29aa2b1a40 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-15 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-16 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-16 Binary files differnew file mode 100644 index 0000000000..e00100f5c2 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-16 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-17 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-17 Binary files differnew file mode 100644 index 0000000000..db281e13fa --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-17 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-18 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-18 Binary files differnew file mode 100644 index 0000000000..5592c32a54 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-18 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-2 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-2 Binary files differnew file mode 100644 index 0000000000..5bd2b993dc --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-2 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-3 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-3 Binary files differnew file mode 100644 index 0000000000..2d89289137 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-3 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-4 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-4 Binary files differnew file mode 100644 index 0000000000..8f3f1c212a --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-4 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-5 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-5 Binary files differnew file mode 100644 index 0000000000..95b05e79ae --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-5 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-6 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-6 Binary files differnew file mode 100644 index 0000000000..497a5019a9 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-6 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-7 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-7 Binary files differnew file mode 100644 index 0000000000..9902bdec7a --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-7 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-8 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-8 Binary files differnew file mode 100644 index 0000000000..fdaaf311b5 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-8 diff --git a/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-9 b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-9 Binary files differnew file mode 100644 index 0000000000..a197c6ad7b --- /dev/null +++ b/services/gpuservice/tests/fuzzers/corpus/seed-2024-08-29-9 diff --git a/services/inputflinger/InputFilter.cpp b/services/inputflinger/InputFilter.cpp index e4d73fc974..2ef94fbb07 100644 --- a/services/inputflinger/InputFilter.cpp +++ b/services/inputflinger/InputFilter.cpp @@ -60,6 +60,7 @@ void InputFilter::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& 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::notifyConfigurationChangedLocked() { 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 41e5247b50..b155122749 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -250,6 +250,10 @@ void InputManager::dump(std::string& dump) { 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 b9e6a03560..5b0b9ac5ef 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 @@ package com.android.server.inputflinger; 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 994d1c4b1a..31b72319ac 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 @@ interface IInputFilter { /** 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 bcef35021e..250e72cfa8 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 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { 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 a3650030ac..688196461a 100644 --- a/services/inputflinger/dispatcher/InputEventTimeline.cpp +++ b/services/inputflinger/dispatcher/InputEventTimeline.cpp @@ -66,15 +66,16 @@ bool ConnectionTimeline::operator!=(const ConnectionTimeline& rhs) const { 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 @@ bool InputEventTimeline::operator==(const InputEventTimeline& rhs) const { 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 1756944d0e..951fcc8d0c 100644 --- a/services/inputflinger/dispatcher/InputEventTimeline.h +++ b/services/inputflinger/dispatcher/InputEventTimeline.h @@ -74,15 +74,38 @@ private: 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 e09d97a13b..4ddd2e9e95 100644 --- a/services/inputflinger/dispatcher/LatencyAggregator.cpp +++ b/services/inputflinger/dispatcher/LatencyAggregator.cpp @@ -134,7 +134,9 @@ void LatencyAggregator::processStatistics(const InputEventTimeline& timeline) { 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 @@ void LatencyAggregator::processSlowEvent(const InputEventTimeline& timeline) { 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 698bd9ff08..69024b326a 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.cpp +++ b/services/inputflinger/dispatcher/LatencyTracker.cpp @@ -67,9 +67,10 @@ LatencyTracker::LatencyTracker(InputEventTimelineProcessor* processor) 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 @@ void LatencyTracker::trackListener(int32_t inputEventId, bool isDown, nsecs_t ev 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 890d61d431..b4053ba1b3 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.h +++ b/services/inputflinger/dispatcher/LatencyTracker.h @@ -52,8 +52,9 @@ public: * 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 dbc28721d1..b17e79a250 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -425,7 +425,7 @@ std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent& rawEvent) { 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 9924d0d491..da2c683d95 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -60,6 +60,21 @@ uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) { } } +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 @@ GestureConverter::GestureConverter(InputReaderContext& readerContext, : 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 @@ std::list<NotifyArgs> GestureConverter::handleScroll(nsecs_t when, nsecs_t readT 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 @@ std::list<NotifyArgs> GestureConverter::handleScroll(nsecs_t when, nsecs_t readT 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 @@ std::list<NotifyArgs> GestureConverter::endScroll(nsecs_t when, nsecs_t readTime 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 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime 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 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime /* 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 829fb9289b..c9a35c151f 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -99,6 +99,7 @@ private: 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 2d5039a1b1..e05e8e512f 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 @@ pub struct BounceKeysFilter { 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 @@ impl BounceKeysFilter { 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 BounceKeysFilter { 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 @@ impl Filter for BounceKeysFilter { 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 @@ impl Filter for BounceKeysFilter { 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 @@ mod tests { Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ + KeyboardType::Alphabetic, ); let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT }; @@ -181,12 +203,103 @@ mod tests { } #[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 @@ mod tests { Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ + KeyboardType::NonAlphabetic, ); let event = @@ -233,12 +347,60 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { 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 8b44af38db..e2212449aa 100644 --- a/services/inputflinger/rust/input_filter.rs +++ b/services/inputflinger/rust/input_filter.rs @@ -35,11 +35,15 @@ use input::ModifierState; 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 @@ impl IInputFilter for InputFilter { 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 @@ impl Filter for BaseFilter { 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 @@ mod tests { InputFilterConfiguration::InputFilterConfiguration, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction, }; + use input::KeyboardType; use std::sync::{Arc, RwLock}; #[test] @@ -256,7 +278,11 @@ mod tests { 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 @@ pub mod test_filter { 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 0f18a2f395..8830aac529 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 OngoingKeyDown { 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 @@ impl SlowKeysFilter { 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 @@ impl Filter for SlowKeysFilter { { // 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 @@ impl Filter for SlowKeysFilter { 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 @@ impl Filter for SlowKeysFilter { 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 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { test_thread.clone(), 1, /* device_id */ SLOW_KEYS_THRESHOLD_NS, + KeyboardType::NonAlphabetic, ); let event = @@ -275,6 +296,115 @@ mod tests { } #[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 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { 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 6c7c7fba39..161a5fca60 100644 --- a/services/inputflinger/rust/sticky_keys_filter.rs +++ b/services/inputflinger/rust/sticky_keys_filter.rs @@ -134,6 +134,14 @@ impl Filter for StickyKeysFilter { 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 @@ mod tests { DeviceInfo::DeviceInfo, IInputFilter::IInputFilterCallbacks::IInputFilterCallbacks, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction, }; + use input::KeyboardType; use input::ModifierState; use std::sync::{Arc, RwLock}; @@ -496,7 +505,11 @@ mod tests { ..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 b738abf6d2..f20c43c523 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 @@ TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { 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 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partia 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 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partia 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 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerAndPalmTurningIntoFinger_report 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 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { 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 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { 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 @@ TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) { 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 @@ TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) { 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 @@ TEST_F(CapturedTouchpadEventConverterTest, 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 @@ TEST_F(CapturedTouchpadEventConverterTest, ButtonPressedBeforeTouch_ReportedOnce 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 @@ TEST_F(CapturedTouchpadEventConverterTest, ButtonReleasedAfterTouchLifts_Reporte 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 @@ TEST_F(CapturedTouchpadEventConverterTest, MultipleButtonsPressedDuringTouch_Rep 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 d77d539f74..e1f844c571 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -32,19 +32,23 @@ static const int HW_TIMEOUT_MULTIPLIER = base::GetIntProperty("ro.hw_timeout_mul } // 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 @@ std::string FakeInputReaderPolicy::getDeviceAlias(const InputDeviceIdentifier&) 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 e5ba620555..61bb9fcb25 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -88,7 +88,8 @@ private: 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 d0cd677ade..225ae0f67c 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -279,6 +279,8 @@ TEST_F(GestureConverterTest, DragWithButton) { } 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 @@ TEST_F(GestureConverterTest, Scroll) { 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 @@ TEST_F(GestureConverterTest, Scroll) { 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 @@ TEST_F(GestureConverterTest, Scroll) { 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, FourFingerSwipe_Horizontal) { } 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 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { 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 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { 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 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { 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_Inwards) { } 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 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { 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 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { 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 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { 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, ResetWithButtonPressed) { } 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 @@ TEST_F(GestureConverterTest, ResetDuringScroll) { 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 2ccd93ec4c..3cc4bdd79e 100644 --- a/services/inputflinger/tests/InputTracingTest.cpp +++ b/services/inputflinger/tests/InputTracingTest.cpp @@ -133,8 +133,8 @@ protected: 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 @@ protected: } } - 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 4fcffddee2..0f92833e64 100644 --- a/services/inputflinger/tests/LatencyTracker_test.cpp +++ b/services/inputflinger/tests/LatencyTracker_test.cpp @@ -61,12 +61,12 @@ const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds( 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 @@ private: 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 @@ void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTim * 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 @@ TEST_F(LatencyTrackerTest, TrackAllParameters_ReportsFullTimeline) { 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, TrackAllParameters_ReportsFullTimeline) { 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, WhenDuplicateEventsAreReported_DoesNotCrash) { 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 @@ TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) { 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 @@ TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) { 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 @@ TEST_F(LatencyTrackerTest, IncompleteEvents_AreHandledConsistently) { 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 @@ TEST_F(LatencyTrackerTest, EventsAreTracked_WhenTrackListenerIsCalledFirst) { 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, EventsAreTracked_WhenTrackListenerIsCalledFirst) { 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 082bbb8136..d2337dd92c 100644 --- a/services/inputflinger/tests/TestConstants.h +++ b/services/inputflinger/tests/TestConstants.h @@ -25,7 +25,10 @@ namespace android { 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 6daeaafbb3..695eb3c5dd 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 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { 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 130c112fd2..f56642b77c 100644 --- a/services/sensorservice/SensorEventConnection.cpp +++ b/services/sensorservice/SensorEventConnection.cpp @@ -172,7 +172,7 @@ bool SensorService::SensorEventConnection::addSensor(int32_t handle) { 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 dc9e8215e7..a8a773ad6b 100644 --- a/services/sensorservice/SensorRegistrationInfo.h +++ b/services/sensorservice/SensorRegistrationInfo.h @@ -38,10 +38,11 @@ public: 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 @@ public: 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 @@ private: 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 3895ffe55e..060508ca25 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -708,7 +708,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { 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 @@ sp<ISensorEventConnection> SensorService::createSensorEventConnection(const Stri // 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 @@ sp<ISensorEventConnection> SensorService::createSensorEventConnection(const Stri // 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 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, 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 @@ status_t SensorService::disable(const sp<SensorEventConnection>& connection, int 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 b0b1a02164..eb6e677117 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 @@ public: 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 629d9f23ff..e910c72e2e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -51,7 +51,8 @@ public: 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 @@ public: 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 0eced73ff9..66237b9d8a 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -60,6 +60,7 @@ using AidlDisplayCapability = aidl::android::hardware::graphics::composer3::Disp 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 @@ public: 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 @@ Error AidlComposer::getClientTargetProperty( 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 @@ Error AidlComposer::getDisplayLuts(Display display, std::vector<Lut>* outLuts) { 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 3669d4c996..246223a668 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -244,9 +244,13 @@ public: 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 888dc08134..7db9a94e54 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 @@ public: 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 d5f65c6211..f1fa9389eb 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -41,6 +41,7 @@ using aidl::android::hardware::graphics::composer3::Color; 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 @@ Error Display::getClientTargetProperty( 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::loadDisplayCapabilities() { } }); } + +void Display::setPhysicalSizeInMm(std::optional<ui::Size> size) { + mPhysicalSize = size; +} + } // namespace impl // Layer methods @@ -1050,6 +1057,14 @@ Error Layer::setBlockingRegion(const Region& region) { 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 be2059a935..8e2aeaf234 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -67,6 +67,7 @@ class Layer; 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 @@ struct ComposerCallback { 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 @@ public: 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 @@ public: [[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 @@ public: 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 @@ public: 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 @@ private: 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 @@ public: // 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 @@ public: // 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 73fa855c3c..bd093f52cf 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -76,6 +76,7 @@ using aidl::android::hardware::graphics::common::HdrConversionCapability; 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 @@ bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size 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 @@ void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, 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 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId d 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 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromDisplayConfigura .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 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromLegacyDisplayCon 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 @@ status_t HWComposer::getDeviceCompositionChanges( 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 @@ status_t HWComposer::getDisplayDecorationSupport( 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 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( 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 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( } 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 9368b7b6dd..b95c619f75 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 @@ public: // 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ private: 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 ec2a3ec024..ee1e07ae7d 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -46,6 +46,7 @@ using aidl::android::hardware::graphics::composer3::Capability; 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 @@ Error HidlComposer::getClientTargetProperty( 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 8bca5ad31f..701a54bc66 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -351,8 +351,12 @@ public: 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 2a0ee5a993..47b811b721 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -38,6 +38,8 @@ using base::StringAppendF; 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 @@ nsecs_t getMinTime(PredictionState predictionState, TimelineItem predictions, 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 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, 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 @@ void SurfaceFrame::onCommitNotComposited(Fps refreshRate, Fps displayFrameRender 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 @@ void SurfaceFrame::tracePredictions(int64_t displayFrameToken, nsecs_t monoBootO 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 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffse 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 @@ void SurfaceFrame::trace(int64_t displayFrameToken, nsecs_t monoBootOffset) cons 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 @@ std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) } 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::onCommitNotComposited() { } } -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 @@ void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid, 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 @@ void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs (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 @@ void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs // 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 @@ void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs 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 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid, 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 @@ nsecs_t FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t mono 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 @@ void FrameTimeline::flushPendingPresentFences() { 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 @@ void FrameTimeline::flushPendingPresentFences() { 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 94cfcb40b9..cffb61ee10 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -214,7 +214,8 @@ public: // 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 @@ public: 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 @@ private: 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 @@ public: // 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 @@ public: 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 @@ public: }; 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 @@ private: 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 e5cca8fa95..4af27ab84d 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 636f7bdabf..c8bb068fa9 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 @@ constexpr int kDumpTableRowLength = 159; 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 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) : 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 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) 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 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) 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 @@ Layer::~Layer() { 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 @@ Layer::~Layer() { 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 @@ Layer::~Layer() { } // --------------------------------------------------------------------------- -// 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 @@ sp<IBinder> Layer::getHandle() { // 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 @@ bool Layer::computeTrustedPresentationState(const FloatRect& bounds, const Float 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 @@ Rect Layer::getCroppedBufferSize(const State& s) const { 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 @@ aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionT } // ---------------------------------------------------------------------------- -// 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 @@ void Layer::setTransactionFlags(uint32_t mask) { 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 @@ bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { 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 @@ void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInf gui::GameMode gameMode) { mDrawingState.frameTimelineInfo = info; mDrawingState.postTime = postTime; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); if (const auto& bufferSurfaceFrameTX = mDrawingState.bufferSurfaceFrameTX; @@ -1315,40 +561,6 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const { 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 @@ void Layer::getFrameStats(FrameStats* outStats) const { 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::writeCompositionStateToProto(perfetto::protos::LayerProto* layerProt } } -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 @@ Region Layer::getVisibleRegion(const DisplayDevice* display) const { 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::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, 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 @@ void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { 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 @@ bool Layer::setTransformToDisplayInverse(bool transformToDisplayInverse) { if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false; mDrawingState.sequence++; mDrawingState.transformToDisplayInverse = transformToDisplayInverse; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -2704,97 +873,7 @@ bool Layer::setBufferCrop(const Rect& bufferCrop) { 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; } @@ -2861,7 +940,6 @@ bool Layer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer, mDrawingState.isAutoTimestamp = isAutoTimestamp; mDrawingState.latchedVsyncId = info.vsyncId; mDrawingState.useVsyncIdForRefreshRateSelection = info.useForRefreshRateSelection; - mDrawingState.modified = true; if (!buffer) { resetDrawingStateBufferInfo(); setTransactionFlags(eTransactionNeeded); @@ -3009,7 +1087,6 @@ void Layer::recordLayerHistoryAnimationTx(const scheduler::LayerProps& layerProp 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 @@ bool Layer::setExtendedRangeBrightness(float currentBufferRatio, float desiredRa return false; mDrawingState.currentHdrSdrRatio = currentBufferRatio; mDrawingState.desiredHdrSdrRatio = desiredRatio; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -3028,40 +1104,6 @@ bool Layer::setExtendedRangeBrightness(float currentBufferRatio, float desiredRa 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 @@ bool Layer::setSidebandStream(const sp<NativeHandle>& sidebandStream, const Fram } mDrawingState.sidebandStream = sidebandStream; - mDrawingState.modified = true; if (sidebandStream != nullptr && mDrawingState.buffer != nullptr) { releasePreviousBuffer(); resetDrawingStateBufferInfo(); @@ -3174,14 +1215,6 @@ Rect Layer::getBufferSize(const State& /*s*/) const { 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::onPreComposition(nsecs_t refreshStartTime) { } } -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 @@ void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) { mFlinger->getTransactionCallbackInvoker() .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles); mDrawingState.callbackHandles = remainingHandles; - - mDrawingStateModified = false; } void Layer::gatherBufferInfo() { @@ -3305,7 +1320,6 @@ void Layer::gatherBufferInfo() { 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 @@ void Layer::gatherBufferInfo() { 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 @@ Rect Layer::computeBufferCrop(const State& s) { } } -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 @@ void Layer::tracePendingBufferCount(int32_t pendingBuffers) { 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 @@ sp<LayerFE> Layer::getCompositionEngineLayerFE( 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 @@ bool Layer::willReleaseBufferOnLatch() const { 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 @@ bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bo // 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 @@ bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bo if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) || (mBufferInfo.mTransform != oldBufferInfo.mTransform) || - (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) || (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) { recomputeVisibleRegions = true; } @@ -3893,35 +1552,14 @@ bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bo 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 @@ uint32_t Layer::getBufferTransform() const { 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 @@ sp<GraphicBuffer> Layer::getBuffer() const { 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 @@ bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thre 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 f6eed6332b..9caa20cfb8 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 @@ public: 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 @@ public: 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 @@ public: // 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 @@ public: 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 @@ public: // 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 @@ public: 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 @@ public: * 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 @@ public: 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 @@ public: 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 @@ public: */ 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 @@ public: 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 @@ public: 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 @@ public: // 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 @@ public: // 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 @@ public: */ 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ protected: 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 @@ protected: // 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 @@ protected: // 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: // 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 @@ private: // 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 0d2987c94a..5eea45b436 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -178,7 +178,7 @@ void LayerProtoHelper::writeToProto( } 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 @@ void LayerProtoHelper::writeToProto( 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 @@ void LayerProtoHelper::readFromProto(const perfetto::protos::BlurRegion& proto, 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 @@ perfetto::protos::LayersProto LayerProtoFromSnapshotGenerator::generate( } } - 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 @@ void LayerProtoHelper::writeSnapshotToProto(perfetto::protos::LayerProto* layerI 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 d6720123ac..41ea68420f 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -62,7 +62,7 @@ public: 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 @@ public: 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 f52e60deda..13e054e249 100644 --- a/services/surfaceflinger/LayerVector.cpp +++ b/services/surfaceflinger/LayerVector.cpp @@ -45,51 +45,12 @@ int LayerVector::do_compare(const void* lhs, const void* rhs) const 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 a531f4fd95..38dc11d3bc 100644 --- a/services/surfaceflinger/LayerVector.h +++ b/services/surfaceflinger/LayerVector.h @@ -46,11 +46,8 @@ public: // 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 034e467be9..aa66ccf172 100644 --- a/services/surfaceflinger/RenderArea.h +++ b/services/surfaceflinger/RenderArea.h @@ -39,21 +39,6 @@ public: 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 d31fceab7e..218c56ef3d 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -320,7 +320,8 @@ void EventThread::setDuration(std::chrono::nanoseconds workDuration, 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 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { } 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 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, } 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 @@ void EventThread::dump(std::string& result) const { 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 @@ scheduler::VSyncCallbackRegistration EventThread::onNewVsyncScheduleInternal( 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 f772126349..bbe4f9d899 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -220,6 +220,7 @@ private: 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 dbc458cb7f..ff1926e03f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -595,8 +595,7 @@ bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { 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 9f6eab288b..ab9014e418 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -841,7 +841,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi 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 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi 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 @@ auto RefreshRateSelector::setPolicy(const PolicyVariant& policy) -> SetPolicyRes 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 566bb8ede8..be00079b9c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -127,7 +127,7 @@ void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) { 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::setDuration(Cycle cycle, std::chrono::nanoseconds workDuration, } } -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 88f0e9435a..1367ec385e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -187,7 +187,7 @@ public: } } - 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 0c43ffbc04..8993c38d37 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -93,6 +93,8 @@ public: * 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 @@ public: 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 900bce0aa9..1925f1165c 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -103,7 +103,8 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTim 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 @@ void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { 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 @@ void VSyncDispatchTimerQueueEntry::dump(std::string& result) const { 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 4a7cff58dd..6e36f02463 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -695,9 +695,12 @@ std::optional<TimePoint> VSyncPredictor::VsyncTimeline::nextAnticipatedVSyncTime 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 7590d981d4..c794a7ba43 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -532,9 +532,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI 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 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& displayToken, 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 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) { // 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 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { 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 @@ void SurfaceFlinger::applyActiveMode(PhysicalDisplayId displayId) { 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 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t 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 @@ void SurfaceFlinger::onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId, 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::onRefreshRateChangedDebug(const RefreshRateChangedDebugData })); } +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 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, { // 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 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, } 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 SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, 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 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( 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 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( 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 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( 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 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, 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 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { // Commit display transactions. const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; mFrontEndDisplayInfosChanged = displayTransactionNeeded; - mForceTransactionDisplayChange = displayTransactionNeeded; if (mSomeChildrenChanged) { mVisibleRegionsDirty = true; @@ -4252,6 +4234,8 @@ void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId display if (data.hintStatus.compare_exchange_strong(scheduleHintOnTx, NotifyExpectedPresentHintStatus::Sent)) { sendHint(); + constexpr bool kAllowToEnable = true; + mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable); } })); } @@ -4352,55 +4336,8 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { 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 @@ status_t SurfaceFlinger::addClientLayer(LayerCreationArgs& args, const sp<IBinde 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 @@ void SurfaceFlinger::addTransactionReadyFilters() { } // 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 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f } } + 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 @@ status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args, if (result != NO_ERROR) { return result; } - - mirrorLayer->setClonedChild(mirrorFrom->createClone()); } outResult.layerId = mirrorLayer->sequence; @@ -5284,33 +5221,22 @@ status_t SurfaceFlinger::createEffectLayer(const LayerCreationArgs& args, sp<IBi 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 @@ perfetto::protos::LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t tra } } - 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 @@ void SurfaceFlinger::dumpHwc(std::string& result) const { 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 @@ static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) { 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::captureLayers(const LayerCaptureArgs& args, 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::traverseLegacyLayers(const LayerVector::Visitor& visitor) c // --------------------------------------------------------------------------- -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 @@ status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp<IBinder>& displayTo 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 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) con 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 @@ perfetto::protos::LayersSnapshotProto SurfaceFlinger::takeLayersSnapshotProto( 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 7fb5c36aad..3eb72cc4c0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -135,6 +135,7 @@ class FrameTracer; 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 @@ public: // 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 @@ private: 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 @@ private: } 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: // 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 @@ private: }; bool mIsHdcpViaNegVsync = false; - bool mIsHotplugErrViaNegVsync = false; std::mutex mHotplugMutex; std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex); @@ -1393,13 +1379,6 @@ private: 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 @@ private: 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 617ea2c566..1dba17585c 100644 --- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp @@ -162,7 +162,10 @@ bool LayerTraceGenerator::generate(const perfetto::protos::TransactionTraceFile& 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 881bf35b58..c6856aea75 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -149,6 +149,13 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& 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::addPresentFence(sp<Fence> presentFence) { } 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 7853a9f359..14a7487156 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 @@ public: 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 @@ private: 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 8ec908fffd..12d6138675 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -119,7 +119,6 @@ void FlagManager::dump(std::string& result) const { 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 @@ void FlagManager::dump(std::string& result) const { 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_LEGACY_SERVER_FLAG(use_skia_tracing, PROPERTY_SKIA_ATRACE_ENABLED, 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_24q4, ""); 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 473e564903..a1be19421b 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -56,7 +56,6 @@ public: /// 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 @@ public: 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 0ff846e744..102e2b643c 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -4,10 +4,10 @@ package: "com.android.graphics.surfaceflinger.flags" 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 @@ flag { } } # 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 @@ flag { } } # deprecate_vsync_sf - flag { +flag { name: "detached_mirror" namespace: "window_surfaces" description: "Ignore local transform when mirroring a partial hierarchy" @@ -55,6 +66,17 @@ flag { } # 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 @@ flag { } # 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 @@ flag { } # 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 @@ flag { } # 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 56f2f1b07a..7857961ce4 100644 --- a/services/surfaceflinger/tests/OWNERS +++ b/services/surfaceflinger/tests/OWNERS @@ -4,5 +4,5 @@ per-file HdrSdrRatioOverlay_test.cpp = alecmouri@google.com, sallyqi@google.com, 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 3104dd4720..ae380ad459 100644 --- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h +++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h @@ -515,6 +515,23 @@ public: 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 9be0fc38b3..0dfbd6185e 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -84,9 +84,11 @@ public: 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 2cff2f2929..e0753a3cfb 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -58,6 +58,7 @@ using namespace std::chrono_literals; 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 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { 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 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { 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 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { 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 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_OFF) { 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 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_OFF) { 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 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { 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 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { 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 @@ struct MockHWC2ComposerCallback final : StrictMock<HWC2::ComposerCallback> { 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 7e84408f7d..de37b6342c 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -894,7 +894,6 @@ TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitCategory) { 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 2860345538..90207232b0 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 @@ TEST_F(LayerSnapshotTest, hideLayerWithNanMatrix) { UPDATE_AND_VERIFY(mSnapshotBuilder, {2}); EXPECT_TRUE(getSnapshot(1)->isHiddenByPolicy()); } +TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) { + if (!com::android::graphics::libgui::flags::edge_extension_shader()) { + GTEST_SKIP() << "Skipping test because edge_extension_shader is off"; + } + 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 06c4e30989..9efe73d450 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -1837,6 +1837,43 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_12 } } +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 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighH // 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 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch 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 358f6b0cf5..45ca7e2f59 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -884,7 +884,6 @@ TEST_F(AttachedChoreographerTest, removedWhenLayerIsGone) { 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 933d03dac1..352000ef9a 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -239,7 +239,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { 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 aa9af5d4ca..725354b845 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -335,13 +335,6 @@ public: 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 @@ public: (*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 @@ public: } 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 @@ public: } 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 @@ public: 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 7bf167498b..f8f08c78fd 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 9f6065b683..e27af0e62c 100644 --- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp @@ -128,12 +128,10 @@ TEST_F(TunnelModeEnabledReporterTest, callsNewListenerWithFreshInformation) { 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 @@ TEST_F(TunnelModeEnabledReporterTest, layerWithSidebandStreamTriggersUpdate) { 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 7c678bd811..918107d270 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -915,7 +915,8 @@ TEST_F(VSyncPredictorTest, adjustsVrrTimeline) { 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 e380e19797..f472d8fefe 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -180,8 +180,12 @@ public: 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 1eda3586c5..5edd2cd9e3 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -35,6 +35,7 @@ public: (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 @@ public: 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 @@ public: (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 fdb6f4dafe..45f86fa1a8 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -31,15 +31,11 @@ public: 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 3d8124b81b..4ac16188fa 100644 --- a/services/vibratorservice/VibratorHalWrapper.cpp +++ b/services/vibratorservice/VibratorHalWrapper.cpp @@ -96,6 +96,17 @@ Info HalWrapper::getInfo() { 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 @@ HalResult<std::vector<float>> HalWrapper::getMaxAmplitudesInternal() { 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 @@ HalResult<std::vector<float>> AidlHalWrapper::getMaxAmplitudesInternal() { 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 ae0d9ab411..4938b156e7 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h @@ -258,6 +258,9 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: mResonantFrequency, mFrequencyResolution, mQFactor, - mMaxAmplitudes}; + mMaxAmplitudes, + mMaxEnvelopeEffectSize, + mMinEnvelopeEffectControlPointDuration, + mMaxEnvelopeEffectControlPointDuration}; } private: @@ -340,6 +354,11 @@ private: 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 @@ protected: 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 @@ protected: 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 ba7e1f07bf..17f384d320 100644 --- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp @@ -235,6 +235,9 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { 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 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { .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 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { 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 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { 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 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { 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 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { 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 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { 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 83430d79a5..a09ddecf91 100644 --- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp @@ -220,6 +220,9 @@ TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoDoesNotCacheFailedResult) { 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 @@ TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoCachesResult) { 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 436e6c6b7c..879d2d0fa7 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -27,9 +27,18 @@ ndk_library { 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 @@ cc_library_shared { "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 a3fe33e67e..9ff0b46c0f 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 4998018882..b468a8911b 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 ef213f0c7a..01436db4ae 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 @@ void CreateInfoWrapper::FilterExtension(const char* name) { 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 @@ void CreateInfoWrapper::FilterExtension(const char* name) { 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 @@ VkResult EnumerateDeviceExtensionProperties( 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 8f090083f8..f741977d50 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 @@ ProcHook::Extension GetProcHookExtension(const char* name) { 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 4527214c3f..649c0f1a17 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 @@ struct ProcHook { 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 0000000000..891bc0261b --- /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 00e987fb2e..09b0a145af 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1215,8 +1215,15 @@ VkResult GetPhysicalDeviceSurfaceFormats2KHR( 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 @@ static VkResult getProducerUsage(const VkDevice& device, .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 @@ VkResult CreateSwapchainKHR(VkDevice device, 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 @@ VkResult CreateSwapchainKHR(VkDevice device, 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 @@ VkResult CreateSwapchainKHR(VkDevice device, .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 @@ VkResult CreateSwapchainKHR(VkDevice device, // 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 @@ VkResult CreateSwapchainKHR(VkDevice device, 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 d34851e536..40a45af94e 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 fb3bd05e07..0d1e223226 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 be24172eed..001af208a8 100644 --- a/vulkan/scripts/api_generator.py +++ b/vulkan/scripts/api_generator.py @@ -61,6 +61,9 @@ def gen_h(): #include "driver_gen.h" +/* + * This file is autogenerated by api_generator.py. Do not edit directly. + */ namespace vulkan { namespace api { @@ -283,6 +286,9 @@ def gen_cpp(): #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 48c0ae9304..61595993f1 100644 --- a/vulkan/scripts/driver_generator.py +++ b/vulkan/scripts/driver_generator.py @@ -49,6 +49,7 @@ _KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [ '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 @@ def gen_h(): #include <optional> #include <vector> +/* + * This file is autogenerated by driver_generator.py. Do not edit directly. + */ namespace vulkan { namespace driver { @@ -503,6 +507,9 @@ def gen_cpp(): 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 3624c1d032..5c5bea316b 100644 --- a/vulkan/scripts/null_generator.py +++ b/vulkan/scripts/null_generator.py @@ -55,6 +55,9 @@ def gen_h(): #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 @@ def gen_cpp(): using namespace null_driver; +/* + * This file is autogenerated by null_generator.py. Do not edit directly. + */ namespace { struct NameProc { |