Merge "[native] Migrate deprecated GL GrSurfaceBackend related functions" into main
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 4842312..615701c 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -207,9 +207,7 @@
int PropertiesHelper::dry_run_ = -1;
int PropertiesHelper::unroot_ = -1;
int PropertiesHelper::parallel_run_ = -1;
-#if !defined(__ANDROID_VNDK__)
int PropertiesHelper::strict_run_ = -1;
-#endif
bool PropertiesHelper::IsUserBuild() {
if (build_type_.empty()) {
@@ -240,7 +238,6 @@
return parallel_run_ == 1;
}
-#if !defined(__ANDROID_VNDK__)
bool PropertiesHelper::IsStrictRun() {
if (strict_run_ == -1) {
// Defaults to using stricter timeouts.
@@ -248,7 +245,6 @@
}
return strict_run_ == 1;
}
-#endif
int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 6049e3e..9e955e3 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -198,18 +198,14 @@
* will default to true. This results in shortened timeouts for flaky
* sections.
*/
-#if !defined(__ANDROID_VNDK__)
static bool IsStrictRun();
-#endif
private:
static std::string build_type_;
static int dry_run_;
static int unroot_;
static int parallel_run_;
-#if !defined(__ANDROID_VNDK__)
static int strict_run_;
-#endif
};
/*
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 818fd80..27ae8f6 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -560,61 +560,6 @@
return Dexopt();
}
- ////////////////////////////////////
- // Helpers, mostly taken from ART //
- ////////////////////////////////////
-
- // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
- static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
- constexpr size_t kPageSize = PAGE_SIZE;
- static_assert(IsPowerOfTwo(kPageSize), "page size must be power of two");
- CHECK_EQ(min_delta % kPageSize, 0u);
- CHECK_EQ(max_delta % kPageSize, 0u);
- CHECK_LT(min_delta, max_delta);
-
- std::default_random_engine generator;
- generator.seed(GetSeed());
- std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta);
- int32_t r = distribution(generator);
- if (r % 2 == 0) {
- r = RoundUp(r, kPageSize);
- } else {
- r = RoundDown(r, kPageSize);
- }
- CHECK_LE(min_delta, r);
- CHECK_GE(max_delta, r);
- CHECK_EQ(r % kPageSize, 0u);
- return r;
- }
-
- static uint64_t GetSeed() {
-#ifdef __BIONIC__
- // Bionic exposes arc4random, use it.
- uint64_t random_data;
- arc4random_buf(&random_data, sizeof(random_data));
- return random_data;
-#else
-#error "This is only supposed to run with bionic. Otherwise, implement..."
-#endif
- }
-
- void AddCompilerOptionFromSystemProperty(const char* system_property,
- const char* prefix,
- bool runtime,
- std::vector<std::string>& out) const {
- const std::string* value = system_properties_.GetProperty(system_property);
- if (value != nullptr) {
- if (runtime) {
- out.push_back("--runtime-arg");
- }
- if (prefix != nullptr) {
- out.push_back(StringPrintf("%s%s", prefix, value->c_str()));
- } else {
- out.push_back(*value);
- }
- }
- }
-
static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
static constexpr const char* kAndroidDataPathPropertyName = "ANDROID_DATA";
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index c86993c..c40caf5 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -19,9 +19,12 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/wait.h>
+#include <unistd.h>
+#include <algorithm>
#include <array>
#include <fstream>
+#include <iostream>
#include <sstream>
#include <android-base/file.h>
@@ -29,6 +32,7 @@
#include <android-base/macros.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <libdm/dm.h>
#include <selinux/android.h>
@@ -37,7 +41,7 @@
#include "otapreopt_utils.h"
#ifndef LOG_TAG
-#define LOG_TAG "otapreopt"
+#define LOG_TAG "otapreopt_chroot"
#endif
using android::base::StringPrintf;
@@ -49,20 +53,22 @@
// so just try the possibilities one by one.
static constexpr std::array kTryMountFsTypes = {"ext4", "erofs"};
-static void CloseDescriptor(int fd) {
- if (fd >= 0) {
- int result = close(fd);
- UNUSED(result); // Ignore result. Printing to logcat will open a new descriptor
- // that we do *not* want.
- }
-}
-
static void CloseDescriptor(const char* descriptor_string) {
int fd = -1;
std::istringstream stream(descriptor_string);
stream >> fd;
if (!stream.fail()) {
- CloseDescriptor(fd);
+ if (fd >= 0) {
+ if (close(fd) < 0) {
+ PLOG(ERROR) << "Failed to close " << fd;
+ }
+ }
+ }
+}
+
+static void SetCloseOnExec(int fd) {
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+ PLOG(ERROR) << "Failed to set FD_CLOEXEC on " << fd;
}
}
@@ -129,24 +135,39 @@
}
// Entry for otapreopt_chroot. Expected parameters are:
-// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
-// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
-// be passed on to otapreopt in the chroot.
+//
+// [cmd] [status-fd] [target-slot-suffix]
+//
+// The file descriptor denoted by status-fd will be closed. Dexopt commands on
+// the form
+//
+// "dexopt" [dexopt-params]
+//
+// are then read from stdin until EOF and passed on to /system/bin/otapreopt one
+// by one. After each call a line with the current command count is written to
+// stdout and flushed.
static int otapreopt_chroot(const int argc, char **arg) {
// Validate arguments
- // We need the command, status channel and target slot, at a minimum.
- if(argc < 3) {
- PLOG(ERROR) << "Not enough arguments.";
+ if (argc == 2 && std::string_view(arg[1]) == "--version") {
+ // Accept a single --version flag, to allow the script to tell this binary
+ // from the earlier one.
+ std::cout << "2" << std::endl;
+ return 0;
+ }
+ if (argc != 3) {
+ LOG(ERROR) << "Wrong number of arguments: " << argc;
exit(208);
}
- // Close all file descriptors. They are coming from the caller, we do not want to pass them
- // on across our fork/exec into a different domain.
- // 1) Default descriptors.
- CloseDescriptor(STDIN_FILENO);
- CloseDescriptor(STDOUT_FILENO);
- CloseDescriptor(STDERR_FILENO);
- // 2) The status channel.
- CloseDescriptor(arg[1]);
+ const char* status_fd = arg[1];
+ const char* slot_suffix = arg[2];
+
+ // Set O_CLOEXEC on standard fds. They are coming from the caller, we do not
+ // want to pass them on across our fork/exec into a different domain.
+ SetCloseOnExec(STDIN_FILENO);
+ SetCloseOnExec(STDOUT_FILENO);
+ SetCloseOnExec(STDERR_FILENO);
+ // Close the status channel.
+ CloseDescriptor(status_fd);
// We need to run the otapreopt tool from the postinstall partition. As such, set up a
// mount namespace and change root.
@@ -185,20 +206,20 @@
// 2) We're in a mount namespace here, so when we die, this will be cleaned up.
// 3) Ignore errors. Printing anything at this stage will open a file descriptor
// for logging.
- if (!ValidateTargetSlotSuffix(arg[2])) {
- LOG(ERROR) << "Target slot suffix not legal: " << arg[2];
+ if (!ValidateTargetSlotSuffix(slot_suffix)) {
+ LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
exit(207);
}
- TryExtraMount("vendor", arg[2], "/postinstall/vendor");
+ TryExtraMount("vendor", slot_suffix, "/postinstall/vendor");
// Try to mount the product partition. update_engine doesn't do this for us, but we
// want it for product APKs. Same notes as vendor above.
- TryExtraMount("product", arg[2], "/postinstall/product");
+ TryExtraMount("product", slot_suffix, "/postinstall/product");
// Try to mount the system_ext partition. update_engine doesn't do this for
// us, but we want it for system_ext APKs. Same notes as vendor and product
// above.
- TryExtraMount("system_ext", arg[2], "/postinstall/system_ext");
+ TryExtraMount("system_ext", slot_suffix, "/postinstall/system_ext");
constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig";
// Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot
@@ -329,30 +350,37 @@
exit(218);
}
- // Now go on and run otapreopt.
+ // Now go on and read dexopt lines from stdin and pass them on to otapreopt.
- // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc
- // Outgoing: cmd + target-slot + cmd... | Outgoing | = argc - 1
- std::vector<std::string> cmd;
- cmd.reserve(argc);
- cmd.push_back("/system/bin/otapreopt");
+ int count = 1;
+ for (std::array<char, 1000> linebuf;
+ std::cin.clear(), std::cin.getline(&linebuf[0], linebuf.size()); ++count) {
+ // Subtract one from gcount() since getline() counts the newline.
+ std::string line(&linebuf[0], std::cin.gcount() - 1);
- // The first parameter is the status file descriptor, skip.
- for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
- cmd.push_back(arg[i]);
+ if (std::cin.fail()) {
+ LOG(ERROR) << "Command exceeds max length " << linebuf.size() << " - skipped: " << line;
+ continue;
+ }
+
+ std::vector<std::string> tokenized_line = android::base::Tokenize(line, " ");
+ std::vector<std::string> cmd{"/system/bin/otapreopt", slot_suffix};
+ std::move(tokenized_line.begin(), tokenized_line.end(), std::back_inserter(cmd));
+
+ LOG(INFO) << "Command " << count << ": " << android::base::Join(cmd, " ");
+
+ // Fork and execute otapreopt in its own process.
+ std::string error_msg;
+ bool exec_result = Exec(cmd, &error_msg);
+ if (!exec_result) {
+ LOG(ERROR) << "Running otapreopt failed: " << error_msg;
+ }
+
+ // Print the count to stdout and flush to indicate progress.
+ std::cout << count << std::endl;
}
- // Fork and execute otapreopt in its own process.
- std::string error_msg;
- bool exec_result = Exec(cmd, &error_msg);
- if (!exec_result) {
- LOG(ERROR) << "Running otapreopt failed: " << error_msg;
- }
-
- if (!exec_result) {
- exit(213);
- }
-
+ LOG(INFO) << "No more dexopt commands";
return 0;
}
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index e483d54..28bd793 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -16,7 +16,9 @@
# limitations under the License.
#
-# This script will run as a postinstall step to drive otapreopt.
+# This script runs as a postinstall step to drive otapreopt. It comes with the
+# OTA package, but runs /system/bin/otapreopt_chroot in the (old) active system
+# image. See system/extras/postinst/postinst.sh for some docs.
TARGET_SLOT="$1"
STATUS_FD="$2"
@@ -31,12 +33,11 @@
BOOT_COMPLETE=$(getprop $BOOT_PROPERTY_NAME)
if [ "$BOOT_COMPLETE" != "1" ] ; then
- echo "Error: boot-complete not detected."
+ echo "$0: Error: boot-complete not detected."
# We must return 0 to not block sideload.
exit 0
fi
-
# Compute target slot suffix.
# TODO: Once bootctl is not restricted, we should query from there. Or get this from
# update_engine as a parameter.
@@ -45,44 +46,63 @@
elif [ "$TARGET_SLOT" = "1" ] ; then
TARGET_SLOT_SUFFIX="_b"
else
- echo "Unknown target slot $TARGET_SLOT"
+ echo "$0: Unknown target slot $TARGET_SLOT"
exit 1
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
+ # to missing sepolicy rules, so there's no use spending time trying to dexopt
+ # (b/291974157).
+ echo "$0: Current system image is too old to work with OTA preopt - skipping."
+ exit 0
+fi
PREPARE=$(cmd otadexopt prepare)
# Note: Ignore preparation failures. Step and done will fail and exit this.
# This is necessary to support suspends - the OTA service will keep
# the state around for us.
-PROGRESS=$(cmd otadexopt progress)
-print -u${STATUS_FD} "global_progress $PROGRESS"
-
-i=0
-while ((i<MAXIMUM_PACKAGES)) ; do
+# Create an array with all dexopt commands in advance, to know how many there are.
+otadexopt_cmds=()
+while (( ${#otadexopt_cmds[@]} < MAXIMUM_PACKAGES )) ; do
DONE=$(cmd otadexopt done)
if [ "$DONE" = "OTA complete." ] ; then
break
fi
-
- DEXOPT_PARAMS=$(cmd otadexopt next)
-
- /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX $DEXOPT_PARAMS >&- 2>&-
-
- PROGRESS=$(cmd otadexopt progress)
- print -u${STATUS_FD} "global_progress $PROGRESS"
-
- i=$((i+1))
+ otadexopt_cmds+=("$(cmd otadexopt next)")
done
DONE=$(cmd otadexopt done)
+cmd otadexopt cleanup
+
+echo "$0: Using streaming otapreopt_chroot on ${#otadexopt_cmds[@]} packages"
+
+function print_otadexopt_cmds {
+ for cmd in "${otadexopt_cmds[@]}" ; do
+ print "$cmd"
+ done
+}
+
+function report_progress {
+ while read count ; do
+ # mksh can't do floating point arithmetic, so emulate a fixed point calculation.
+ (( permilles = 1000 * count / ${#otadexopt_cmds[@]} ))
+ printf 'global_progress %d.%03d\n' $((permilles / 1000)) $((permilles % 1000)) >&${STATUS_FD}
+ done
+}
+
+print_otadexopt_cmds | \
+ /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX | \
+ report_progress
+
if [ "$DONE" = "OTA incomplete." ] ; then
- echo "Incomplete."
+ echo "$0: Incomplete."
else
- echo "Complete or error."
+ echo "$0: Complete or error."
fi
print -u${STATUS_FD} "global_progress 1.0"
-cmd otadexopt cleanup
exit 0
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 3ce586b..c962c15 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -263,8 +263,8 @@
}
prebuilt_etc {
- name: "android.hardware.threadnetwork.prebuilt.xml",
- src: "android.hardware.threadnetwork.xml",
+ name: "android.hardware.thread_network.prebuilt.xml",
+ src: "android.hardware.thread_network.xml",
defaults: ["frameworks_native_data_etc_defaults"],
}
diff --git a/data/etc/android.hardware.threadnetwork.xml b/data/etc/android.hardware.thread_network.xml
similarity index 83%
rename from data/etc/android.hardware.threadnetwork.xml
rename to data/etc/android.hardware.thread_network.xml
index 9cbdc90..b116ed6 100644
--- a/data/etc/android.hardware.threadnetwork.xml
+++ b/data/etc/android.hardware.thread_network.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- Adds the feature indicating support for the ThreadNetwork API -->
+<!-- Adds the feature indicating support for the Thread networking protocol -->
<permissions>
- <feature name="android.hardware.threadnetwork" />
+ <feature name="android.hardware.thread_network" />
</permissions>
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 0d1503e..383795e 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -129,3 +129,18 @@
],
export_include_dirs: ["include_random_parcel_seeds"],
}
+
+cc_binary_host {
+ name: "binder2corpus",
+ static_libs: [
+ "libbinder_random_parcel_seeds",
+ ],
+ srcs: [
+ "binder2corpus/binder2corpus.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libutils",
+ ],
+}
diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md
new file mode 100644
index 0000000..59bf9f3
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md
@@ -0,0 +1,31 @@
+# binder2corpus
+
+This tool converts recordings generated by record_binder tool to fuzzer seeds for fuzzService.
+
+# Steps to add corpus:
+
+## Start recording the service binder
+ex. record_binder start manager
+
+## Run test on device or keep device idle
+ex. atest servicemanager_test
+
+## Stop the recording
+record_binder stop manager
+
+## Pull the recording on host
+Recordings are present on device at /data/local/recordings/<service_name>. Use adb pull.
+Use inspect command of record_binder to check if there are some transactions captured.
+ex. record_binder inspect manager
+
+## run corpus generator tool
+binder2corpus <recording_path> <dir_to_write_corpus>
+
+## Build fuzzer and sync data directory
+ex. m servicemanager_fuzzer && adb sync data
+
+## Push corpus on device
+ex. adb push servicemanager_fuzzer_corpus/ /data/fuzz/x86_64/servicemanager_fuzzer/
+
+## Run fuzzer with corpus directory as argument
+ex. adb shell /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer_corpus
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp
new file mode 100644
index 0000000..c0fdaea
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/RecordedTransaction.h>
+
+#include <fuzzseeds/random_parcel_seeds.h>
+
+#include <sys/prctl.h>
+
+using android::generateSeedsFromRecording;
+using android::status_t;
+using android::base::unique_fd;
+using android::binder::debug::RecordedTransaction;
+
+status_t generateCorpus(const char* recordingPath, const char* corpusDir) {
+ unique_fd fd(open(recordingPath, O_RDONLY));
+ if (!fd.ok()) {
+ std::cerr << "Failed to open recording file at path " << recordingPath
+ << " with error: " << strerror(errno) << '\n';
+ return android::BAD_VALUE;
+ }
+
+ if (auto res = mkdir(corpusDir, 0766); res != 0) {
+ std::cerr
+ << "Failed to create corpus directory at path. Delete directory if already exists: "
+ << corpusDir << std::endl;
+ return android::BAD_VALUE;
+ }
+
+ int transactionNumber = 0;
+ while (auto transaction = RecordedTransaction::fromFile(fd)) {
+ ++transactionNumber;
+ std::string filePath = std::string(corpusDir) + std::string("transaction_") +
+ std::to_string(transactionNumber);
+ constexpr int openFlags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC;
+ android::base::unique_fd corpusFd(open(filePath.c_str(), openFlags, 0666));
+ if (!corpusFd.ok()) {
+ std::cerr << "Failed to open fd. Path " << filePath
+ << " with error: " << strerror(errno) << std::endl;
+ return android::UNKNOWN_ERROR;
+ }
+ generateSeedsFromRecording(corpusFd, transaction.value());
+ }
+
+ if (transactionNumber == 0) {
+ std::cerr << "No valid transaction has been found in recording file: " << recordingPath
+ << std::endl;
+ return android::BAD_VALUE;
+ }
+
+ return android::NO_ERROR;
+}
+
+void printHelp(const char* toolName) {
+ std::cout << "Usage: \n\n"
+ << toolName
+ << " <recording_path> <destination_directory> \n\n*Use "
+ "record_binder tool for recording binder transactions."
+ << std::endl;
+}
+
+int main(int argc, char** argv) {
+ if (argc != 3) {
+ printHelp(argv[0]);
+ return 1;
+ }
+ const char* sourcePath = argv[1];
+ const char* corpusDir = argv[2];
+ if (android::NO_ERROR != generateCorpus(sourcePath, corpusDir)) {
+ std::cerr << "Failed to generate fuzzer corpus." << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/libs/bufferstreams/rust/Android.bp b/libs/bufferstreams/rust/Android.bp
index 95a85b5..ff95148 100644
--- a/libs/bufferstreams/rust/Android.bp
+++ b/libs/bufferstreams/rust/Android.bp
@@ -17,7 +17,8 @@
crate_name: "bufferstreams",
srcs: ["src/lib.rs"],
edition: "2021",
- vendor_available: true,
- host_supported: true,
+ rlibs: [
+ "libnativewindow_rs",
+ ],
min_sdk_version: "30",
}
diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs
index 51f1c73..1d321c8 100644
--- a/libs/bufferstreams/rust/src/lib.rs
+++ b/libs/bufferstreams/rust/src/lib.rs
@@ -14,9 +14,143 @@
//! libbufferstreams: Reactive Streams for Graphics Buffers
+use nativewindow::*;
+use std::sync::{Arc, Weak};
+use std::time::Instant;
+
/// This function will print Hello World.
#[no_mangle]
pub extern "C" fn hello() -> bool {
println!("Hello world.");
true
}
+
+/// BufferPublishers provide buffers to BufferSusbscribers. Depending on the
+/// particular object in question, these could be allocated locally or provided
+/// over IPC.
+///
+/// BufferPublishers are required to adhere to the following, based on the
+/// reactive streams specification:
+/// * The total number of on_next´s signalled by a Publisher to a Subscriber
+/// MUST be less than or equal to the total number of elements requested by that
+/// Subscriber´s Subscription at all times.
+/// * A Publisher MAY signal fewer on_next than requested and terminate the
+/// Subscription by calling on_complete or on_error.
+/// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber
+/// MUST be signaled serially.
+/// * If a Publisher fails it MUST signal an on_error.
+/// * If a Publisher terminates successfully (finite stream) it MUST signal an
+/// on_complete.
+/// * If a Publisher signals either on_error or on_complete on a Subscriber,
+/// that Subscriber’s Subscription MUST be considered cancelled.
+/// * Once a terminal state has been signaled (on_error, on_complete) it is
+/// REQUIRED that no further signals occur.
+/// * If a Subscription is cancelled its Subscriber MUST eventually stop being
+/// signaled.
+/// * A Publisher MAY support multiple Subscribers and decides whether each
+/// Subscription is unicast or multicast.
+pub trait BufferPublisher {
+ /// This function will create the subscription between the publisher and
+ /// the subscriber.
+ fn subscribe(&self, subscriber: Weak<dyn BufferSubscriber>);
+}
+
+/// BufferSubscribers can subscribe to BufferPublishers. They can request Frames
+/// via the BufferSubscription they get from the publisher, then receive Frames
+/// via on_next.
+///
+/// BufferSubcribers are required to adhere to the following, based on the
+/// reactive streams specification:
+/// * The total number of on_next´s signalled by a Publisher to a Subscriber
+/// MUST be less than or equal to the total number of elements requested by that
+/// Subscriber´s Subscription at all times.
+/// * A Publisher MAY signal fewer on_next than requested and terminate the
+/// Subscription by calling on_complete or on_error.
+/// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber
+/// MUST be signaled serially.
+/// * If a Publisher fails it MUST signal an on_error.
+/// * If a Publisher terminates successfully (finite stream) it MUST signal an
+/// on_complete.
+/// * If a Publisher signals either on_error or on_complete on a Subscriber,
+/// that Subscriber’s Subscription MUST be considered cancelled.
+/// * Once a terminal state has been signaled (on_error, on_complete) it is
+/// REQUIRED that no further signals occur.
+/// * If a Subscription is cancelled its Subscriber MUST eventually stop being
+/// signaled.
+/// * Publisher.subscribe MAY be called as many times as wanted but MUST be
+/// with a different Subscriber each time.
+/// * A Publisher MAY support multiple Subscribers and decides whether each
+/// Subscription is unicast or multicast.
+pub trait BufferSubscriber {
+ /// This function will be called at the beginning of the subscription.
+ fn on_subscribe(&self, subscription: Arc<dyn BufferSubscription>);
+ /// This function will be called for buffer that comes in.
+ fn on_next(&self, frame: Frame);
+ /// This function will be called in case of an error.
+ fn on_error(&self, error: BufferError);
+ /// This function will be called on finite streams when done.
+ fn on_complete(&self);
+}
+
+/// BufferSubscriptions serve as the bridge between BufferPublishers and
+/// BufferSubscribers. BufferSubscribers receive a BufferSubscription when they
+/// subscribe to a BufferPublisher via on_subscribe.
+/// This object is to be used by the BufferSubscriber to cancel its subscription
+/// or request more buffers.
+///
+/// BufferSubcriptions are required to adhere to the following, based on the
+/// reactive streams specification:
+/// * Subscription.request and Subscription.cancel MUST only be called inside
+/// of its Subscriber context.
+/// * The Subscription MUST allow the Subscriber to call Subscription.request
+/// synchronously from within on_next or on_subscribe.
+/// * Subscription.request MUST place an upper bound on possible synchronous
+/// recursion between Publisher and Subscriber.
+/// * Subscription.request SHOULD respect the responsivity of its caller by
+/// returning in a timely manner.
+/// * Subscription.cancel MUST respect the responsivity of its caller by
+/// returning in a timely manner, MUST be idempotent and MUST be thread-safe.
+/// * After the Subscription is cancelled, additional
+/// Subscription.request(n: u64) MUST be NOPs.
+/// * After the Subscription is cancelled, additional Subscription.cancel()
+/// MUST be NOPs.
+/// * While the Subscription is not cancelled, Subscription.request(n: u64)
+/// MUST register the given number of additional elements to be produced to the
+/// respective subscriber.
+/// * While the Subscription is not cancelled, Subscription.request(n: u64)
+/// MUST signal on_error if the argument is <= 0. The cause message SHOULD
+/// explain that non-positive request signals are illegal.
+/// * While the Subscription is not cancelled, Subscription.request(n: u64)
+/// MAY synchronously call on_next on this (or other) subscriber(s).
+/// * While the Subscription is not cancelled, Subscription.request(n: u64)
+/// MAY synchronously call on_complete or on_error on this (or other)
+/// subscriber(s).
+/// * While the Subscription is not cancelled, Subscription.cancel() MUST
+/// request the Publisher to eventually stop signaling its Subscriber. The
+/// operation is NOT REQUIRED to affect the Subscription immediately.
+/// * While the Subscription is not cancelled, Subscription.cancel() MUST
+/// request the Publisher to eventually drop any references to the corresponding
+/// subscriber.
+/// * While the Subscription is not cancelled, calling Subscription.cancel MAY
+/// cause the Publisher, if stateful, to transition into the shut-down state if
+/// no other Subscription exists at this point.
+/// * Calling Subscription.cancel MUST return normally.
+/// * Calling Subscription.request MUST return normally.
+pub trait BufferSubscription {
+ /// request
+ fn request(&self, n: u64);
+ /// cancel
+ fn cancel(&self);
+}
+/// Type used to describe errors produced by subscriptions.
+type BufferError = Box<dyn std::error::Error + Send + Sync + 'static>;
+
+/// Struct used to contain the buffer.
+pub struct Frame {
+ /// A handle to the C buffer interface.
+ pub buffer: AHardwareBuffer,
+ /// The time at which the buffer was dispatched.
+ pub present_time: Instant,
+ /// A fence used for reading/writing safely.
+ pub fence: i32,
+}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 5c324b2..207fa4f 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -303,13 +303,8 @@
// frame numbers that were in a sync. We remove the frame from mSyncedFrameNumbers
// set and then check if it's empty. If there are no more pending syncs, we can
// proceed with flushing the shadow queue.
- // We also want to check if mSyncTransaction is null because it's possible another
- // sync request came in while waiting, but it hasn't started processing yet. In that
- // case, we don't actually want to flush the frames in between since they will get
- // processed and merged with the sync transaction and released earlier than if they
- // were sent to SF
mSyncedFrameNumbers.erase(currFrameNumber);
- if (mSyncedFrameNumbers.empty() && mSyncTransaction == nullptr) {
+ if (mSyncedFrameNumbers.empty()) {
flushShadowQueue();
}
} else {
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 826a418..070f6bf 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1075131
+
chrisforbes@google.com
jreck@google.com
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 3c508c7..6bc3324 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -450,7 +450,9 @@
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
surfaceControlStats);
}
+ }
+ for (const auto& transactionStats : listenerStats.transactionStats) {
for (const auto& surfaceStats : transactionStats.surfaceStats) {
// The callbackMap contains the SurfaceControl object, which we need to look up the
// layerId. Since we don't know which callback contains the SurfaceControl, iterate
diff --git a/libs/gui/tests/OWNERS b/libs/gui/tests/OWNERS
index 156efdb..48cd30d 100644
--- a/libs/gui/tests/OWNERS
+++ b/libs/gui/tests/OWNERS
@@ -1,3 +1,6 @@
# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > Surfaces
# Bug component: 316245 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp
# Buganizer template url: https://b.corp.google.com/issues/new?component=316245&template=1018194 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp
+
+# Android > Android OS & Apps > graphics > Core Graphics Stack (CoGS)
+# Bug component: 1075130
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index a5bcc62..a2ec57c 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -61,6 +61,7 @@
/// program termination.
///
/// Available since API level 26.
+ #[inline]
pub fn new(
width: u32,
height: u32,
@@ -199,6 +200,7 @@
#[test]
#[should_panic]
fn take_from_raw_panics_on_null() {
+ // SAFETY: Passing a null pointer is safe, it should just panic.
unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) };
}
@@ -216,9 +218,13 @@
};
let mut raw_buffer_ptr = ptr::null_mut();
+ // SAFETY: The pointers are valid because they come from references, and
+ // `AHardwareBuffer_allocate` doesn't retain them after it returns.
let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) };
assert_eq!(status, 0);
+ // SAFETY: The pointer must be valid because it was just allocated successfully, and we
+ // don't use it after calling this.
let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) };
assert_eq!(buffer.width(), 1024);
}
diff --git a/libs/nativewindow/tests/benchmark/Android.bp b/libs/nativewindow/tests/benchmark/Android.bp
new file mode 100644
index 0000000..6f844cf
--- /dev/null
+++ b/libs/nativewindow/tests/benchmark/Android.bp
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 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.
+
+cc_defaults {
+ name: "nativewindow_benchmark_defaults_cc",
+ shared_libs: ["libnativewindow"],
+ static_libs: [
+ "libbase",
+ "libgoogle-benchmark-main",
+ ],
+ test_suites: [
+ "device-tests",
+ "NativeWindowBenchmarks",
+ ],
+}
+
+cc_benchmark {
+ name: "nativewindow_buffer_benchmarks_cc",
+ srcs: ["buffer_benchmarks.cc"],
+ defaults: ["nativewindow_benchmark_defaults_cc"],
+}
+
+rust_defaults {
+ name: "nativewindow_benchmark_defaults_rs",
+ rustlibs: [
+ "libnativewindow_rs",
+ "libcriterion",
+ ],
+ test_suites: [
+ "device-tests",
+ "NativeWindowBenchmarks",
+ ],
+}
+
+rust_benchmark {
+ name: "nativewindow_buffer_benchmarks_rs",
+ srcs: ["buffer_benchmarks.rs"],
+ defaults: ["nativewindow_benchmark_defaults_rs"],
+}
diff --git a/libs/nativewindow/tests/benchmark/README.md b/libs/nativewindow/tests/benchmark/README.md
new file mode 100644
index 0000000..7eae538
--- /dev/null
+++ b/libs/nativewindow/tests/benchmark/README.md
@@ -0,0 +1,22 @@
+# libnativewindow Benchmarks
+
+This directory contains benchmarks for the C++ and Rust variants of
+libnativewindow.
+
+## Running
+
+It is currently a little tricky to get statistics from Rust benchmarks directly
+from tradefed. But we can hack it by using atest to build/push, then running
+the benchmarks by hand to get stats.
+
+```
+ $ atest nativewindow_buffer_benchmarks_rs nativewindow_buffer_benchmarks_cc -d
+ $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_cc/x86_64/nativewindow_buffer_benchmarks_cc
+ $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_rs/x86_64/nativewindow_buffer_benchmarks_rs --bench
+```
+
+## Results
+
+On a remote emulator, the results we see from the benchmarks from Rust and C++
+seem to be roughly equivalent! Allocating/deallocating a 720p buffer takes
+~2.3ms on each.
diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc
new file mode 100644
index 0000000..9b31993
--- /dev/null
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc
@@ -0,0 +1,74 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <android-base/macros.h>
+#include <android/hardware_buffer.h>
+#include <benchmark/benchmark.h>
+
+constexpr AHardwareBuffer_Desc k720pDesc = {.width = 1280,
+ .height = 720,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ .stride = 0};
+
+static void BM_BufferAllocationDeallocation(benchmark::State& state) {
+ AHardwareBuffer* buffer = nullptr;
+ for (auto _ : state) {
+ int status = AHardwareBuffer_allocate(&k720pDesc, &buffer);
+ if (UNLIKELY(status != 0)) {
+ state.SkipWithError("Unable to allocate buffer.");
+ }
+ AHardwareBuffer_release(buffer);
+ buffer = nullptr;
+ }
+}
+BENCHMARK(BM_BufferAllocationDeallocation);
+
+static void BM_AHardwareBuffer_Id(benchmark::State& state) {
+ AHardwareBuffer* buffer = nullptr;
+ int status = AHardwareBuffer_allocate(&k720pDesc, &buffer);
+ if (UNLIKELY(status != 0)) {
+ state.SkipWithError("Unable to allocate buffer.");
+ }
+
+ for (auto _ : state) {
+ uint64_t id = 0;
+ int status = AHardwareBuffer_getId(buffer, &id);
+ if (UNLIKELY(status != 0)) {
+ state.SkipWithError("Unable to get ID.");
+ }
+ }
+
+ AHardwareBuffer_release(buffer);
+}
+BENCHMARK(BM_AHardwareBuffer_Id);
+
+static void BM_AHardwareBuffer_Desc(benchmark::State& state) {
+ AHardwareBuffer* buffer = nullptr;
+ int status = AHardwareBuffer_allocate(&k720pDesc, &buffer);
+ if (UNLIKELY(status != 0)) {
+ state.SkipWithError("Unable to allocate buffer.");
+ }
+
+ for (auto _ : state) {
+ AHardwareBuffer_Desc desc = {};
+ AHardwareBuffer_describe(buffer, &desc);
+ }
+
+ AHardwareBuffer_release(buffer);
+}
+BENCHMARK(BM_AHardwareBuffer_Desc);
+
+BENCHMARK_MAIN();
diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
new file mode 100644
index 0000000..fbd49c0
--- /dev/null
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
@@ -0,0 +1,60 @@
+// Copyright (C) 2023 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.
+
+//! Benchmark for libnativewindow AHardwareBuffer bindings
+
+#![allow(dead_code)]
+#![allow(missing_docs)]
+
+use criterion::*;
+use nativewindow::*;
+
+#[inline]
+fn create_720p_buffer() -> AHardwareBuffer {
+ AHardwareBuffer::new(
+ 1280,
+ 720,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ )
+ .unwrap()
+}
+
+fn criterion_benchmark(c: &mut Criterion) {
+ c.bench_function("allocate_deallocate", |b| {
+ b.iter(|| {
+ let buffer = create_720p_buffer();
+ drop(buffer);
+ })
+ });
+
+ let buffer = create_720p_buffer();
+ c.bench_with_input(BenchmarkId::new("id", "buffer"), &buffer, |b, buffer| {
+ b.iter(|| {
+ buffer.id();
+ })
+ });
+
+ // This benchmark exercises getters that need to fetch data via an
+ // underlying call to AHardwareBuffer_describe.
+ c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| {
+ b.iter(|| {
+ buffer.width();
+ })
+ });
+}
+
+criterion_group!(benches, criterion_benchmark);
+criterion_main!(benches);
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 5d23a5e..66e1aa1 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1075131
+
adyabr@google.com
alecmouri@google.com
djsollen@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 0d7df10..e7a2c7a 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1251,7 +1251,6 @@
texture.setFiltering(layer.source.buffer.useTextureFiltering);
texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
- setSourceY410BT2020(layer.source.buffer.isY410BT2020);
renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
texCoords[0] = vec2(0.0, 0.0);
@@ -1294,7 +1293,6 @@
// Cleanup if there's a buffer source
if (layer.source.buffer.buffer != nullptr) {
disableBlending();
- setSourceY410BT2020(false);
disableTexturing();
}
}
@@ -1357,10 +1355,6 @@
}
}
-void GLESRenderEngine::setSourceY410BT2020(bool enable) {
- mState.isY410BT2020 = enable;
-}
-
void GLESRenderEngine::setSourceDataSpace(Dataspace source) {
mDataSpace = source;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 402ff52..ea75e21 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -183,7 +183,6 @@
void setupCornerRadiusCropSize(float width, float height);
// HDR and color management related functions and state
- void setSourceY410BT2020(bool enable);
void setSourceDataSpace(ui::Dataspace source);
void setOutputDataSpace(ui::Dataspace dataspace);
void setDisplayMaxLuminance(const float maxLuminance);
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index f7f2d54..812dda0 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -98,9 +98,6 @@
shaderKey.set(Key::INPUT_TF_MASK, (i & 1) ?
Key::INPUT_TF_HLG : Key::INPUT_TF_ST2084);
- // Cache Y410 input on or off
- shaderKey.set(Key::Y410_BT2020_MASK, (i & 2) ?
- Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
if (cache.count(shaderKey) == 0) {
cache.emplace(shaderKey, generateProgram(shaderKey));
shaderCount++;
@@ -161,13 +158,11 @@
ProgramCache::Key ProgramCache::computeKey(const Description& description) {
Key needs;
needs.set(Key::TEXTURE_MASK,
- !description.textureEnabled
- ? Key::TEXTURE_OFF
+ !description.textureEnabled ? Key::TEXTURE_OFF
: description.texture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES
- ? Key::TEXTURE_EXT
- : description.texture.getTextureTarget() == GL_TEXTURE_2D
- ? Key::TEXTURE_2D
- : Key::TEXTURE_OFF)
+ ? Key::TEXTURE_EXT
+ : description.texture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D
+ : Key::TEXTURE_OFF)
.set(Key::ALPHA_MASK, (description.color.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
.set(Key::BLEND_MASK,
description.isPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
@@ -186,8 +181,6 @@
.set(Key::ROUNDED_CORNERS_MASK,
description.cornerRadius > 0 ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF)
.set(Key::SHADOW_MASK, description.drawShadows ? Key::SHADOW_ON : Key::SHADOW_OFF);
- needs.set(Key::Y410_BT2020_MASK,
- description.isY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
if (needs.hasTransformMatrix() ||
(description.inputTransferFunction != description.outputTransferFunction)) {
@@ -650,20 +643,6 @@
fs << "uniform vec4 color;";
}
- if (needs.isY410BT2020()) {
- fs << R"__SHADER__(
- vec3 convertY410BT2020(const vec3 color) {
- const vec3 offset = vec3(0.0625, 0.5, 0.5);
- const mat3 transform = mat3(
- vec3(1.1678, 1.1678, 1.1678),
- vec3( 0.0, -0.1878, 2.1481),
- vec3(1.6836, -0.6523, 0.0));
- // Y is in G, U is in R, and V is in B
- return clamp(transform * (color.grb - offset), 0.0, 1.0);
- }
- )__SHADER__";
- }
-
if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) ||
needs.hasDisplayColorMatrix()) {
if (needs.needsToneMapping()) {
@@ -730,9 +709,6 @@
} else {
if (needs.isTexturing()) {
fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
- if (needs.isY410BT2020()) {
- fs << "gl_FragColor.rgb = convertY410BT2020(gl_FragColor.rgb);";
- }
} else {
fs << "gl_FragColor.rgb = color.rgb;";
fs << "gl_FragColor.a = 1.0;";
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index 535d21c..b18914f 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -108,11 +108,6 @@
OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT,
- Y410_BT2020_SHIFT = 12,
- Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
- Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
- Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
-
SHADOW_SHIFT = 13,
SHADOW_MASK = 1 << SHADOW_SHIFT,
SHADOW_OFF = 0 << SHADOW_SHIFT,
@@ -180,7 +175,6 @@
outputTF >>= Key::OUTPUT_TF_SHIFT;
return inputTF != outputTF;
}
- inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
// for use by std::unordered_map
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index b3a617c..b501c40 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -64,9 +64,6 @@
// overrides the alpha channel of the buffer.
bool isOpaque = false;
- // HDR color-space setting for Y410.
- bool isY410BT2020 = false;
-
float maxLuminanceNits = 0.0;
};
@@ -189,8 +186,7 @@
lhs.useTextureFiltering == rhs.useTextureFiltering &&
lhs.textureTransform == rhs.textureTransform &&
lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha &&
- lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 &&
- lhs.maxLuminanceNits == rhs.maxLuminanceNits;
+ lhs.isOpaque == rhs.isOpaque && lhs.maxLuminanceNits == rhs.maxLuminanceNits;
}
static inline bool operator==(const Geometry& lhs, const Geometry& rhs) {
@@ -247,7 +243,6 @@
PrintMatrix(settings.textureTransform, os);
*os << "\n .usePremultipliedAlpha = " << settings.usePremultipliedAlpha;
*os << "\n .isOpaque = " << settings.isOpaque;
- *os << "\n .isY410BT2020 = " << settings.isY410BT2020;
*os << "\n .maxLuminanceNits = " << settings.maxLuminanceNits;
*os << "\n}";
}
diff --git a/libs/renderengine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h
index fa6ec10..2873ad7 100644
--- a/libs/renderengine/include/renderengine/private/Description.h
+++ b/libs/renderengine/include/renderengine/private/Description.h
@@ -64,9 +64,6 @@
// color used when texturing is disabled or when setting alpha.
half4 color;
- // true if the sampled pixel values are in Y410/BT2020 rather than RGBA
- bool isY410BT2020 = false;
-
// transfer functions for the input/output
TransferFunction inputTransferFunction = TransferFunction::LINEAR;
TransferFunction outputTransferFunction = TransferFunction::LINEAR;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 477beaf..02c2f65 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1356,6 +1356,7 @@
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyInputDevicesChangedWasCalled());
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
+ mTestListener->clearNotifyDeviceResetCalls();
}
void TearDown() override {
@@ -1828,6 +1829,51 @@
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertStylusGestureNotified(mDeviceInfo.getId()));
}
+TEST_F(TouchIntegrationTest, ExternalStylusConnectedDuringTouchGesture) {
+ const Point centerPoint = mDevice->getCenterPoint();
+
+ // Down
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
+ mDevice->sendDown(centerPoint);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+
+ // Move
+ mDevice->sendMove(centerPoint + Point(1, 1));
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)));
+
+ // Connecting an external stylus mid-gesture should not interrupt the ongoing gesture stream.
+ auto externalStylus = createUinputDevice<UinputExternalStylus>();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
+ const auto stylusInfo = findDeviceByName(externalStylus->getName());
+ ASSERT_TRUE(stylusInfo);
+
+ // Move
+ mDevice->sendMove(centerPoint + Point(2, 2));
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)));
+
+ // Disconnecting an external stylus mid-gesture should not interrupt the ongoing gesture stream.
+ externalStylus.reset();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
+
+ // Up
+ mDevice->sendUp();
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(
+ mTestListener->assertNotifyMotionWasCalled(WithMotionAction(AMOTION_EVENT_ACTION_UP)));
+
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
+}
+
// --- StylusButtonIntegrationTest ---
// Verify the behavior of button presses reported by various kinds of styluses, including buttons
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index fc917dd..41e250f 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -57,6 +57,18 @@
"Expected notifyDeviceReset() to have been called."));
}
+void TestInputListener::clearNotifyDeviceResetCalls() {
+ std::scoped_lock<std::mutex> lock(mLock);
+ std::get<std::vector<NotifyDeviceResetArgs>>(mQueues).clear();
+}
+
+void TestInputListener::assertNotifyDeviceResetWasCalled(
+ const ::testing::Matcher<NotifyDeviceResetArgs>& matcher) {
+ NotifyDeviceResetArgs outEventArgs;
+ ASSERT_NO_FATAL_FAILURE(assertNotifyDeviceResetWasCalled(&outEventArgs));
+ ASSERT_THAT(outEventArgs, matcher);
+}
+
void TestInputListener::assertNotifyDeviceResetWasNotCalled() {
ASSERT_NO_FATAL_FAILURE(
assertNotCalled<NotifyDeviceResetArgs>("notifyDeviceReset() should not be called."));
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index deb6048..3c5e014 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -43,6 +43,10 @@
void assertNotifyConfigurationChangedWasNotCalled();
+ void clearNotifyDeviceResetCalls();
+
+ void assertNotifyDeviceResetWasCalled(const ::testing::Matcher<NotifyDeviceResetArgs>& matcher);
+
void assertNotifyDeviceResetWasCalled(NotifyDeviceResetArgs* outEventArgs = nullptr);
void assertNotifyDeviceResetWasNotCalled();
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
index 020ea86..183383f 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -139,6 +139,10 @@
return mDeviceId == args.deviceId;
}
+ bool MatchAndExplain(const NotifyDeviceResetArgs& args, std::ostream*) const {
+ return mDeviceId == args.deviceId;
+ }
+
bool MatchAndExplain(const InputEvent& event, std::ostream*) const {
return mDeviceId == event.getDeviceId();
}
diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
index 7e020ee..752257b 100644
--- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
@@ -45,8 +45,7 @@
lhs.useTextureFiltering == rhs.useTextureFiltering &&
lhs.textureTransform == rhs.textureTransform &&
lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha &&
- lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 &&
- lhs.maxLuminanceNits == rhs.maxLuminanceNits;
+ lhs.isOpaque == rhs.isOpaque && lhs.maxLuminanceNits == rhs.maxLuminanceNits;
}
inline bool equalIgnoringBuffer(const renderengine::LayerSettings& lhs,
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
index 8f67f36..97725ea 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -220,17 +220,6 @@
minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
- if (args.hasWideColorGamut) {
- // insert HDR10/HLG as we will force client composition for HDR10/HLG
- // layers
- if (!hasHDR10Support()) {
- types.push_back(ui::Hdr::HDR10);
- }
-
- if (!hasHLGSupport()) {
- types.push_back(ui::Hdr::HLG);
- }
- }
mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
index b3ff2ec..03a97dc 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -282,39 +282,6 @@
}
}
-TEST_F(DisplayColorProfileTest, ctorSignalsHdrSupportForAnyWideColorGamutDevice) {
- {
- // If the output does not profile wide color gamut, then no HDR modes
- // will be profileed in the generated HDR capabilities.
- auto profile = ProfileFactory().setHasWideColorGamut(false).build();
-
- EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), IsEmpty());
- }
-
- {
- // If the HWC does not show profile for certain HDR modes, then the
- // generated HDR capabilities will indicate profile anyway.
- auto profile = ProfileFactory().setHasWideColorGamut(true).build();
-
- EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2));
- EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10));
- EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG));
- }
-
- {
- // If the HWC profiles the HDR modes, then the generated capabilities
- // still has one entry for each HDR type.
- auto profile = ProfileFactory()
- .setHasWideColorGamut(true)
- .addHdrTypes({Hdr::HLG, Hdr::HDR10})
- .build();
-
- EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2));
- EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10));
- EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG));
- }
-}
-
/* ------------------------------------------------------------------------
* DisplayColorProfile::hasRenderIntent
*/
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 3c7cbe6..70ccaf8 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -213,10 +213,7 @@
ATRACE_INT(mRenderFrameRateFPSTrace.c_str(), renderFps.getIntValue());
mRefreshRateSelector->setActiveMode(modeId, renderFps);
-
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->changeRefreshRate(displayFps, renderFps);
- }
+ updateRefreshRateOverlayRate(displayFps, renderFps);
}
status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info,
@@ -473,7 +470,7 @@
mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, features);
mRefreshRateOverlay->setLayerStack(getLayerStack());
mRefreshRateOverlay->setViewport(getSize());
- updateRefreshRateOverlayRate(getActiveMode().modePtr->getFps(), getActiveMode().fps);
+ updateRefreshRateOverlayRate(getActiveMode().modePtr->getFps(), getActiveMode().fps, setByHwc);
}
void DisplayDevice::updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc) {
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index ee589c3..5d41fdd 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -468,19 +468,9 @@
if (forceUpdate ||
requested.what &
(layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged |
- layer_state_t::eApiChanged)) {
- isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ &&
- requested.api == NATIVE_WINDOW_API_MEDIA &&
- requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102;
- }
-
- if (forceUpdate ||
- requested.what &
- (layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged |
layer_state_t::eApiChanged | layer_state_t::eShadowRadiusChanged |
layer_state_t::eBlurRegionsChanged | layer_state_t::eStretchChanged)) {
- forceClientComposition = isHdrY410 || shadowSettings.length > 0 ||
- stretchEffect.hasEffect();
+ forceClientComposition = shadowSettings.length > 0 || stretchEffect.hasEffect();
}
if (forceUpdate ||
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 19477fa..92d23e2 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -72,7 +72,6 @@
Rect transformedBoundsWithoutTransparentRegion;
renderengine::ShadowSettings shadowSettings;
bool premultipliedAlpha;
- bool isHdrY410;
ui::Transform parentTransform;
Rect bufferSize;
Rect croppedBufferSize;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index cf39187..159d0f0 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -854,8 +854,9 @@
}
if (forceUpdate || snapshot.clientChanges & layer_state_t::eCornerRadiusChanged ||
- snapshot.changes.any(RequestedLayerState::Changes::Geometry)) {
- updateRoundedCorner(snapshot, requested, parentSnapshot);
+ snapshot.changes.any(RequestedLayerState::Changes::Geometry |
+ RequestedLayerState::Changes::BufferUsageFlags)) {
+ updateRoundedCorner(snapshot, requested, parentSnapshot, args);
}
if (forceUpdate || snapshot.clientChanges & layer_state_t::eShadowRadiusChanged ||
@@ -870,8 +871,8 @@
}
// computed snapshot properties
- snapshot.forceClientComposition = snapshot.isHdrY410 || snapshot.shadowSettings.length > 0 ||
- snapshot.stretchEffect.hasEffect();
+ snapshot.forceClientComposition =
+ snapshot.shadowSettings.length > 0 || snapshot.stretchEffect.hasEffect();
snapshot.contentOpaque = snapshot.isContentOpaque();
snapshot.isOpaque = snapshot.contentOpaque && !snapshot.roundedCorner.hasRoundedCorners() &&
snapshot.color.a == 1.f;
@@ -886,7 +887,12 @@
void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot,
const RequestedLayerState& requested,
- const LayerSnapshot& parentSnapshot) {
+ const LayerSnapshot& parentSnapshot,
+ const Args& args) {
+ if (args.skipRoundCornersWhenProtected && requested.isProtected()) {
+ snapshot.roundedCorner = RoundedCornerState();
+ return;
+ }
snapshot.roundedCorner = RoundedCornerState();
RoundedCornerState parentRoundedCorner;
if (parentSnapshot.roundedCorner.hasRoundedCorners()) {
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index d361605..3d64b36 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -54,6 +54,7 @@
std::unordered_set<uint32_t> excludeLayerIds;
const std::unordered_map<std::string, bool>& supportedLayerGenericMetadata;
const std::unordered_map<std::string, uint32_t>& genericLayerMetadataKeyMap;
+ bool skipRoundCornersWhenProtected = false;
};
LayerSnapshotBuilder();
@@ -103,7 +104,7 @@
bool parentIsRelative, const Args& args);
static void resetRelativeState(LayerSnapshot& snapshot);
static void updateRoundedCorner(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
- const LayerSnapshot& parentSnapshot);
+ const LayerSnapshot& parentSnapshot, const Args& args);
void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
const LayerSnapshot& parentSnapshot, uint32_t displayRotationFlags);
static void updateShadows(LayerSnapshot& snapshot, const RequestedLayerState& requested,
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index a4777d1..d979c46 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -147,6 +147,8 @@
const ui::Size oldBufferSize = hadBuffer
? ui::Size(externalTexture->getWidth(), externalTexture->getHeight())
: ui::Size();
+ const uint64_t oldUsageFlags = hadBuffer ? externalTexture->getUsage() : 0;
+
const bool hadSideStream = sidebandStream != nullptr;
const layer_state_t& clientState = resolvedComposerState.state;
const bool hadBlur = hasBlur();
@@ -177,6 +179,10 @@
changes |= RequestedLayerState::Changes::BufferSize;
changes |= RequestedLayerState::Changes::Geometry;
}
+ const uint64_t usageFlags = hasBuffer ? externalTexture->getUsage() : 0;
+ if (oldUsageFlags != usageFlags) {
+ changes |= RequestedLayerState::Changes::BufferUsageFlags;
+ }
}
if (hasBuffer != hadBuffer) {
@@ -570,6 +576,10 @@
return true;
}
+bool RequestedLayerState::isProtected() const {
+ return externalTexture && externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED;
+}
+
void RequestedLayerState::clearChanges() {
what = 0;
changes.clear();
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 1c19d6d..0309302 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -56,6 +56,7 @@
Animation = 1u << 17,
BufferSize = 1u << 18,
GameMode = 1u << 19,
+ BufferUsageFlags = 1u << 20,
};
static Rect reduce(const Rect& win, const Region& exclude);
RequestedLayerState(const LayerCreationArgs&);
@@ -85,6 +86,7 @@
bool willReleaseBufferOnLatch() const;
bool backpressureEnabled() const;
bool isSimpleBufferUpdate(const layer_state_t&) const;
+ bool isProtected() const;
// Layer serial number. This gives layers an explicit ordering, so we
// have a stable sort order when their layer stack and Z-order are
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index cfcc424..59a8825 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -659,7 +659,7 @@
// 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 (isHdrY410() || drawShadows() || snapshot->stretchEffect.hasEffect()) {
+ if (drawShadows() || snapshot->stretchEffect.hasEffect()) {
snapshot->forceClientComposition = true;
}
// If there are no visible region changes, we still need to update blur parameters.
@@ -835,12 +835,12 @@
mFlinger->mUpdateInputInfo = true;
}
- commitTransaction(mDrawingState);
+ commitTransaction();
return flags;
}
-void Layer::commitTransaction(State&) {
+void Layer::commitTransaction() {
// Set the present state for all bufferlessSurfaceFramesTX to Presented. The
// bufferSurfaceFrameTX will be presented in latchBuffer.
for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
@@ -3887,13 +3887,6 @@
return true;
}
-bool Layer::isHdrY410() const {
- // pixel format is HDR Y410 masquerading as RGBA_1010102
- return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ &&
- mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA &&
- mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102);
-}
-
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;
@@ -4295,7 +4288,6 @@
snapshot->contentOpaque = isOpaque(mDrawingState);
snapshot->layerOpaqueFlagSet =
(mDrawingState.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
- snapshot->isHdrY410 = isHdrY410();
sp<Layer> p = mDrawingParent.promote();
if (p != nullptr) {
snapshot->parentTransform = p->getTransform();
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5d77657..3eef277 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -431,8 +431,6 @@
void updateCloneBufferInfo();
uint64_t mPreviousFrameNumber = 0;
- bool isHdrY410() const;
-
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
@@ -912,6 +910,7 @@
void setTransformHint(std::optional<ui::Transform::RotationFlags> transformHint) {
mTransformHint = transformHint;
}
+ void commitTransaction();
// Keeps track of the previously presented layer stacks. This is used to get
// the release fences from the correct displays when we release the last buffer
// from the layer.
@@ -932,7 +931,6 @@
void preparePerFrameCompositionState();
void preparePerFrameBufferCompositionState();
void preparePerFrameEffectsCompositionState();
- virtual void commitTransaction(State& stateToCommit);
void gatherBufferInfo();
void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&);
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index 4d3e048..5ae52ab 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -225,7 +225,6 @@
layerSettings.source.buffer.fence = mSnapshot->acquireFence;
layerSettings.source.buffer.textureName = mSnapshot->textureName;
layerSettings.source.buffer.usePremultipliedAlpha = mSnapshot->premultipliedAlpha;
- layerSettings.source.buffer.isY410BT2020 = mSnapshot->isHdrY410;
bool hasSmpte2086 = mSnapshot->hdrMetadata.validTypes & HdrMetadata::SMPTE2086;
bool hasCta861_3 = mSnapshot->hdrMetadata.validTypes & HdrMetadata::CTA861_3;
float maxLuminance = 0.f;
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 4734097..3270e4c 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1075131
+
adyabr@google.com
alecmouri@google.com
chaviw@google.com
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7b37407..328a382 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2311,7 +2311,9 @@
.forceFullDamage = mForceFullDamage,
.supportedLayerGenericMetadata =
getHwComposer().getSupportedLayerGenericMetadata(),
- .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()};
+ .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(),
+ .skipRoundCornersWhenProtected =
+ !getRenderEngine().supportsProtectedContent()};
mLayerSnapshotBuilder.update(args);
}
@@ -2335,6 +2337,7 @@
if (!mLegacyFrontEndEnabled) {
ATRACE_NAME("DisplayCallbackAndStatsUpdates");
applyTransactions(update.transactions, vsyncId);
+ traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); });
const nsecs_t latchTime = systemTime();
bool unused = false;
@@ -8205,19 +8208,22 @@
bool setByHwc = getHwComposer().hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG);
for (const auto& [id, display] : mPhysicalDisplays) {
if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) {
- if (setByHwc) {
- const auto status =
- getHwComposer().setRefreshRateChangedCallbackDebugEnabled(id, enable);
- if (status != NO_ERROR) {
- ALOGE("Error updating the refresh rate changed callback debug enabled");
- return;
- }
- }
-
if (const auto device = getDisplayDeviceLocked(id)) {
- device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner,
- mRefreshRateOverlayRenderRate,
- mRefreshRateOverlayShowInMiddle);
+ const auto enableOverlay = [&](const bool setByHwc) FTL_FAKE_GUARD(
+ kMainThreadContext) {
+ device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner,
+ mRefreshRateOverlayRenderRate,
+ mRefreshRateOverlayShowInMiddle);
+ };
+ enableOverlay(setByHwc);
+ if (setByHwc) {
+ const auto status =
+ getHwComposer().setRefreshRateChangedCallbackDebugEnabled(id, enable);
+ if (status != NO_ERROR) {
+ ALOGE("Error updating the refresh rate changed callback debug enabled");
+ enableOverlay(/*setByHwc*/ false);
+ }
+ }
}
}
}
@@ -8660,7 +8666,9 @@
.excludeLayerIds = std::move(excludeLayerIds),
.supportedLayerGenericMetadata =
getHwComposer().getSupportedLayerGenericMetadata(),
- .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()};
+ .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(),
+ .skipRoundCornersWhenProtected =
+ !getRenderEngine().supportsProtectedContent()};
mLayerSnapshotBuilder.update(args);
auto getLayerSnapshotsFn =
@@ -8695,7 +8703,9 @@
.excludeLayerIds = std::move(excludeLayerIds),
.supportedLayerGenericMetadata =
getHwComposer().getSupportedLayerGenericMetadata(),
- .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()};
+ .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(),
+ .skipRoundCornersWhenProtected =
+ !getRenderEngine().supportsProtectedContent()};
mLayerSnapshotBuilder.update(args);
auto getLayerSnapshotsFn =
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e8a9cfe..14fa492 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -600,7 +600,6 @@
EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
- EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
EXPECT_EQ(false, layer.source.buffer.isOpaque);
EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x);
diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp
index 1c9aee7..d30d5b8 100644
--- a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp
@@ -99,8 +99,7 @@
}
void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
- auto c = layer->getDrawingState();
- layer->commitTransaction(c);
+ layer->commitTransaction();
}
namespace {
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index e475b84..1380555 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -17,6 +17,8 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <gui/fake/BufferData.h>
+
#include "Client.h" // temporarily needed for LayerCreationArgs
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHierarchy.h"
@@ -333,6 +335,32 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setRoundedCorners(uint32_t id, float radius) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eCornerRadiusChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.cornerRadius = radius;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setBuffer(uint32_t id, std::shared_ptr<renderengine::ExternalTexture> texture) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eBufferChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().externalTexture = texture;
+ transactions.back().states.front().state.bufferData =
+ std::make_shared<fake::BufferData>(texture->getId(), texture->getWidth(),
+ texture->getHeight(), texture->getPixelFormat(),
+ texture->getUsage());
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
LayerLifecycleManager mLifecycleManager;
};
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index a581d5b..65bac00 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -17,6 +17,8 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <renderengine/mock/FakeExternalTexture.h>
+
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
#include "FrontEnd/LayerSnapshotBuilder.h"
@@ -68,12 +70,17 @@
setColor(id);
}
- void updateAndVerify(LayerSnapshotBuilder& actualBuilder, bool hasDisplayChanges,
- const std::vector<uint32_t> expectedVisibleLayerIdsInZOrder) {
+ void update(LayerSnapshotBuilder& actualBuilder, LayerSnapshotBuilder::Args& args) {
if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) {
mHierarchyBuilder.update(mLifecycleManager.getLayers(),
mLifecycleManager.getDestroyedLayers());
}
+ args.root = mHierarchyBuilder.getHierarchy();
+ actualBuilder.update(args);
+ }
+
+ void updateAndVerify(LayerSnapshotBuilder& actualBuilder, bool hasDisplayChanges,
+ const std::vector<uint32_t> expectedVisibleLayerIdsInZOrder) {
LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
.layerLifecycleManager = mLifecycleManager,
.includeMetadata = false,
@@ -83,7 +90,7 @@
.supportsBlur = true,
.supportedLayerGenericMetadata = {},
.genericLayerMetadataKeyMap = {}};
- actualBuilder.update(args);
+ update(actualBuilder, args);
// rebuild layer snapshots from scratch and verify that it matches the updated state.
LayerSnapshotBuilder expectedBuilder(args);
@@ -596,4 +603,50 @@
scheduler::LayerInfo::FrameRateCompatibility::Default);
}
+TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) {
+ setRoundedCorners(1, 42.f);
+ setRoundedCorners(2, 42.f);
+ setCrop(1, Rect{1000, 1000});
+ setCrop(2, Rect{1000, 1000});
+
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_TRUE(getSnapshot({.id = 1})->roundedCorner.hasRoundedCorners());
+ EXPECT_EQ(getSnapshot({.id = 1})->roundedCorner.radius.x, 42.f);
+ EXPECT_TRUE(getSnapshot({.id = 2})->roundedCorner.hasRoundedCorners());
+
+ // add a buffer with the protected bit, check rounded corners are not set when
+ // skipRoundCornersWhenProtected == true
+ setBuffer(1,
+ std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_PROTECTED /*usage*/));
+
+ LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = false,
+ .displays = mFrontEndDisplayInfos,
+ .displayChanges = false,
+ .globalShadowSettings = globalShadowSettings,
+ .supportsBlur = true,
+ .supportedLayerGenericMetadata = {},
+ .genericLayerMetadataKeyMap = {},
+ .skipRoundCornersWhenProtected = true};
+ update(mSnapshotBuilder, args);
+ EXPECT_FALSE(getSnapshot({.id = 1})->roundedCorner.hasRoundedCorners());
+ // layer 2 doesn't have a buffer and should be unaffected
+ EXPECT_TRUE(getSnapshot({.id = 2})->roundedCorner.hasRoundedCorners());
+
+ // remove protected bit, check rounded corners are set
+ setBuffer(1,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 2ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ update(mSnapshotBuilder, args);
+ EXPECT_TRUE(getSnapshot({.id = 1})->roundedCorner.hasRoundedCorners());
+ EXPECT_EQ(getSnapshot({.id = 1})->roundedCorner.radius.x, 42.f);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 44ab569..a1e4e25 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -85,8 +85,7 @@
void SetFrameRateTest::commitTransaction() {
for (auto layer : mLayers) {
- auto c = layer->getDrawingState();
- layer->commitTransaction(c);
+ layer->commitTransaction();
}
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 764d19b..00b5bf0 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -61,10 +61,7 @@
return sp<Layer>::make(args);
}
- void commitTransaction(Layer* layer) {
- auto c = layer->getDrawingState();
- layer->commitTransaction(c);
- }
+ void commitTransaction(Layer* layer) { layer->commitTransaction(); }
TestableSurfaceFlinger mFlinger;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index e2c6491..caa265f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -60,10 +60,7 @@
return sp<Layer>::make(args);
}
- void commitTransaction(Layer* layer) {
- auto c = layer->getDrawingState();
- layer->commitTransaction(c);
- }
+ void commitTransaction(Layer* layer) { layer->commitTransaction(); }
TestableSurfaceFlinger mFlinger;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index a14fed2..d059f8f 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -23,6 +23,7 @@
#include <dlfcn.h>
#include <string.h>
#include <sys/prctl.h>
+#include <unistd.h>
#include <mutex>
#include <string>
@@ -362,6 +363,7 @@
void ForEachFileInZip(const std::string& zipname,
const std::string& dir_in_zip,
Functor functor) {
+ static const size_t kPageSize = getpagesize();
int32_t err;
ZipArchiveHandle zip = nullptr;
if ((err = OpenArchive(zipname.c_str(), &zip)) != 0) {
@@ -389,7 +391,7 @@
// the APK. Loading still may fail for other reasons, but this at least
// lets us avoid failed-to-load log messages in the typical case of
// compressed and/or unaligned libraries.
- if (entry.method != kCompressStored || entry.offset % PAGE_SIZE != 0)
+ if (entry.method != kCompressStored || entry.offset % kPageSize != 0)
continue;
functor(filename);
}