Merge "SF: Add support for boundless layers 1/2"
diff --git a/libs/gui/CleanSpec.mk b/CleanSpec.mk
similarity index 70%
rename from libs/gui/CleanSpec.mk
rename to CleanSpec.mk
index 5a5144c..1855d26 100644
--- a/libs/gui/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 The Android Open Source Project
+# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -34,19 +34,23 @@
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/thermalserviced)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/thermalservice.rc)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 16abc1e..08218b8 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,8 +6,10 @@
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
libs/graphicsenv/
libs/gui/
+ libs/renderengine/
libs/ui/
libs/vr/
+ services/bufferhub/
services/surfaceflinger/
services/vr/
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d950b7c..d6ca0bf 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -91,7 +91,12 @@
chmod 0666 /sys/kernel/tracing/events/sync/enable
chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
chmod 0666 /sys/kernel/tracing/events/fence/enable
-
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable
+ chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable
+ chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable
+ chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable
# disk
chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 260ea4b..71658d8 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -87,27 +87,27 @@
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
dprintf(fd, "id: %d\n", ds_.id_);
dprintf(fd, "pid: %d\n", ds_.pid_);
- dprintf(fd, "update_progress: %s\n", ds_.update_progress_ ? "true" : "false");
+ dprintf(fd, "update_progress: %s\n", ds_.options_->do_progress_updates ? "true" : "false");
dprintf(fd, "update_progress_threshold: %d\n", ds_.update_progress_threshold_);
dprintf(fd, "last_updated_progress: %d\n", ds_.last_updated_progress_);
dprintf(fd, "progress:\n");
ds_.progress_->Dump(fd, " ");
- dprintf(fd, "args: %s\n", ds_.args_.c_str());
- dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
+ dprintf(fd, "args: %s\n", ds_.options_->args.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
dprintf(fd, "version: %s\n", ds_.version_.c_str());
dprintf(fd, "bugreport_dir: %s\n", ds_.bugreport_dir_.c_str());
dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
dprintf(fd, "path: %s\n", ds_.path_.c_str());
- dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str());
dprintf(fd, "name: %s\n", ds_.name_.c_str());
dprintf(fd, "now: %ld\n", ds_.now_);
dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
- dprintf(fd, "notification title: %s\n", ds_.notification_title.c_str());
- dprintf(fd, "notification description: %s\n", ds_.notification_description.c_str());
+ dprintf(fd, "notification title: %s\n", ds_.options_->notification_title.c_str());
+ dprintf(fd, "notification description: %s\n", ds_.options_->notification_description.c_str());
return NO_ERROR;
}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 17bb7c3..904c0e9 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -682,7 +682,7 @@
CommandOptions::WithTimeout(1).Always().Build());
printf("Bugreport format version: %s\n", version_.c_str());
printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
- PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
+ PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
printf("\n");
}
@@ -1374,6 +1374,12 @@
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
printf("========================================================\n");
+
+ printf("========================================================\n");
+ printf("== Obtaining statsd metadata\n");
+ printf("========================================================\n");
+ // This differs from the usual dumpsys stats, which is the stats report data.
+ RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
}
/* Dumps state for the default case. Returns true if everything went fine. */
@@ -1623,7 +1629,7 @@
printf("*** See dumpstate-board.txt entry ***\n");
}
-static void ShowUsageAndExit(int exitCode = 1) {
+static void ShowUsageAndExit(int exit_code = 1) {
fprintf(stderr,
"usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
"[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1643,7 +1649,7 @@
" -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
"shouldn't be used with -P)\n"
" -v: prints the dumpstate header and exit\n");
- exit(exitCode);
+ exit(exit_code);
}
static void ExitOnInvalidArgs() {
@@ -1769,13 +1775,13 @@
* if we are writing zip files and adds the version file.
*/
static void PrepareToWriteToFile() {
- const Dumpstate::DumpOptions& options = ds.options_;
- ds.bugreport_dir_ = dirname(options.use_outfile.c_str());
+ ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
- ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(options.use_outfile.c_str()),
- device_name.c_str(), build_id.c_str());
- if (options.do_add_date) {
+ ds.base_name_ =
+ android::base::StringPrintf("%s-%s-%s", basename(ds.options_->use_outfile.c_str()),
+ device_name.c_str(), build_id.c_str());
+ if (ds.options_->do_add_date) {
char date[80];
strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
ds.name_ = date;
@@ -1783,13 +1789,13 @@
ds.name_ = "undated";
}
- if (options.telephony_only) {
+ if (ds.options_->telephony_only) {
ds.base_name_ += "-telephony";
- } else if (options.wifi_only) {
+ } else if (ds.options_->wifi_only) {
ds.base_name_ += "-wifi";
}
- if (options.do_fb) {
+ if (ds.options_->do_fb) {
ds.screenshot_path_ = ds.GetPath(".png");
}
ds.tmp_path_ = ds.GetPath(".tmp");
@@ -1805,7 +1811,7 @@
ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
- if (options.do_zip_file) {
+ if (ds.options_->do_zip_file) {
ds.path_ = ds.GetPath(".zip");
MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
create_parent_dirs(ds.path_.c_str());
@@ -1824,7 +1830,6 @@
* printing zipped file status, etc.
*/
static void FinalizeFile() {
- const Dumpstate::DumpOptions& options = ds.options_;
/* check if user changed the suffix using system properties */
std::string name =
android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
@@ -1853,7 +1858,7 @@
}
bool do_text_file = true;
- if (options.do_zip_file) {
+ if (ds.options_->do_zip_file) {
if (!ds.FinishZipFile()) {
MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
do_text_file = true;
@@ -1880,7 +1885,7 @@
ds.path_.clear();
}
}
- if (options.use_control_socket) {
+ if (ds.options_->use_control_socket) {
if (do_text_file) {
dprintf(ds.control_socket_fd_,
"FAIL:could not create zip file, check %s "
@@ -1894,7 +1899,6 @@
/* Broadcasts that we are done with the bugreport */
static void SendBugreportFinishedBroadcast() {
- const Dumpstate::DumpOptions& options = ds.options_;
if (!ds.path_.empty()) {
MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
// clang-format off
@@ -1908,22 +1912,22 @@
"--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
};
// clang-format on
- if (options.do_fb) {
+ if (ds.options_->do_fb) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.SCREENSHOT");
am_args.push_back(ds.screenshot_path_);
}
- if (!ds.notification_title.empty()) {
+ if (ds.options_->notification_title.empty()) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.TITLE");
- am_args.push_back(ds.notification_title);
- if (!ds.notification_description.empty()) {
+ am_args.push_back(ds.options_->notification_title);
+ if (!ds.options_->notification_description.empty()) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.DESCRIPTION");
- am_args.push_back(ds.notification_description);
+ am_args.push_back(ds.options_->notification_description);
}
}
- if (options.is_remote_mode) {
+ if (ds.options_->is_remote_mode) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
am_args.push_back(SHA256_file_hash(ds.path_));
@@ -1936,30 +1940,77 @@
}
}
-int Dumpstate::ParseCommandlineOptions(int argc, char* argv[]) {
- int ret = -1; // success
+// TODO: Move away from system properties when we have options passed via binder calls.
+/* Sets runtime options from the system properties and then clears those properties. */
+static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
+ options->extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
+ if (!options->extra_options.empty()) {
+ // Framework uses a system property to override some command-line args.
+ // Currently, it contains the type of the requested bugreport.
+ if (options->extra_options == "bugreportplus") {
+ // Currently, the dumpstate binder is only used by Shell to update progress.
+ options->do_start_service = true;
+ options->do_progress_updates = true;
+ options->do_fb = false;
+ } else if (options->extra_options == "bugreportremote") {
+ options->do_vibrate = false;
+ options->is_remote_mode = true;
+ options->do_fb = false;
+ } else if (options->extra_options == "bugreportwear") {
+ options->do_start_service = true;
+ options->do_progress_updates = true;
+ options->do_zip_file = true;
+ } else if (options->extra_options == "bugreporttelephony") {
+ options->telephony_only = true;
+ } else if (options->extra_options == "bugreportwifi") {
+ options->wifi_only = true;
+ options->do_zip_file = true;
+ } else {
+ MYLOGE("Unknown extra option: %s\n", options->extra_options.c_str());
+ }
+ // Reset the property
+ android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
+ }
+
+ options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
+ if (!options->notification_title.empty()) {
+ // Reset the property
+ android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
+
+ options->extra_options = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+ if (!options->notification_description.empty()) {
+ // Reset the property
+ android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+ }
+ MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
+ options->notification_description.c_str());
+ }
+}
+
+Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
+ RunStatus status = RunStatus::OK;
int c;
while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
switch (c) {
// clang-format off
- case 'd': options_.do_add_date = true; break;
- case 'z': options_.do_zip_file = true; break;
- case 'o': options_.use_outfile = optarg; break;
- case 's': options_.use_socket = true; break;
- case 'S': options_.use_control_socket = true; break;
- case 'v': options_.show_header_only = true; break;
- case 'q': options_.do_vibrate = false; break;
- case 'p': options_.do_fb = true; break;
- case 'P': update_progress_ = true; break;
- case 'R': options_.is_remote_mode = true; break;
- case 'B': options_.do_broadcast = true; break;
- case 'V': break; // compatibility no-op
+ case 'd': do_add_date = true; break;
+ case 'z': do_zip_file = true; break;
+ case 'o': use_outfile = optarg; break;
+ case 's': use_socket = true; break;
+ case 'S': use_control_socket = true; break;
+ case 'v': show_header_only = true; break;
+ case 'q': do_vibrate = false; break;
+ case 'p': do_fb = true; break;
+ case 'P': do_progress_updates = true; break;
+ case 'R': is_remote_mode = true; break;
+ case 'B': do_broadcast = true; break;
+ case 'V': break; // compatibility no-op
case 'h':
- ret = 0;
+ status = RunStatus::HELP;
break;
default:
fprintf(stderr, "Invalid option: %c\n", c);
- ret = 1;
+ status = RunStatus::INVALID_INPUT;
break;
// clang-format on
}
@@ -1967,87 +2018,44 @@
// TODO: use helper function to convert argv into a string
for (int i = 0; i < argc; i++) {
- args_ += argv[i];
+ args += argv[i];
if (i < argc - 1) {
- args_ += " ";
+ args += " ";
}
}
// Reset next index used by getopt so this can be called multiple times, for eg, in tests.
optind = 1;
- return ret;
+
+ SetOptionsFromProperties(this);
+ return status;
}
-// TODO: Move away from system properties when we have binder.
-void Dumpstate::SetOptionsFromProperties() {
- extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
- if (!extra_options_.empty()) {
- // Framework uses a system property to override some command-line args.
- // Currently, it contains the type of the requested bugreport.
- if (extra_options_ == "bugreportplus") {
- // Currently, the dumpstate binder is only used by Shell to update progress.
- options_.do_start_service = true;
- update_progress_ = true;
- options_.do_fb = false;
- } else if (extra_options_ == "bugreportremote") {
- options_.do_vibrate = false;
- options_.is_remote_mode = true;
- options_.do_fb = false;
- } else if (extra_options_ == "bugreportwear") {
- options_.do_start_service = true;
- update_progress_ = true;
- options_.do_zip_file = true;
- } else if (extra_options_ == "bugreporttelephony") {
- options_.telephony_only = true;
- } else if (extra_options_ == "bugreportwifi") {
- options_.wifi_only = true;
- options_.do_zip_file = true;
- } else {
- MYLOGE("Unknown extra option: %s\n", extra_options_.c_str());
- }
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
- }
-
- notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
- if (!notification_title.empty()) {
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
-
- notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
- if (!notification_description.empty()) {
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
- }
- MYLOGD("notification (title: %s, description: %s)\n", notification_title.c_str(),
- notification_description.c_str());
- }
-}
-
-bool Dumpstate::ValidateOptions() {
- if ((options_.do_zip_file || options_.do_add_date || ds.update_progress_ ||
- options_.do_broadcast) &&
- options_.use_outfile.empty()) {
+bool Dumpstate::DumpOptions::ValidateOptions() const {
+ if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast)
+ && use_outfile.empty()) {
return false;
}
- if (options_.use_control_socket && !options_.do_zip_file) {
+ if (use_control_socket && !do_zip_file) {
return false;
}
- if (ds.update_progress_ && !options_.do_broadcast) {
+ if (do_progress_updates && !do_broadcast) {
return false;
}
- if (options_.is_remote_mode && (ds.update_progress_ || !options_.do_broadcast ||
- !options_.do_zip_file || !options_.do_add_date)) {
+ if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
return false;
}
return true;
}
-/* Main entry point for dumpstate. */
-int run_main(int argc, char* argv[]) {
+Dumpstate::RunStatus Dumpstate::RunWithOptions(std::unique_ptr<DumpOptions> options) {
+ if (!options->ValidateOptions()) {
+ return RunStatus::INVALID_INPUT;
+ }
+ options_ = std::move(options);
/* set as high priority, and protect from OOM killer */
setpriority(PRIO_PROCESS, 0, -20);
@@ -2064,52 +2072,42 @@
}
}
- int status = ds.ParseCommandlineOptions(argc, argv);
- if (status != -1) {
- ShowUsageAndExit(status);
- }
- ds.SetOptionsFromProperties();
- if (!ds.ValidateOptions()) {
- ExitOnInvalidArgs();
+ if (version_ == VERSION_DEFAULT) {
+ version_ = VERSION_CURRENT;
}
- if (ds.version_ == VERSION_DEFAULT) {
- ds.version_ = VERSION_CURRENT;
- }
-
- if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
+ if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
- ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
+ version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
VERSION_SPLIT_ANR.c_str());
- exit(1);
+ return RunStatus::INVALID_INPUT;
}
- const Dumpstate::DumpOptions& options = ds.options_;
- if (options.show_header_only) {
- ds.PrintHeader();
- exit(0);
+ if (options_->show_header_only) {
+ PrintHeader();
+ return RunStatus::OK;
}
// Redirect output if needed
- bool is_redirecting = !options.use_socket && !options.use_outfile.empty();
+ bool is_redirecting = !options_->use_socket && !options_->use_outfile.empty();
// TODO: temporarily set progress until it's part of the Dumpstate constructor
- std::string stats_path = is_redirecting
- ? android::base::StringPrintf("%s/dumpstate-stats.txt",
- dirname(options.use_outfile.c_str()))
- : "";
- ds.progress_.reset(new Progress(stats_path));
+ std::string stats_path =
+ is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt",
+ dirname(options_->use_outfile.c_str()))
+ : "";
+ progress_.reset(new Progress(stats_path));
/* gets the sequential id */
uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
- ds.id_ = ++last_id;
+ id_ = ++last_id;
android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
MYLOGI("begin\n");
register_sig_handler();
- if (options.do_start_service) {
+ if (options_->do_start_service) {
MYLOGI("Starting 'dumpstate' service\n");
android::status_t ret;
if ((ret = android::os::DumpstateService::Start()) != android::OK) {
@@ -2121,43 +2119,43 @@
MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
}
- MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
- ds.extra_options_.c_str());
+ MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
+ options_->extra_options.c_str());
- MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
+ MYLOGI("bugreport format version: %s\n", version_.c_str());
- ds.do_early_screenshot_ = ds.update_progress_;
+ do_early_screenshot_ = options_->do_progress_updates;
// If we are going to use a socket, do it as early as possible
// to avoid timeouts from bugreport.
- if (options.use_socket) {
+ if (options_->use_socket) {
redirect_to_socket(stdout, "dumpstate");
}
- if (options.use_control_socket) {
+ if (options_->use_control_socket) {
MYLOGD("Opening control socket\n");
- ds.control_socket_fd_ = open_socket("dumpstate");
- ds.update_progress_ = 1;
+ control_socket_fd_ = open_socket("dumpstate");
+ options_->do_progress_updates = 1;
}
if (is_redirecting) {
PrepareToWriteToFile();
- if (ds.update_progress_) {
- if (options.do_broadcast) {
+ if (options_->do_progress_updates) {
+ if (options_->do_broadcast) {
// clang-format off
std::vector<std::string> am_args = {
"--receiver-permission", "android.permission.DUMP",
- "--es", "android.intent.extra.NAME", ds.name_,
- "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
- "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
- "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
+ "--es", "android.intent.extra.NAME", name_,
+ "--ei", "android.intent.extra.ID", std::to_string(id_),
+ "--ei", "android.intent.extra.PID", std::to_string(pid_),
+ "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
};
// clang-format on
SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
}
- if (options.use_control_socket) {
- dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
+ if (options_->use_control_socket) {
+ dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
}
}
}
@@ -2169,23 +2167,23 @@
fclose(cmdline);
}
- if (options.do_vibrate) {
+ if (options_->do_vibrate) {
Vibrate(150);
}
- if (options.do_fb && ds.do_early_screenshot_) {
- if (ds.screenshot_path_.empty()) {
+ if (options_->do_fb && do_early_screenshot_) {
+ if (screenshot_path_.empty()) {
// should not have happened
MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
} else {
MYLOGI("taking early screenshot\n");
- ds.TakeScreenshot();
+ TakeScreenshot();
}
}
- if (options.do_zip_file && ds.zip_file != nullptr) {
- if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
+ if (options_->do_zip_file && zip_file != nullptr) {
+ if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
+ MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
strerror(errno));
}
}
@@ -2194,19 +2192,19 @@
int dup_stderr_fd;
if (is_redirecting) {
TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
- redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
- if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
- ds.log_path_.c_str(), strerror(errno));
+ redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()));
+ if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
+ MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
+ strerror(errno));
}
TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
/* TODO: rather than generating a text file now and zipping it later,
it would be more efficient to redirect stdout to the zip entry
directly, but the libziparchive doesn't support that option yet. */
- redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str()));
- if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
+ redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()));
+ if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
- ds.tmp_path_.c_str(), strerror(errno));
+ tmp_path_.c_str(), strerror(errno));
}
}
@@ -2216,18 +2214,18 @@
// NOTE: there should be no stdout output until now, otherwise it would break the header.
// In particular, DurationReport objects should be created passing 'title, NULL', so their
// duration is logged into MYLOG instead.
- ds.PrintHeader();
+ PrintHeader();
- if (options.telephony_only) {
+ if (options_->telephony_only) {
DumpstateTelephonyOnly();
- ds.DumpstateBoard();
- } else if (options.wifi_only) {
+ DumpstateBoard();
+ } else if (options_->wifi_only) {
DumpstateWifiOnly();
} else {
// Dump state for the default case. This also drops root.
if (!DumpstateDefault()) {
// Something went wrong.
- return -1;
+ return RunStatus::ERROR;
}
}
@@ -2237,12 +2235,12 @@
}
/* rename or zip the (now complete) .tmp file to its final location */
- if (!options.use_outfile.empty()) {
+ if (!options_->use_outfile.empty()) {
FinalizeFile();
}
/* vibrate a few but shortly times to let user know it's finished */
- if (options.do_vibrate) {
+ if (options_->do_vibrate) {
for (int i = 0; i < 3; i++) {
Vibrate(75);
usleep((75 + 50) * 1000);
@@ -2250,26 +2248,51 @@
}
/* tell activity manager we're done */
- if (options.do_broadcast) {
+ if (options_->do_broadcast) {
SendBugreportFinishedBroadcast();
}
- MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
- ds.progress_->GetInitialMax());
- ds.progress_->Save();
- MYLOGI("done (id %d)\n", ds.id_);
+ MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
+ progress_->GetInitialMax());
+ progress_->Save();
+ MYLOGI("done (id %d)\n", id_);
if (is_redirecting) {
TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
}
- if (options.use_control_socket && ds.control_socket_fd_ != -1) {
+ if (options_->use_control_socket && control_socket_fd_ != -1) {
MYLOGD("Closing control socket\n");
- close(ds.control_socket_fd_);
+ close(control_socket_fd_);
}
- ds.tombstone_data_.clear();
- ds.anr_data_.clear();
+ tombstone_data_.clear();
+ anr_data_.clear();
+ return RunStatus::OK;
+}
+
+/* Main entry point for dumpstate. */
+int run_main(int argc, char* argv[]) {
+ std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
+ Dumpstate::RunStatus status = options->Initialize(argc, argv);
+ if (status == Dumpstate::RunStatus::OK) {
+ status = ds.RunWithOptions(std::move(options));
+ }
+
+ switch (status) {
+ case Dumpstate::RunStatus::OK:
+ return 0;
+ break;
+ case Dumpstate::RunStatus::HELP:
+ ShowUsageAndExit(0 /* exit code */);
+ break;
+ case Dumpstate::RunStatus::INVALID_INPUT:
+ ExitOnInvalidArgs();
+ break;
+ case Dumpstate::RunStatus::ERROR:
+ exit(-1);
+ break;
+ }
return 0;
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 389cc2e..c2f7f6a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -183,6 +183,8 @@
friend class DumpstateTest;
public:
+ enum RunStatus { OK, HELP, INVALID_INPUT, ERROR };
+
static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS;
static Dumpstate& GetInstance();
@@ -290,22 +292,12 @@
/* Returns true if the current version supports priority dump feature. */
bool CurrentVersionSupportsPriorityDumps() const;
- // TODO: revisit the return values later.
- /*
- * Parses commandline arguments and sets runtime options accordingly.
- *
- * Returns 0 or positive number if the caller should exit with returned value as
- * exit code, or returns -1 if caller should proceed with execution.
- */
- int ParseCommandlineOptions(int argc, char* argv[]);
+ struct DumpOptions;
- /* Sets runtime options from the system properties. */
- void SetOptionsFromProperties();
+ /* Main entry point for running a complete bugreport. Takes ownership of options. */
+ RunStatus RunWithOptions(std::unique_ptr<DumpOptions> options);
- /* Returns true if the options set so far are consistent. */
- bool ValidateOptions();
-
- // TODO: add update_progress_ & other options from DumpState.
+ // TODO: add other options from DumpState.
/*
* Structure to hold options that determine the behavior of dumpstate.
*/
@@ -322,7 +314,22 @@
bool do_start_service = false;
bool telephony_only = false;
bool wifi_only = false;
+ // Whether progress updates should be published.
+ bool do_progress_updates = false;
std::string use_outfile;
+ // Extra options passed as system property.
+ std::string extra_options;
+ // Command-line arguments as string
+ std::string args;
+ // Notification title and description
+ std::string notification_title;
+ std::string notification_description;
+
+ /* Initializes options from commandline arguments and system properties. */
+ RunStatus Initialize(int argc, char* argv[]);
+
+ /* Returns true if the options set so far are consistent. */
+ bool ValidateOptions() const;
};
// TODO: initialize fields on constructor
@@ -333,10 +340,7 @@
pid_t pid_;
// Runtime options.
- DumpOptions options_;
-
- // Whether progress updates should be published.
- bool update_progress_ = false;
+ std::unique_ptr<DumpOptions> options_;
// How frequently the progess should be updated;the listener will only be notificated when the
// delta from the previous update is more than the threshold.
@@ -356,12 +360,6 @@
// Bugreport format version;
std::string version_ = VERSION_CURRENT;
- // Command-line arguments as string
- std::string args_;
-
- // Extra options passed as system property.
- std::string extra_options_;
-
// Full path of the directory where the bugreport files will be written.
std::string bugreport_dir_;
@@ -398,10 +396,6 @@
std::string listener_name_;
bool report_section_;
- // Notification title and description
- std::string notification_title;
- std::string notification_description;
-
// List of open tombstone dump files.
std::vector<DumpData> tombstone_data_;
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index c57535a..b675c51 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -137,6 +137,175 @@
}
};
+class DumpOptionsTest : public Test {
+ public:
+ virtual ~DumpOptionsTest() {
+ }
+ virtual void SetUp() {
+ options_ = Dumpstate::DumpOptions();
+ }
+
+ Dumpstate::DumpOptions options_;
+};
+
+TEST_F(DumpOptionsTest, InitializeNone) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate")
+ };
+ // clang-format on
+
+ Dumpstate::DumpOptions options;
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ EXPECT_FALSE(options_.do_add_date);
+ EXPECT_FALSE(options_.do_zip_file);
+ EXPECT_EQ("", options_.use_outfile);
+ EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.show_header_only);
+ EXPECT_TRUE(options_.do_vibrate);
+ EXPECT_FALSE(options_.do_fb);
+ EXPECT_FALSE(options_.do_progress_updates);
+ EXPECT_FALSE(options_.is_remote_mode);
+ EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializePartial1) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate"),
+ const_cast<char*>("-d"),
+ const_cast<char*>("-z"),
+ const_cast<char*>("-o abc"),
+ const_cast<char*>("-s"),
+ const_cast<char*>("-S"),
+
+ };
+ // clang-format on
+
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ EXPECT_TRUE(options_.do_add_date);
+ EXPECT_TRUE(options_.do_zip_file);
+ // TODO: Maybe we should trim the filename
+ EXPECT_EQ(" abc", std::string(options_.use_outfile));
+ EXPECT_TRUE(options_.use_socket);
+ EXPECT_TRUE(options_.use_control_socket);
+
+ // Other options retain default values
+ EXPECT_FALSE(options_.show_header_only);
+ EXPECT_TRUE(options_.do_vibrate);
+ EXPECT_FALSE(options_.do_fb);
+ EXPECT_FALSE(options_.do_progress_updates);
+ EXPECT_FALSE(options_.is_remote_mode);
+ EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializePartial2) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate"),
+ const_cast<char*>("-v"),
+ const_cast<char*>("-q"),
+ const_cast<char*>("-p"),
+ const_cast<char*>("-P"),
+ const_cast<char*>("-R"),
+ const_cast<char*>("-B"),
+ };
+ // clang-format on
+
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ EXPECT_TRUE(options_.show_header_only);
+ EXPECT_FALSE(options_.do_vibrate);
+ EXPECT_TRUE(options_.do_fb);
+ EXPECT_TRUE(options_.do_progress_updates);
+ EXPECT_TRUE(options_.is_remote_mode);
+ EXPECT_TRUE(options_.do_broadcast);
+
+ // Other options retain default values
+ EXPECT_FALSE(options_.do_add_date);
+ EXPECT_FALSE(options_.do_zip_file);
+ EXPECT_EQ("", options_.use_outfile);
+ EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.use_control_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeHelp) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate"),
+ const_cast<char*>("-h")
+ };
+ // clang-format on
+
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ // -h is for help.
+ EXPECT_EQ(status, Dumpstate::RunStatus::HELP);
+}
+
+TEST_F(DumpOptionsTest, InitializeUnknown) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate"),
+ const_cast<char*>("-u") // unknown flag
+ };
+ // clang-format on
+
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ // -u is unknown.
+ EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
+ options_.do_zip_file = true;
+ EXPECT_FALSE(options_.ValidateOptions());
+ options_.use_outfile = "a/b/c";
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
+ options_.do_broadcast = true;
+ EXPECT_FALSE(options_.ValidateOptions());
+ options_.use_outfile = "a/b/c";
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) {
+ options_.use_control_socket = true;
+ EXPECT_FALSE(options_.ValidateOptions());
+
+ options_.do_zip_file = true;
+ options_.use_outfile = "a/b/c"; // do_zip_file needs outfile
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
+ options_.do_progress_updates = true;
+ options_.use_outfile = "a/b/c"; // do_progress_updates needs outfile
+ EXPECT_FALSE(options_.ValidateOptions());
+
+ options_.do_broadcast = true;
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
+ options_.is_remote_mode = true;
+ EXPECT_FALSE(options_.ValidateOptions());
+
+ options_.do_broadcast = true;
+ options_.do_zip_file = true;
+ options_.do_add_date = true;
+ options_.use_outfile = "a/b/c"; // do_broadcast needs outfile
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
class DumpstateTest : public DumpstateBaseTest {
public:
void SetUp() {
@@ -144,9 +313,8 @@
SetDryRun(false);
SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
ds.progress_.reset(new Progress());
- ds.update_progress_ = false;
ds.update_progress_threshold_ = 0;
- ds.options_ = Dumpstate::DumpOptions();
+ ds.options_.reset(new Dumpstate::DumpOptions());
}
// Runs a command and capture `stdout` and `stderr`.
@@ -171,7 +339,7 @@
}
void SetProgress(long progress, long initial_max, long threshold = 0) {
- ds.update_progress_ = true;
+ ds.options_->do_progress_updates = true;
ds.update_progress_threshold_ = threshold;
ds.last_updated_progress_ = 0;
ds.progress_.reset(new Progress(initial_max, progress, 1.2));
@@ -204,157 +372,6 @@
Dumpstate& ds = Dumpstate::GetInstance();
};
-TEST_F(DumpstateTest, ParseCommandlineOptionsNone) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate")
- };
- // clang-format on
-
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
- EXPECT_EQ(-1, ret);
- EXPECT_FALSE(ds.options_.do_add_date);
- EXPECT_FALSE(ds.options_.do_zip_file);
- EXPECT_EQ("", ds.options_.use_outfile);
- EXPECT_FALSE(ds.options_.use_socket);
- EXPECT_FALSE(ds.options_.use_control_socket);
- EXPECT_FALSE(ds.options_.show_header_only);
- EXPECT_TRUE(ds.options_.do_vibrate);
- EXPECT_FALSE(ds.options_.do_fb);
- EXPECT_FALSE(ds.update_progress_);
- EXPECT_FALSE(ds.options_.is_remote_mode);
- EXPECT_FALSE(ds.options_.do_broadcast);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsPartial1) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate"),
- const_cast<char*>("-d"),
- const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
- const_cast<char*>("-s"),
- const_cast<char*>("-S"),
-
- };
- // clang-format on
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
- EXPECT_EQ(-1, ret);
- EXPECT_TRUE(ds.options_.do_add_date);
- EXPECT_TRUE(ds.options_.do_zip_file);
- // TODO: Maybe we should trim the filename
- EXPECT_EQ(" abc", std::string(ds.options_.use_outfile));
- EXPECT_TRUE(ds.options_.use_socket);
- EXPECT_TRUE(ds.options_.use_control_socket);
-
- // Other options retain default values
- EXPECT_FALSE(ds.options_.show_header_only);
- EXPECT_TRUE(ds.options_.do_vibrate);
- EXPECT_FALSE(ds.options_.do_fb);
- EXPECT_FALSE(ds.update_progress_);
- EXPECT_FALSE(ds.options_.is_remote_mode);
- EXPECT_FALSE(ds.options_.do_broadcast);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsPartial2) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate"),
- const_cast<char*>("-v"),
- const_cast<char*>("-q"),
- const_cast<char*>("-p"),
- const_cast<char*>("-P"),
- const_cast<char*>("-R"),
- const_cast<char*>("-B"),
- };
- // clang-format on
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
- EXPECT_EQ(-1, ret);
- EXPECT_TRUE(ds.options_.show_header_only);
- EXPECT_FALSE(ds.options_.do_vibrate);
- EXPECT_TRUE(ds.options_.do_fb);
- EXPECT_TRUE(ds.update_progress_);
- EXPECT_TRUE(ds.options_.is_remote_mode);
- EXPECT_TRUE(ds.options_.do_broadcast);
-
- // Other options retain default values
- EXPECT_FALSE(ds.options_.do_add_date);
- EXPECT_FALSE(ds.options_.do_zip_file);
- EXPECT_EQ("", ds.options_.use_outfile);
- EXPECT_FALSE(ds.options_.use_socket);
- EXPECT_FALSE(ds.options_.use_control_socket);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsHelp) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate"),
- const_cast<char*>("-h")
- };
- // clang-format on
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-
- // -h is for help. Caller exit with code = 0 after printing usage, so expect return = 0.
- EXPECT_EQ(0, ret);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsUnknown) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate"),
- const_cast<char*>("-u") // unknown flag
- };
- // clang-format on
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-
- // -u is unknown. Caller exit with code = 1 to show execution failure, after printing usage,
- // so expect return = 1.
- EXPECT_EQ(1, ret);
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedOutfile1) {
- ds.options_.do_zip_file = true;
- EXPECT_FALSE(ds.ValidateOptions());
- ds.options_.use_outfile = "a/b/c";
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedOutfile2) {
- ds.options_.do_broadcast = true;
- EXPECT_FALSE(ds.ValidateOptions());
- ds.options_.use_outfile = "a/b/c";
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedZipfile) {
- ds.options_.use_control_socket = true;
- EXPECT_FALSE(ds.ValidateOptions());
-
- ds.options_.do_zip_file = true;
- ds.options_.use_outfile = "a/b/c"; // do_zip_file needs outfile
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
- ds.update_progress_ = true;
- ds.options_.use_outfile = "a/b/c"; // update_progress_ needs outfile
- EXPECT_FALSE(ds.ValidateOptions());
-
- ds.options_.do_broadcast = true;
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsRemoteMode) {
- ds.options_.is_remote_mode = true;
- EXPECT_FALSE(ds.ValidateOptions());
-
- ds.options_.do_broadcast = true;
- ds.options_.do_zip_file = true;
- ds.options_.do_add_date = true;
- ds.options_.use_outfile = "a/b/c"; // do_broadcast needs outfile
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
TEST_F(DumpstateTest, RunCommandNoArgs) {
EXPECT_EQ(-1, RunCommand("", {}));
}
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 77f09b7..4ad5c4b 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -916,7 +916,7 @@
bool max_changed = progress_->Inc(delta_sec);
// ...but only notifiy listeners when necessary.
- if (!update_progress_) return;
+ if (!options_->do_progress_updates) return;
int progress = progress_->Get();
int max = progress_->GetMax();
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 9d0d8ba..2e9701f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -14,6 +14,7 @@
"CacheItem.cpp",
"CacheTracker.cpp",
"InstalldNativeService.cpp",
+ "QuotaUtils.cpp",
"dexopt.cpp",
"globals.cpp",
"utils.cpp",
@@ -33,6 +34,21 @@
"libutils",
],
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
+
clang: true,
tidy: true,
@@ -59,6 +75,26 @@
aidl: {
export_aidl_headers: true,
},
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
+}
+
+cc_library_headers {
+ name: "libinstalld_headers",
+ export_include_dirs: ["."],
}
//
@@ -73,6 +109,21 @@
static_libs: ["libdiskusage"],
init_rc: ["installd.rc"],
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
}
// OTA chroot tool
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index a7242c3..8b868fb 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -19,13 +19,13 @@
#include "CacheTracker.h"
#include <fts.h>
-#include <sys/quota.h>
#include <sys/xattr.h>
#include <utils/Trace.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "QuotaUtils.h"
#include "utils.h"
using android::base::StringPrintf;
@@ -33,9 +33,13 @@
namespace android {
namespace installd {
-CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
- cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
- mItemsLoaded(false) {
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& uuid)
+ : cacheUsed(0),
+ cacheQuota(0),
+ mUserId(userId),
+ mAppId(appId),
+ mItemsLoaded(false),
+ mUuid(uuid) {
}
CacheTracker::~CacheTracker() {
@@ -72,26 +76,18 @@
bool CacheTracker::loadQuotaStats() {
int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId);
- if (!mQuotaDevice.empty() && cacheGid != -1 && extCacheGid != -1) {
- struct dqblk dq;
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
- }
- return false;
+ if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) {
+ int64_t space;
+ if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) {
+ cacheUsed += space;
} else {
- cacheUsed += dq.dqb_curspace;
+ return false;
}
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), extCacheGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
- }
- return false;
+ if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) {
+ cacheUsed += space;
} else {
- cacheUsed += dq.dqb_curspace;
+ return false;
}
return true;
} else {
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
index 44359b4..b0527e7 100644
--- a/cmds/installd/CacheTracker.h
+++ b/cmds/installd/CacheTracker.h
@@ -39,7 +39,7 @@
*/
class CacheTracker {
public:
- CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+ CacheTracker(userid_t userId, appid_t appId, const std::string& uuid);
~CacheTracker();
std::string toString();
@@ -61,8 +61,8 @@
private:
userid_t mUserId;
appid_t mAppId;
- std::string mQuotaDevice;
bool mItemsLoaded;
+ const std::string& mUuid;
std::vector<std::string> mDataPaths;
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e4990b0..81055d8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -31,7 +31,6 @@
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
-#include <sys/quota.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@@ -64,6 +63,7 @@
#include "CacheTracker.h"
#include "MatchExtensionGen.h"
+#include "QuotaUtils.h"
#ifndef LOG_TAG
#define LOG_TAG "installd"
@@ -77,7 +77,6 @@
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";
-static constexpr const char* kPropHasReserved = "vold.has_reserved";
static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
@@ -258,11 +257,6 @@
for (const auto& n : mStorageMounts) {
out << " " << n.first << " = " << n.second << endl;
}
-
- out << endl << "Quota reverse mounts:" << endl;
- for (const auto& n : mQuotaReverseMounts) {
- out << " " << n.first << " = " << n.second << endl;
- }
}
{
@@ -343,55 +337,6 @@
return 0;
}
-/**
- * Ensure that we have a hard-limit quota to protect against abusive apps;
- * they should never use more than 90% of blocks or 50% of inodes.
- */
-static int prepare_app_quota(const std::unique_ptr<std::string>& uuid ATTRIBUTE_UNUSED,
- const std::string& device, uid_t uid) {
- // Skip when reserved blocks are protecting us against abusive apps
- if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0;
- // Skip when device no quotas present
- if (device.empty()) return 0;
-
- struct dqblk dq;
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
- reinterpret_cast<char*>(&dq)) != 0) {
- PLOG(WARNING) << "Failed to find quota for " << uid;
- return -1;
- }
-
-#if APPLY_HARD_QUOTAS
- if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
- auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
- struct statvfs stat;
- if (statvfs(path.c_str(), &stat) != 0) {
- PLOG(WARNING) << "Failed to statvfs " << path;
- return -1;
- }
-
- dq.dqb_valid = QIF_LIMITS;
- dq.dqb_bhardlimit =
- (((static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
- dq.dqb_ihardlimit = (stat.f_files / 2);
- if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
- reinterpret_cast<char*>(&dq)) != 0) {
- PLOG(WARNING) << "Failed to set hard quota for " << uid;
- return -1;
- } else {
- LOG(DEBUG) << "Applied hard quotas for " << uid;
- return 0;
- }
- } else {
- // Hard quota already set; assume it's reasonable
- return 0;
- }
-#else
- // Hard quotas disabled
- return 0;
-#endif
-}
-
static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
return true;
@@ -506,10 +451,6 @@
return error("Failed to restorecon " + path);
}
- if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
- return error("Failed to set hard quota " + path);
- }
-
if (!prepare_app_profile_dir(packageName, appId, userId)) {
return error("Failed to prepare profiles for " + packageName);
}
@@ -616,6 +557,10 @@
// No code cache on shared storage
} else {
// Clear everything on shared storage
+ path = StringPrintf("%s/Android/sandbox/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
if (delete_dir_contents(path, true) != 0) {
res = error("Failed to delete contents of " + path);
@@ -699,6 +644,10 @@
}
auto extPath = findDataMediaPath(uuid, userId);
+ path = StringPrintf("%s/Android/sandbox/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
@@ -988,13 +937,6 @@
}
}
- // Data under /data/media doesn't have an app, but we still want
- // to limit it to prevent abuse.
- if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
- multiuser_get_uid(userId, AID_MEDIA_RW))) {
- return error("Failed to set hard quota for media_rw");
- }
-
return ok();
}
@@ -1041,9 +983,9 @@
CHECK_ARGUMENT_UUID(uuid);
std::lock_guard<std::recursive_mutex> lock(mLock);
+ auto uuidString = uuid ? *uuid : "";
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
auto data_path = create_data_path(uuid_);
- auto device = findQuotaDeviceForUuid(uuid);
auto noop = (flags & FLAG_FREE_CACHE_NOOP);
int64_t free = data_disk_free(data_path);
@@ -1090,7 +1032,7 @@
search->second->addDataPath(p->fts_path);
} else {
auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
- multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+ multiuser_get_user_id(uid), multiuser_get_app_id(uid), uuidString));
tracker->addDataPath(p->fts_path);
{
std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
@@ -1255,53 +1197,26 @@
}
#endif
-static void collectQuotaStats(const std::string& device, int32_t userId,
+static void collectQuotaStats(const std::string& uuid, int32_t userId,
int32_t appId, struct stats* stats, struct stats* extStats) {
- if (device.empty()) return;
-
- struct dqblk dq;
-
+ int64_t space;
if (stats != nullptr) {
uid_t uid = multiuser_get_uid(userId, appId);
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
- stats->dataSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+ stats->dataSize += space;
}
int cacheGid = multiuser_get_cache_gid(userId, appId);
if (cacheGid != -1) {
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
-#endif
- stats->cacheSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+ stats->cacheSize += space;
}
}
int sharedGid = multiuser_get_shared_gid(0, appId);
if (sharedGid != -1) {
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
-#endif
- stats->codeSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) {
+ stats->codeSize += space;
}
}
}
@@ -1309,32 +1224,16 @@
if (extStats != nullptr) {
int extGid = multiuser_get_ext_gid(userId, appId);
if (extGid != -1) {
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
-#endif
- extStats->dataSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) {
+ extStats->dataSize += space;
}
}
int extCacheGid = multiuser_get_ext_cache_gid(userId, appId);
if (extCacheGid != -1) {
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extCacheGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extCacheGid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << extCacheGid << " " << dq.dqb_curspace;
-#endif
- extStats->dataSize += dq.dqb_curspace;
- extStats->cacheSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) {
+ extStats->dataSize += space;
+ extStats->cacheSize += space;
}
}
}
@@ -1498,10 +1397,10 @@
memset(&stats, 0, sizeof(stats));
memset(&extStats, 0, sizeof(extStats));
+ auto uuidString = uuid ? *uuid : "";
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- auto device = findQuotaDeviceForUuid(uuid);
- if (device.empty()) {
+ if (!IsQuotaSupported(uuidString)) {
flags &= ~FLAG_USE_QUOTA;
}
@@ -1521,7 +1420,7 @@
ATRACE_END();
ATRACE_BEGIN("quota");
- collectQuotaStats(device, userId, appId, &stats, &extStats);
+ collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
ATRACE_END();
} else {
ATRACE_BEGIN("code");
@@ -1552,6 +1451,8 @@
}
ATRACE_BEGIN("external");
+ auto sandboxPath = create_data_media_package_path(uuid_, userId, "sandbox", pkgname);
+ calculate_tree_size(sandboxPath, &extStats.dataSize);
auto extPath = create_data_media_package_path(uuid_, userId, "data", pkgname);
collectManualStats(extPath, &extStats);
auto mediaPath = create_data_media_package_path(uuid_, userId, "media", pkgname);
@@ -1604,27 +1505,19 @@
memset(&stats, 0, sizeof(stats));
memset(&extStats, 0, sizeof(extStats));
+ auto uuidString = uuid ? *uuid : "";
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- auto device = findQuotaDeviceForUuid(uuid);
- if (device.empty()) {
+ if (!IsQuotaSupported(uuidString)) {
flags &= ~FLAG_USE_QUOTA;
}
if (flags & FLAG_USE_QUOTA) {
- struct dqblk dq;
+ int64_t space;
ATRACE_BEGIN("obb");
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
- extStats.codeSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+ extStats.codeSize += space;
}
ATRACE_END();
@@ -1650,16 +1543,8 @@
ATRACE_BEGIN("external");
uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
- extStats.dataSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+ extStats.dataSize += space;
}
ATRACE_END();
@@ -1676,7 +1561,7 @@
int64_t dataSize = extStats.dataSize;
for (auto appId : appIds) {
if (appId >= AID_APP_START) {
- collectQuotaStats(device, userId, appId, &stats, &extStats);
+ collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
#if MEASURE_DEBUG
// Sleep to make sure we don't lose logs
@@ -1758,6 +1643,7 @@
LOG(INFO) << "Measuring external " << userId;
#endif
+ auto uuidString = uuid ? *uuid : "";
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
int64_t totalSize = 0;
@@ -1767,58 +1653,33 @@
int64_t appSize = 0;
int64_t obbSize = 0;
- auto device = findQuotaDeviceForUuid(uuid);
- if (device.empty()) {
+ if (!IsQuotaSupported(uuidString)) {
flags &= ~FLAG_USE_QUOTA;
}
if (flags & FLAG_USE_QUOTA) {
- struct dqblk dq;
+ int64_t space;
ATRACE_BEGIN("quota");
uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
- totalSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+ totalSize = space;
}
gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
- reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
-#endif
- audioSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) {
+ audioSize = space;
}
gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
- reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
-#endif
- videoSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) {
+ videoSize = space;
}
gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
- reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
-#endif
- imageSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) {
+ imageSize = space;
}
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
- reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
- obbSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+ obbSize = space;
}
ATRACE_END();
@@ -1827,7 +1688,7 @@
memset(&extStats, 0, sizeof(extStats));
for (auto appId : appIds) {
if (appId >= AID_APP_START) {
- collectQuotaStats(device, userId, appId, nullptr, &extStats);
+ collectQuotaStats(uuidString, userId, appId, nullptr, &extStats);
}
}
appSize = extStats.dataSize;
@@ -2615,7 +2476,12 @@
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
mStorageMounts.clear();
- mQuotaReverseMounts.clear();
+
+#if !BYPASS_QUOTA
+ if (!InvalidateQuotaMounts()) {
+ return error("Failed to read mounts");
+ }
+#endif
std::ifstream in("/proc/mounts");
if (!in.is_open()) {
@@ -2636,32 +2502,6 @@
mStorageMounts[source] = target;
}
#endif
-
-#if !BYPASS_QUOTA
- if (source.compare(0, 11, "/dev/block/") == 0) {
- struct dqblk dq;
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
- reinterpret_cast<char*>(&dq)) == 0) {
- LOG(DEBUG) << "Found quota mount " << source << " at " << target;
- mQuotaReverseMounts[target] = source;
-
- // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
- // need to kick it again to enable DQUOT_LIMITS_ENABLED. We
- // only need hard limits enabled when we're not being protected
- // by reserved blocks.
- if (!android::base::GetBoolProperty(kPropHasReserved, false)) {
- if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1,
- nullptr) != 0 && errno != EBUSY) {
- PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
- }
- if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1,
- nullptr) != 0 && errno != EBUSY) {
- PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
- }
- }
- }
- }
-#endif
}
return ok();
}
@@ -2679,16 +2519,10 @@
return StringPrintf("%s/%u", resolved.c_str(), userid);
}
-std::string InstalldNativeService::findQuotaDeviceForUuid(
- const std::unique_ptr<std::string>& uuid) {
- std::lock_guard<std::recursive_mutex> lock(mMountsLock);
- auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
- return mQuotaReverseMounts[path];
-}
-
binder::Status InstalldNativeService::isQuotaSupported(
- const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) {
- *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty();
+ const std::unique_ptr<std::string>& uuid, bool* _aidl_return) {
+ auto uuidString = uuid ? *uuid : "";
+ *_aidl_return = IsQuotaSupported(uuidString);
return ok();
}
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index cebd3f9..367f2c1 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -150,14 +150,11 @@
/* Map of all storage mounts from source to target */
std::unordered_map<std::string, std::string> mStorageMounts;
- /* Map of all quota mounts from target to source */
- std::unordered_map<std::string, std::string> mQuotaReverseMounts;
/* Map from UID to cache quota size */
std::unordered_map<uid_t, int64_t> mCacheQuotas;
std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid);
- std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
};
} // namespace installd
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index 50440f1..5d4f176 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -1,7 +1,8 @@
set noparent
-calin@google.com
agampe@google.com
+calin@google.com
jsharkey@android.com
-toddke@google.com
+mathieuc@google.com
ngeoffray@google.com
+toddke@google.com
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
new file mode 100644
index 0000000..b238dd3
--- /dev/null
+++ b/cmds/installd/QuotaUtils.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QuotaUtils.h"
+
+#include <fstream>
+#include <unordered_map>
+
+#include <sys/quota.h>
+
+#include <android-base/logging.h>
+
+#include "utils.h"
+
+namespace android {
+namespace installd {
+
+namespace {
+
+std::recursive_mutex mMountsLock;
+
+/* Map of all quota mounts from target to source */
+std::unordered_map<std::string, std::string> mQuotaReverseMounts;
+
+std::string& FindQuotaDeviceForUuid(const std::string& uuid) {
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+ auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str());
+ return mQuotaReverseMounts[path];
+}
+
+} // namespace
+
+bool InvalidateQuotaMounts() {
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
+ mQuotaReverseMounts.clear();
+
+ std::ifstream in("/proc/mounts");
+ if (!in.is_open()) {
+ return false;
+ }
+
+ std::string source;
+ std::string target;
+ std::string ignored;
+ while (!in.eof()) {
+ std::getline(in, source, ' ');
+ std::getline(in, target, ' ');
+ std::getline(in, ignored);
+
+ if (source.compare(0, 11, "/dev/block/") == 0) {
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+ reinterpret_cast<char*>(&dq)) == 0) {
+ LOG(DEBUG) << "Found quota mount " << source << " at " << target;
+ mQuotaReverseMounts[target] = source;
+ }
+ }
+ }
+ return true;
+}
+
+bool IsQuotaSupported(const std::string& uuid) {
+ return !FindQuotaDeviceForUuid(uuid).empty();
+}
+
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) {
+ const std::string device = FindQuotaDeviceForUuid(uuid);
+ if (device == "") {
+ return -1;
+ }
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+ }
+ return -1;
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+ return dq.dqb_curspace;
+ }
+}
+
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) {
+ const std::string device = FindQuotaDeviceForUuid(uuid);
+ if (device == "") {
+ return -1;
+ }
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), gid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << gid;
+ }
+ return -1;
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << gid << " " << dq.dqb_curspace;
+#endif
+ return dq.dqb_curspace;
+ }
+
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h
new file mode 100644
index 0000000..9ad170f
--- /dev/null
+++ b/cmds/installd/QuotaUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_QUOTA_UTILS_H_
+#define ANDROID_INSTALLD_QUOTA_UTILS_H_
+
+#include <memory>
+#include <string>
+
+namespace android {
+namespace installd {
+
+/* Clear and recompute the reverse mounts map */
+bool InvalidateQuotaMounts();
+
+/* Whether quota is supported in the device with the given uuid */
+bool IsQuotaSupported(const std::string& uuid);
+
+/* Get the current occupied space in bytes for a uid or -1 if fails */
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid);
+
+/* Get the current occupied space in bytes for a gid or -1 if fails */
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid);
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_QUOTA_UTILS_H_
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 66dece7..aad9939 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -54,6 +54,8 @@
#include "utils.h"
using android::base::EndsWith;
+using android::base::GetBoolProperty;
+using android::base::GetProperty;
using android::base::ReadFully;
using android::base::StringPrintf;
using android::base::WriteFully;
@@ -181,36 +183,11 @@
return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
}
-static int split_count(const char *str)
-{
- char *ctx;
- int count = 0;
- char buf[kPropertyValueMax];
-
- strlcpy(buf, str, sizeof(buf));
- char *pBuf = buf;
-
- while(strtok_r(pBuf, " ", &ctx) != nullptr) {
- count++;
- pBuf = nullptr;
- }
-
- return count;
-}
-
-static int split(char *buf, const char **argv)
-{
- char *ctx;
- int count = 0;
- char *tok;
- char *pBuf = buf;
-
- while((tok = strtok_r(pBuf, " ", &ctx)) != nullptr) {
- argv[count++] = tok;
- pBuf = nullptr;
- }
-
- return count;
+static std::vector<std::string> SplitBySpaces(const std::string& str) {
+ if (str.empty()) {
+ return {};
+ }
+ return android::base::Split(str, " ");
}
static const char* get_location_from_path(const char* path) {
@@ -224,341 +201,279 @@
}
}
-[[ noreturn ]]
-static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
- const char* input_file_name, const char* output_file_name, int swap_fd,
- const char* instruction_set, const char* compiler_filter,
- bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
- const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
- bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
- static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
+// need to be performed between the fork and exec.
+class ExecVHelper {
+ public:
+ // Store a placeholder for the binary name.
+ ExecVHelper() : args_(1u, std::string()) {}
- if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
- LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
- << MAX_INSTRUCTION_SET_LEN;
- exit(DexoptReturnCodes::kInstructionSetLength);
+ void PrepareArgs(const std::string& bin) {
+ CHECK(!args_.empty());
+ CHECK(args_[0].empty());
+ args_[0] = bin;
+ // Write char* into array.
+ for (const std::string& arg : args_) {
+ argv_.push_back(arg.c_str());
+ }
+ argv_.push_back(nullptr); // Add null terminator.
}
- // Get the relative path to the input file.
- const char* relative_input_file_name = get_location_from_path(input_file_name);
-
- char dex2oat_Xms_flag[kPropertyValueMax];
- bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, nullptr) > 0;
-
- char dex2oat_Xmx_flag[kPropertyValueMax];
- bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, nullptr) > 0;
-
- char dex2oat_threads_buf[kPropertyValueMax];
- bool have_dex2oat_threads_flag = get_property(post_bootcomplete
- ? "dalvik.vm.dex2oat-threads"
- : "dalvik.vm.boot-dex2oat-threads",
- dex2oat_threads_buf,
- nullptr) > 0;
- char dex2oat_threads_arg[kPropertyValueMax + 2];
- if (have_dex2oat_threads_flag) {
- sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
+ [[ noreturn ]]
+ void Exec(int exit_code) {
+ execv(argv_[0], (char * const *)&argv_[0]);
+ PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
+ exit(exit_code);
}
- char dex2oat_isa_features_key[kPropertyKeyMax];
- sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
- char dex2oat_isa_features[kPropertyValueMax];
- bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
- dex2oat_isa_features, nullptr) > 0;
-
- char dex2oat_isa_variant_key[kPropertyKeyMax];
- sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
- char dex2oat_isa_variant[kPropertyValueMax];
- bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
- dex2oat_isa_variant, nullptr) > 0;
-
- const char *dex2oat_norelocation = "-Xnorelocate";
- bool have_dex2oat_relocation_skip_flag = false;
-
- char dex2oat_flags[kPropertyValueMax];
- int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
- dex2oat_flags, nullptr) <= 0 ? 0 : split_count(dex2oat_flags);
- ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
-
- // If we are booting without the real /data, don't spend time compiling.
- char vold_decrypt[kPropertyValueMax];
- bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;
- bool skip_compilation = (have_vold_decrypt &&
- (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
- (strcmp(vold_decrypt, "1") == 0)));
-
- bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);
-
- char app_image_format[kPropertyValueMax];
- char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
- bool have_app_image_format =
- image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
- if (have_app_image_format) {
- sprintf(image_format_arg, "--image-format=%s", app_image_format);
- }
-
- char dex2oat_large_app_threshold[kPropertyValueMax];
- bool have_dex2oat_large_app_threshold =
- get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, nullptr) > 0;
- char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
- if (have_dex2oat_large_app_threshold) {
- sprintf(dex2oat_large_app_threshold_arg,
- "--very-large-app-threshold=%s",
- dex2oat_large_app_threshold);
- }
-
- // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
- const char* dex2oat_bin = "/system/bin/dex2oat";
- constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
- // Do not use dex2oatd for release candidates (give dex2oat more soak time).
- bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
- if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) {
- if (access(kDex2oatDebugPath, X_OK) == 0) {
- dex2oat_bin = kDex2oatDebugPath;
+ // Add an arg if it's not empty.
+ void AddArg(const std::string& arg) {
+ if (!arg.empty()) {
+ args_.push_back(arg);
}
}
- bool generate_minidebug_info = kEnableMinidebugInfo &&
- android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
- kMinidebugInfoSystemPropertyDefault);
-
- static const char* RUNTIME_ARG = "--runtime-arg";
-
- static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
-
- // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
- // use arraysize instead.
- char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN];
- char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX];
- char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN];
- char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN];
- char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN];
- char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX];
- char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
- char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax];
- char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax];
- char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax];
- char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax];
- char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax];
- bool have_dex2oat_swap_fd = false;
- char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
- bool have_dex2oat_image_fd = false;
- char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
- size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
- char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN];
- char class_loader_context_arg[class_loader_context_size];
- if (class_loader_context != nullptr) {
- snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
- class_loader_context);
- }
-
- sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
- sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
- sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);
- sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);
- sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
- sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
- sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
- sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
- sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
- if (swap_fd >= 0) {
- have_dex2oat_swap_fd = true;
- sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
- }
- if (image_fd >= 0) {
- have_dex2oat_image_fd = true;
- sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
- }
-
- if (have_dex2oat_Xms_flag) {
- sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);
- }
- if (have_dex2oat_Xmx_flag) {
- sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
- }
- sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version);
-
- // Compute compiler filter.
-
- bool have_dex2oat_compiler_filter_flag = false;
- if (skip_compilation) {
- strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
- sizeof(dex2oat_compiler_filter_arg));
- have_dex2oat_compiler_filter_flag = true;
- have_dex2oat_relocation_skip_flag = true;
- } else if (compiler_filter != nullptr) {
- if (strlen(compiler_filter) + strlen("--compiler-filter=") <
- arraysize(dex2oat_compiler_filter_arg)) {
- sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
- have_dex2oat_compiler_filter_flag = true;
- } else {
- ALOGW("Compiler filter name '%s' is too large (max characters is %zu)",
- compiler_filter,
- kPropertyValueMax);
+ // Add a runtime arg if it's not empty.
+ void AddRuntimeArg(const std::string& arg) {
+ if (!arg.empty()) {
+ args_.push_back("--runtime-arg");
+ args_.push_back(arg);
}
}
- if (!have_dex2oat_compiler_filter_flag) {
- char dex2oat_compiler_filter_flag[kPropertyValueMax];
- have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
- dex2oat_compiler_filter_flag, nullptr) > 0;
- if (have_dex2oat_compiler_filter_flag) {
- sprintf(dex2oat_compiler_filter_arg,
- "--compiler-filter=%s",
- dex2oat_compiler_filter_flag);
- }
- }
+ protected:
+ // Holder arrays for backing arg storage.
+ std::vector<std::string> args_;
- // Check whether all apps should be compiled debuggable.
- if (!debuggable) {
- char prop_buf[kPropertyValueMax];
- debuggable =
- (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
- (prop_buf[0] == '1');
- }
- char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
- if (profile_fd != -1) {
- sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
- }
+ // Argument poiners.
+ std::vector<const char*> argv_;
+};
- // Get the directory of the apk to pass as a base classpath directory.
- char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];
- std::string apk_dir(input_file_name);
- unsigned long dir_index = apk_dir.rfind('/');
- bool has_base_dir = dir_index != std::string::npos;
- if (has_base_dir) {
- apk_dir = apk_dir.substr(0, dir_index);
- sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
- }
-
- std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
- std::string compilation_reason_arg = compilation_reason == nullptr
- ? ""
- : std::string("--compilation-reason=") + compilation_reason;
-
- ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
-
- // Disable cdex if update input vdex is true since this combination of options is not
- // supported.
- const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
- const char* argv[9 // program name, mandatory arguments and the final NULL
- + (have_dex2oat_isa_variant ? 1 : 0)
- + (have_dex2oat_isa_features ? 1 : 0)
- + (have_dex2oat_Xms_flag ? 2 : 0)
- + (have_dex2oat_Xmx_flag ? 2 : 0)
- + (have_dex2oat_compiler_filter_flag ? 1 : 0)
- + (have_dex2oat_threads_flag ? 1 : 0)
- + (have_dex2oat_swap_fd ? 1 : 0)
- + (have_dex2oat_image_fd ? 1 : 0)
- + (have_dex2oat_relocation_skip_flag ? 2 : 0)
- + (generate_debug_info ? 1 : 0)
- + (debuggable ? 1 : 0)
- + (have_app_image_format ? 1 : 0)
- + dex2oat_flags_count
- + (profile_fd == -1 ? 0 : 1)
- + (class_loader_context != nullptr ? 1 : 0)
- + (has_base_dir ? 1 : 0)
- + (have_dex2oat_large_app_threshold ? 1 : 0)
- + (disable_cdex ? 1 : 0)
- + (generate_minidebug_info ? 1 : 0)
- + (target_sdk_version != 0 ? 2 : 0)
- + (enable_hidden_api_checks ? 2 : 0)
- + (dex_metadata_fd > -1 ? 1 : 0)
- + (compilation_reason != nullptr ? 1 : 0)];
- int i = 0;
- argv[i++] = dex2oat_bin;
- argv[i++] = zip_fd_arg;
- argv[i++] = zip_location_arg;
- argv[i++] = input_vdex_fd_arg;
- argv[i++] = output_vdex_fd_arg;
- argv[i++] = oat_fd_arg;
- argv[i++] = oat_location_arg;
- argv[i++] = instruction_set_arg;
- if (have_dex2oat_isa_variant) {
- argv[i++] = instruction_set_variant_arg;
- }
- if (have_dex2oat_isa_features) {
- argv[i++] = instruction_set_features_arg;
- }
- if (have_dex2oat_Xms_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_Xms_arg;
- }
- if (have_dex2oat_Xmx_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_Xmx_arg;
- }
- if (have_dex2oat_compiler_filter_flag) {
- argv[i++] = dex2oat_compiler_filter_arg;
- }
- if (have_dex2oat_threads_flag) {
- argv[i++] = dex2oat_threads_arg;
- }
- if (have_dex2oat_swap_fd) {
- argv[i++] = dex2oat_swap_fd;
- }
- if (have_dex2oat_image_fd) {
- argv[i++] = dex2oat_image_fd;
- }
- if (generate_debug_info) {
- argv[i++] = "--generate-debug-info";
- }
- if (debuggable) {
- argv[i++] = "--debuggable";
- }
- if (have_app_image_format) {
- argv[i++] = image_format_arg;
- }
- if (have_dex2oat_large_app_threshold) {
- argv[i++] = dex2oat_large_app_threshold_arg;
- }
- if (dex2oat_flags_count) {
- i += split(dex2oat_flags, argv + i);
- }
- if (have_dex2oat_relocation_skip_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_norelocation;
- }
- if (profile_fd != -1) {
- argv[i++] = profile_arg;
- }
- if (has_base_dir) {
- argv[i++] = base_dir;
- }
- if (class_loader_context != nullptr) {
- argv[i++] = class_loader_context_arg;
- }
- if (generate_minidebug_info) {
- argv[i++] = kMinidebugDex2oatFlag;
- }
- if (disable_cdex) {
- argv[i++] = kDisableCompactDexFlag;
- }
- if (target_sdk_version != 0) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = target_sdk_version_arg;
- }
- if (enable_hidden_api_checks) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = "-Xhidden-api-checks";
- }
-
- if (dex_metadata_fd > -1) {
- argv[i++] = dex_metadata_fd_arg.c_str();
- }
-
- if(compilation_reason != nullptr) {
- argv[i++] = compilation_reason_arg.c_str();
- }
- // Do not add after dex2oat_flags, they should override others for debugging.
- argv[i] = nullptr;
-
- execv(dex2oat_bin, (char * const *)argv);
- PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
- exit(DexoptReturnCodes::kDex2oatExec);
+static std::string MapPropertyToArg(const std::string& property,
+ const std::string& format,
+ const std::string& default_value = "") {
+ std::string prop = GetProperty(property, default_value);
+ if (!prop.empty()) {
+ return StringPrintf(format.c_str(), prop.c_str());
+ }
+ return "";
}
+class RunDex2Oat : public ExecVHelper {
+ public:
+ RunDex2Oat(int zip_fd,
+ int oat_fd,
+ int input_vdex_fd,
+ int output_vdex_fd,
+ int image_fd,
+ const char* input_file_name,
+ const char* output_file_name,
+ int swap_fd,
+ const char* instruction_set,
+ const char* compiler_filter,
+ bool debuggable,
+ bool post_bootcomplete,
+ bool background_job_compile,
+ int profile_fd,
+ const char* class_loader_context,
+ int target_sdk_version,
+ bool enable_hidden_api_checks,
+ bool generate_compact_dex,
+ int dex_metadata_fd,
+ const char* compilation_reason) {
+ // Get the relative path to the input file.
+ const char* relative_input_file_name = get_location_from_path(input_file_name);
+
+ std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
+ std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
+
+ const char* threads_property = post_bootcomplete
+ ? "dalvik.vm.dex2oat-threads"
+ : "dalvik.vm.boot-dex2oat-threads";
+ std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
+
+ const std::string dex2oat_isa_features_key =
+ StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+ std::string instruction_set_features_arg =
+ MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
+
+ const std::string dex2oat_isa_variant_key =
+ StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+ std::string instruction_set_variant_arg =
+ MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
+
+ const char* dex2oat_norelocation = "-Xnorelocate";
+
+ const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
+ std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
+ ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
+
+ // If we are booting without the real /data, don't spend time compiling.
+ std::string vold_decrypt = GetProperty("vold.decrypt", "");
+ bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+ vold_decrypt == "1";
+
+ const std::string resolve_startup_string_arg =
+ MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+ "--resolve-startup-const-strings=%s");
+ const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
+
+ std::string image_format_arg;
+ if (image_fd >= 0) {
+ image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
+ }
+
+ std::string dex2oat_large_app_threshold_arg =
+ MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
+
+ // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
+ const char* dex2oat_bin = "/system/bin/dex2oat";
+ constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+ // Do not use dex2oatd for release candidates (give dex2oat more soak time).
+ bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
+ if (is_debug_runtime() ||
+ (background_job_compile && is_debuggable_build() && !is_release)) {
+ if (access(kDex2oatDebugPath, X_OK) == 0) {
+ dex2oat_bin = kDex2oatDebugPath;
+ }
+ }
+
+ bool generate_minidebug_info = kEnableMinidebugInfo &&
+ GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
+
+ // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
+ // use arraysize instead.
+ std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
+ std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
+ std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
+ std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
+ std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
+ std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
+ std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
+ std::string dex2oat_compiler_filter_arg;
+ std::string dex2oat_swap_fd;
+ std::string dex2oat_image_fd;
+ std::string target_sdk_version_arg;
+ if (target_sdk_version != 0) {
+ StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+ }
+ std::string class_loader_context_arg;
+ if (class_loader_context != nullptr) {
+ class_loader_context_arg = StringPrintf("--class-loader-context=%s",
+ class_loader_context);
+ }
+
+ if (swap_fd >= 0) {
+ dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
+ }
+ if (image_fd >= 0) {
+ dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
+ }
+
+ // Compute compiler filter.
+ bool have_dex2oat_relocation_skip_flag = false;
+ if (skip_compilation) {
+ dex2oat_compiler_filter_arg = "--compiler-filter=extract";
+ have_dex2oat_relocation_skip_flag = true;
+ } else if (compiler_filter != nullptr) {
+ dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
+ }
+
+ if (dex2oat_compiler_filter_arg.empty()) {
+ dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+ "--compiler-filter=%s");
+ }
+
+ // Check whether all apps should be compiled debuggable.
+ if (!debuggable) {
+ debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
+ }
+ std::string profile_arg;
+ if (profile_fd != -1) {
+ profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
+ }
+
+ // Get the directory of the apk to pass as a base classpath directory.
+ std::string base_dir;
+ std::string apk_dir(input_file_name);
+ unsigned long dir_index = apk_dir.rfind('/');
+ bool has_base_dir = dir_index != std::string::npos;
+ if (has_base_dir) {
+ apk_dir = apk_dir.substr(0, dir_index);
+ base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
+ }
+
+ std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
+
+ std::string compilation_reason_arg = compilation_reason == nullptr
+ ? ""
+ : std::string("--compilation-reason=") + compilation_reason;
+
+ ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
+
+ // Disable cdex if update input vdex is true since this combination of options is not
+ // supported.
+ const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
+
+ AddArg(zip_fd_arg);
+ AddArg(zip_location_arg);
+ AddArg(input_vdex_fd_arg);
+ AddArg(output_vdex_fd_arg);
+ AddArg(oat_fd_arg);
+ AddArg(oat_location_arg);
+ AddArg(instruction_set_arg);
+
+ AddArg(instruction_set_variant_arg);
+ AddArg(instruction_set_features_arg);
+
+ AddRuntimeArg(dex2oat_Xms_arg);
+ AddRuntimeArg(dex2oat_Xmx_arg);
+
+ AddArg(resolve_startup_string_arg);
+ AddArg(dex2oat_compiler_filter_arg);
+ AddArg(dex2oat_threads_arg);
+ AddArg(dex2oat_swap_fd);
+ AddArg(dex2oat_image_fd);
+
+ if (generate_debug_info) {
+ AddArg("--generate-debug-info");
+ }
+ if (debuggable) {
+ AddArg("--debuggable");
+ }
+ AddArg(image_format_arg);
+ AddArg(dex2oat_large_app_threshold_arg);
+
+ if (have_dex2oat_relocation_skip_flag) {
+ AddRuntimeArg(dex2oat_norelocation);
+ }
+ AddArg(profile_arg);
+ AddArg(base_dir);
+ AddArg(class_loader_context_arg);
+ if (generate_minidebug_info) {
+ AddArg(kMinidebugDex2oatFlag);
+ }
+ if (disable_cdex) {
+ AddArg(kDisableCompactDexFlag);
+ }
+ AddArg(target_sdk_version_arg);
+ if (enable_hidden_api_checks) {
+ AddRuntimeArg("-Xhidden-api-checks");
+ }
+
+ if (dex_metadata_fd > -1) {
+ AddArg(dex_metadata_fd_arg);
+ }
+
+ AddArg(compilation_reason_arg);
+
+ // Do not add args after dex2oat_flags, they should override others for debugging.
+ args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
+
+ PrepareArgs(dex2oat_bin);
+ }
+};
+
/*
* Whether dexopt should use a swap file when compiling an APK.
*
@@ -580,13 +495,9 @@
}
// Check the "override" property. If it exists, return value == "true".
- char dex2oat_prop_buf[kPropertyValueMax];
- if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
- if (strcmp(dex2oat_prop_buf, "true") == 0) {
- return true;
- } else {
- return false;
- }
+ std::string dex2oat_prop_buf = GetProperty("dalvik.vm.dex2oat-swap", "");
+ if (!dex2oat_prop_buf.empty()) {
+ return dex2oat_prop_buf == "true";
}
// Shortcut for default value. This is an implementation optimization for the process sketched
@@ -596,8 +507,7 @@
return true;
}
- bool is_low_mem = property_get_bool("ro.config.low_ram", false);
- if (is_low_mem) {
+ if (GetBoolProperty("ro.config.low_ram", false)) {
return true;
}
@@ -738,91 +648,91 @@
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
-[[ noreturn ]]
-static void run_profman(const std::vector<unique_fd>& profile_fds,
- const unique_fd& reference_profile_fd,
- const std::vector<unique_fd>* apk_fds,
- const std::vector<std::string>* dex_locations,
- bool copy_and_update) {
- const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+class RunProfman : public ExecVHelper {
+ public:
+ void SetupArgs(const std::vector<unique_fd>& profile_fds,
+ const unique_fd& reference_profile_fd,
+ const std::vector<unique_fd>& apk_fds,
+ const std::vector<std::string>& dex_locations,
+ bool copy_and_update) {
+ const char* profman_bin =
+ is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
- if (copy_and_update) {
- CHECK_EQ(1u, profile_fds.size());
- CHECK(apk_fds != nullptr);
- CHECK_EQ(1u, apk_fds->size());
- }
- std::vector<std::string> profile_args(profile_fds.size());
- for (size_t k = 0; k < profile_fds.size(); k++) {
- profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
- }
- std::string reference_profile_arg = "--reference-profile-file-fd="
- + std::to_string(reference_profile_fd.get());
-
- std::vector<std::string> apk_args;
- if (apk_fds != nullptr) {
- for (size_t k = 0; k < apk_fds->size(); k++) {
- apk_args.push_back("--apk-fd=" + std::to_string((*apk_fds)[k].get()));
+ if (copy_and_update) {
+ CHECK_EQ(1u, profile_fds.size());
+ CHECK_EQ(1u, apk_fds.size());
}
- }
-
- std::vector<std::string> dex_location_args;
- if (dex_locations != nullptr) {
- for (size_t k = 0; k < dex_locations->size(); k++) {
- dex_location_args.push_back("--dex-location=" + (*dex_locations)[k]);
+ if (reference_profile_fd != -1) {
+ AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
}
+
+ for (const unique_fd& fd : profile_fds) {
+ AddArg("--profile-file-fd=" + std::to_string(fd.get()));
+ }
+
+ for (const unique_fd& fd : apk_fds) {
+ AddArg("--apk-fd=" + std::to_string(fd.get()));
+ }
+
+ for (const std::string& dex_location : dex_locations) {
+ AddArg("--dex-location=" + dex_location);
+ }
+
+ if (copy_and_update) {
+ AddArg("--copy-and-update-profile-key");
+ }
+
+ // Do not add after dex2oat_flags, they should override others for debugging.
+ PrepareArgs(profman_bin);
}
- // program name, reference profile fd, the final NULL and the profile fds
- const char* argv[3 + profile_args.size() + apk_args.size()
- + dex_location_args.size() + (copy_and_update ? 1 : 0)];
- int i = 0;
- argv[i++] = profman_bin;
- argv[i++] = reference_profile_arg.c_str();
- for (size_t k = 0; k < profile_args.size(); k++) {
- argv[i++] = profile_args[k].c_str();
- }
- for (size_t k = 0; k < apk_args.size(); k++) {
- argv[i++] = apk_args[k].c_str();
- }
- for (size_t k = 0; k < dex_location_args.size(); k++) {
- argv[i++] = dex_location_args[k].c_str();
- }
- if (copy_and_update) {
- argv[i++] = "--copy-and-update-profile-key";
+ void SetupMerge(const std::vector<unique_fd>& profiles_fd,
+ const unique_fd& reference_profile_fd,
+ const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
+ const std::vector<std::string>& dex_locations = std::vector<std::string>()) {
+ SetupArgs(profiles_fd,
+ reference_profile_fd,
+ apk_fds,
+ dex_locations,
+ /*copy_and_update=*/false);
}
- // Do not add after dex2oat_flags, they should override others for debugging.
- argv[i] = nullptr;
+ void SetupCopyAndUpdate(unique_fd&& profile_fd,
+ unique_fd&& reference_profile_fd,
+ unique_fd&& apk_fd,
+ const std::string& dex_location) {
+ // The fds need to stay open longer than the scope of the function, so put them into a local
+ // variable vector.
+ profiles_fd_.push_back(std::move(profile_fd));
+ apk_fds_.push_back(std::move(apk_fd));
+ reference_profile_fd_ = std::move(reference_profile_fd);
+ std::vector<std::string> dex_locations = {dex_location};
+ SetupArgs(profiles_fd_, reference_profile_fd_, apk_fds_, dex_locations,
+ /*copy_and_update=*/true);
+ }
- execv(profman_bin, (char * const *)argv);
- PLOG(ERROR) << "execv(" << profman_bin << ") failed";
- exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */
-}
+ void SetupDump(const std::vector<unique_fd>& profiles_fd,
+ const unique_fd& reference_profile_fd,
+ const std::vector<std::string>& dex_locations,
+ const std::vector<unique_fd>& apk_fds,
+ const unique_fd& output_fd) {
+ AddArg("--dump-only");
+ AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
+ SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
+ /*copy_and_update=*/false);
+ }
-[[ noreturn ]]
-static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
- const unique_fd& reference_profile_fd,
- const std::vector<unique_fd>* apk_fds = nullptr,
- const std::vector<std::string>* dex_locations = nullptr) {
- run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
- /*copy_and_update*/false);
-}
+ void Exec() {
+ ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
+ }
-[[ noreturn ]]
-static void run_profman_copy_and_update(unique_fd&& profile_fd,
- unique_fd&& reference_profile_fd,
- unique_fd&& apk_fd,
- const std::string& dex_location) {
- std::vector<unique_fd> profiles_fd;
- profiles_fd.push_back(std::move(profile_fd));
- std::vector<unique_fd> apk_fds;
- apk_fds.push_back(std::move(apk_fd));
- std::vector<std::string> dex_locations;
- dex_locations.push_back(dex_location);
+ private:
+ unique_fd reference_profile_fd_;
+ std::vector<unique_fd> profiles_fd_;
+ std::vector<unique_fd> apk_fds_;
+};
- run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations,
- /*copy_and_update*/true);
-}
+
// Decides if profile guided compilation is needed or not based on existing profiles.
// The location is the package name for primary apks or the dex path for secondary dex files.
@@ -842,11 +752,13 @@
return false;
}
+ RunProfman profman_merge;
+ profman_merge.SetupMerge(profiles_fd, reference_profile_fd);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
drop_capabilities(uid);
- run_profman_merge(profiles_fd, reference_profile_fd);
+ profman_merge.Exec();
}
/* parent */
int return_code = wait_child(pid);
@@ -919,42 +831,6 @@
return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
}
-[[ noreturn ]]
-static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
- const unique_fd& reference_profile_fd,
- const std::vector<std::string>& dex_locations,
- const std::vector<unique_fd>& apk_fds,
- const unique_fd& output_fd) {
- std::vector<std::string> profman_args;
- static const char* PROFMAN_BIN = "/system/bin/profman";
- profman_args.push_back(PROFMAN_BIN);
- profman_args.push_back("--dump-only");
- profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
- if (reference_profile_fd != -1) {
- profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
- reference_profile_fd.get()));
- }
- for (size_t i = 0; i < profile_fds.size(); i++) {
- profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get()));
- }
- for (const std::string& dex_location : dex_locations) {
- profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
- }
- for (size_t i = 0; i < apk_fds.size(); i++) {
- profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
- }
- const char **argv = new const char*[profman_args.size() + 1];
- size_t i = 0;
- for (const std::string& profman_arg : profman_args) {
- argv[i++] = profman_arg.c_str();
- }
- argv[i] = nullptr;
-
- execv(PROFMAN_BIN, (char * const *)argv);
- PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
- exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */
-}
-
bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
const std::string& code_path) {
std::vector<unique_fd> profile_fds;
@@ -991,12 +867,13 @@
apk_fds.push_back(std::move(apk_fd));
+ RunProfman profman_dump;
+ profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
drop_capabilities(uid);
- run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
- apk_fds, output_fd);
+ profman_dump.Exec();
}
/* parent */
int return_code = wait_child(pid);
@@ -1306,10 +1183,8 @@
if (!generate_app_image) {
return Dex2oatFileWrapper();
}
- char app_image_format[kPropertyValueMax];
- bool have_app_image_format =
- get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
- if (!have_app_image_format) {
+ std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
+ if (app_image_format.empty()) {
return Dex2oatFileWrapper();
}
// Recreate is true since we do not want to modify a mapped image. If the app is
@@ -1570,70 +1445,60 @@
// The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
// If this is for a profile guided compilation, profile_was_updated will tell whether or not
// the profile has changed.
-static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oat_fd,
- int zip_fd, const std::string& instruction_set, const std::string& compiler_filter,
- bool profile_was_updated, bool downgrade,
- const char* class_loader_context) {
- CHECK_GE(zip_fd, 0);
- const char* dexoptanalyzer_bin =
- is_debug_runtime()
- ? "/system/bin/dexoptanalyzerd"
- : "/system/bin/dexoptanalyzer";
- static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+class RunDexoptAnalyzer : public ExecVHelper {
+ public:
+ RunDexoptAnalyzer(const std::string& dex_file,
+ int vdex_fd,
+ int oat_fd,
+ int zip_fd,
+ const std::string& instruction_set,
+ const std::string& compiler_filter,
+ bool profile_was_updated,
+ bool downgrade,
+ const char* class_loader_context) {
+ CHECK_GE(zip_fd, 0);
+ const char* dexoptanalyzer_bin =
+ is_debug_runtime()
+ ? "/system/bin/dexoptanalyzerd"
+ : "/system/bin/dexoptanalyzer";
- if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
- LOG(ERROR) << "Instruction set " << instruction_set
- << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
- return;
- }
+ std::string dex_file_arg = "--dex-file=" + dex_file;
+ std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
+ std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
+ std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
+ std::string isa_arg = "--isa=" + instruction_set;
+ std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
+ const char* assume_profile_changed = "--assume-profile-changed";
+ const char* downgrade_flag = "--downgrade";
+ std::string class_loader_context_arg = "--class-loader-context=";
+ if (class_loader_context != nullptr) {
+ class_loader_context_arg += class_loader_context;
+ }
- std::string dex_file_arg = "--dex-file=" + dex_file;
- std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
- std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
- std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
- std::string isa_arg = "--isa=" + instruction_set;
- std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
- const char* assume_profile_changed = "--assume-profile-changed";
- const char* downgrade_flag = "--downgrade";
- std::string class_loader_context_arg = "--class-loader-context=";
- if (class_loader_context != nullptr) {
- class_loader_context_arg += class_loader_context;
- }
+ // program name, dex file, isa, filter
+ AddArg(dex_file_arg);
+ AddArg(isa_arg);
+ AddArg(compiler_filter_arg);
+ if (oat_fd >= 0) {
+ AddArg(oat_fd_arg);
+ }
+ if (vdex_fd >= 0) {
+ AddArg(vdex_fd_arg);
+ }
+ AddArg(zip_fd_arg.c_str());
+ if (profile_was_updated) {
+ AddArg(assume_profile_changed);
+ }
+ if (downgrade) {
+ AddArg(downgrade_flag);
+ }
+ if (class_loader_context != nullptr) {
+ AddArg(class_loader_context_arg.c_str());
+ }
- // program name, dex file, isa, filter, the final NULL
- const int argc = 6 +
- (profile_was_updated ? 1 : 0) +
- (vdex_fd >= 0 ? 1 : 0) +
- (oat_fd >= 0 ? 1 : 0) +
- (downgrade ? 1 : 0) +
- (class_loader_context != nullptr ? 1 : 0);
- const char* argv[argc];
- int i = 0;
- argv[i++] = dexoptanalyzer_bin;
- argv[i++] = dex_file_arg.c_str();
- argv[i++] = isa_arg.c_str();
- argv[i++] = compiler_filter_arg.c_str();
- if (oat_fd >= 0) {
- argv[i++] = oat_fd_arg.c_str();
+ PrepareArgs(dexoptanalyzer_bin);
}
- if (vdex_fd >= 0) {
- argv[i++] = vdex_fd_arg.c_str();
- }
- argv[i++] = zip_fd_arg.c_str();
- if (profile_was_updated) {
- argv[i++] = assume_profile_changed;
- }
- if (downgrade) {
- argv[i++] = downgrade_flag;
- }
- if (class_loader_context != nullptr) {
- argv[i++] = class_loader_context_arg.c_str();
- }
- argv[i] = nullptr;
-
- execv(dexoptanalyzer_bin, (char * const *)argv);
- ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
-}
+};
// Prepares the oat dir for the secondary dex files.
static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
@@ -1885,16 +1750,17 @@
/*is_secondary_dex*/true);
// Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
- exec_dexoptanalyzer(dex_path,
- vdex_file_fd.get(),
- oat_file_fd.get(),
- zip_fd.get(),
- instruction_set,
- compiler_filter, profile_was_updated,
- downgrade,
- class_loader_context);
- PLOG(ERROR) << "Failed to exec dexoptanalyzer";
- _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+ // Note that we do not do it before the fork since opening the files is required to happen
+ // after forking.
+ RunDexoptAnalyzer run_dexopt_analyzer(dex_path,
+ vdex_file_fd.get(),
+ oat_file_fd.get(),
+ zip_fd.get(),
+ instruction_set,
+ compiler_filter, profile_was_updated,
+ downgrade,
+ class_loader_context);
+ run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
}
/* parent */
@@ -2063,6 +1929,27 @@
LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
+ RunDex2Oat runner(input_fd.get(),
+ out_oat_fd.get(),
+ in_vdex_fd.get(),
+ out_vdex_fd.get(),
+ image_fd.get(),
+ dex_path,
+ out_oat_path,
+ swap_fd.get(),
+ instruction_set,
+ compiler_filter,
+ debuggable,
+ boot_complete,
+ background_job_compile,
+ reference_profile_fd.get(),
+ class_loader_context,
+ target_sdk_version,
+ enable_hidden_api_checks,
+ generate_compact_dex,
+ dex_metadata_fd.get(),
+ compilation_reason);
+
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -2074,26 +1961,7 @@
_exit(DexoptReturnCodes::kFlock);
}
- run_dex2oat(input_fd.get(),
- out_oat_fd.get(),
- in_vdex_fd.get(),
- out_vdex_fd.get(),
- image_fd.get(),
- dex_path,
- out_oat_path,
- swap_fd.get(),
- instruction_set,
- compiler_filter,
- debuggable,
- boot_complete,
- background_job_compile,
- reference_profile_fd.get(),
- class_loader_context,
- target_sdk_version,
- enable_hidden_api_checks,
- generate_compact_dex,
- dex_metadata_fd.get(),
- compilation_reason);
+ runner.Exec(DexoptReturnCodes::kDex2oatExec);
} else {
int res = wait_child(pid);
if (res == 0) {
@@ -2421,18 +2289,14 @@
bool move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
// Get the current slot suffix. No suffix, no A/B.
- std::string slot_suffix;
- {
- char buf[kPropertyValueMax];
- if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) {
- return false;
- }
- slot_suffix = buf;
+ const std::string slot_suffix = GetProperty("ro.boot.slot_suffix", "");
+ if (slot_suffix.empty()) {
+ return false;
+ }
- if (!ValidateTargetSlotSuffix(slot_suffix)) {
- LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
- return false;
- }
+ if (!ValidateTargetSlotSuffix(slot_suffix)) {
+ LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
+ return false;
}
// Validate other inputs.
@@ -2661,11 +2525,13 @@
return false;
}
+ RunProfman args;
+ args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
drop_capabilities(app_shared_gid);
- run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+ args.Exec();
}
/* parent */
@@ -2689,6 +2555,13 @@
return false;
}
+ // Return false for empty class path since it may otherwise return true below if profiles is
+ // empty.
+ if (classpath.empty()) {
+ PLOG(ERROR) << "Class path is empty";
+ return false;
+ }
+
// Open and create the snapshot profile.
unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
@@ -2738,6 +2611,8 @@
profiles_fd.push_back(std::move(fd));
}
}
+ RunProfman args;
+ args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -2745,7 +2620,7 @@
// The introduction of new access flags into boot jars causes them to
// fail dex file verification.
- run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+ args.Exec();
}
/* parent */
@@ -2799,6 +2674,11 @@
return false;
}
+ RunProfman args;
+ args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
+ std::move(ref_profile_fd),
+ std::move(apk_fd),
+ code_path);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -2806,10 +2686,7 @@
drop_capabilities(app_shared_gid);
// The copy and update takes ownership over the fds.
- run_profman_copy_and_update(std::move(dex_metadata_fd),
- std::move(ref_profile_fd),
- std::move(apk_fd),
- code_path);
+ args.Exec();
}
/* parent */
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index f216c53..79e6859 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -143,6 +143,20 @@
"AAAACADojmFLPcugSwoBAAAUAgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAA/Ns"
"+ll1eAsAAQQj5QIABIgTAABQSwUGAAAAAAEAAQBRAAAATwEAAAAA";
+class DexoptTestEnvTest : public testing::Test {
+};
+
+TEST_F(DexoptTestEnvTest, CheckSelinux) {
+ ASSERT_EQ(1, is_selinux_enabled());
+
+ // Crude cutout for virtual devices.
+#if !defined(__i386__) && !defined(__x86_64__)
+ constexpr bool kIsX86 = false;
+#else
+ constexpr bool kIsX86 = true;
+#endif
+ ASSERT_TRUE(1 == security_getenforce() || kIsX86 || true /* b/119032200 */);
+}
class DexoptTest : public testing::Test {
protected:
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 6b9cf0d..74ad184 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -43,6 +43,7 @@
#define DEBUG_XATTRS 0
using android::base::EndsWith;
+using android::base::Fdopendir;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -1036,7 +1037,7 @@
continue;
}
- DIR* subdir = fdopendir(subdir_fd);
+ DIR* subdir = Fdopendir(std::move(subdir_fd));
if (subdir == nullptr) {
PLOG(WARNING) << "Could not open dir path " << local_path;
result = false;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5829c4f..d05724a 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,8 +36,6 @@
#define BYPASS_QUOTA 0
#define BYPASS_SDCARDFS 0
-#define APPLY_HARD_QUOTAS 0
-
namespace android {
namespace installd {
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 4d93cb4..152ac28 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -13,5 +13,6 @@
onrestart restart cameraserver
onrestart restart keystore
onrestart restart gatekeeperd
+ onrestart restart thermalservice
writepid /dev/cpuset/system-background/tasks
shutdown critical
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 68ddeb0..c169b76 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -160,7 +160,7 @@
message DisplayCreation {
required int32 id = 1;
required string name = 2;
- required int32 type = 3;
+ optional uint64 display_id = 3;
required bool is_secure = 4;
}
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
index a892e46..d63d97f 100644
--- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
+++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
@@ -172,7 +172,7 @@
def display_create(increment):
increment.display_creation.id = int(input("Enter id: "))
increment.display_creation.name = str(raw_input("Enter name: "))
- increment.display_creation.type = int(input("Enter type: "))
+ increment.display_creation.display_id = int(input("Enter display ID: "))
increment.display_creation.is_secure = bool(input("Enter if secure: "))
def display_delete(increment):
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index c44a1f6..aa8bd3d 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -167,6 +167,25 @@
kSecurityLevelHwSecureAll
};
+ // An offline license may be usable or inactive. The keys in a
+ // usable offline license are available for decryption. When
+ // the offline license state is inactive, the keys have been
+ // marked for release using getKeyRequest with
+ // kKeyType_Release but the key response has not been
+ // received. The keys in an inactive offline license are not
+ // usable for decryption.
+
+ enum OfflineLicenseState {
+ // The offline license state is unknown due to an error
+ kOfflineLicenseStateUnknown,
+ // Offline license state is usable, the keys may be used for decryption.
+ kOfflineLicenseStateUsable,
+ // Offline license state is inactive, the keys have been marked for
+ // release using getKeyRequest() with kKeyType_Release but the
+ // key response has not been received.
+ kOfflineLicenseStateInactive
+ };
+
DrmPlugin() {}
virtual ~DrmPlugin() {}
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index 79f666b..c541511 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -150,19 +150,81 @@
* Move to the next system font.
*
* \param iterator an iterator for the system fonts. Passing NULL is not allowed.
- * \return true if more system fonts are available, otherwise false.
+ * \return a font. If no more font is available, returns nullptr. You need to release the returned
+ * font by ASystemFont_close when it is no longer needed.
*/
ASystemFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
/**
* Close an ASystemFont returned by ASystemFontIterator_next.
*
- * \param font a font returned by ASystemFontIterator_next. Do nothing if NULL is passed.
+ * \param font a font returned by ASystemFontIterator_next or ASystemFont_matchFamilyStyleCharacter.
+ * Do nothing if NULL is passed.
*/
void ASystemFont_close(ASystemFont* _Nullable font) __INTRODUCED_IN(29);
/**
+ * Select the best font from given parameters.
+ *
+ * Only generic font families are supported.
+ * For more information about generic font families, read [W3C spec](https://www.w3.org/TR/css-fonts-4/#generic-font-families)
+ *
+ * Even if no font can render the given text, this function will return a non-null result for
+ * drawing Tofu character.
+ *
+ * Examples:
+ * <code>
+ * // Simple font query for the ASCII character.
+ * std::vector<uint16_t> text = { 'A' };
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ * // runLength will be 1 and the font will points a valid font file.
+ *
+ * // Querying font for CJK characters
+ * std::vector<uint16_t> text = { 0x9AA8 };
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "zh-CN,ja-JP", text.data(), text.length(), &runLength);
+ * // runLength will be 1 and the font will points a Simplified Chinese font.
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "ja-JP,zh-CN", text.data(), text.length(), &runLength);
+ * // runLength will be 1 and the font will points a Japanese font.
+ *
+ * // Querying font for text/color emoji
+ * std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 };
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ * // runLength will be 8 and the font will points a color emoji font.
+ *
+ * // Mixture of multiple script of characters.
+ * // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character.
+ * std::vector<uint16_t> text = { 0x05D0, 0x0E01 };
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ * // runLength will be 1 and the font will points a Hebrew font.
+ * </code>
+ *
+ * \param familyName a null character terminated font family name
+ * \param weight a font weight value. Only from 0 to 1000 value is valid
+ * \param italic true if italic, otherwise false.
+ * \param languageTags a null character terminated comma separated IETF BCP47 compliant language
+ * tags.
+ * \param text a UTF-16 encoded text buffer to be rendered.
+ * \param textLength a length of the given text buffer.
+ * \param runLengthOut if not null, the font run length will be filled.
+ * \return a font to be used for given text and params. You need to release the returned font by
+ * ASystemFont_close when it is no longer needed.
+ */
+ASystemFont* _Nonnull ASystemFont_matchFamilyStyleCharacter(
+ const char* _Nonnull familyName,
+ uint16_t weight,
+ bool italic,
+ const char* _Nonnull languageTags,
+ const uint16_t* _Nonnull text,
+ uint32_t textLength,
+ uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29);
+
+/**
* Return an absolute path to the current font file.
*
* Here is a list of font formats returned by this method:
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 1bd7c4f..f6cc3af 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -115,6 +115,7 @@
return sEmptyDescriptor;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -137,6 +138,7 @@
return err;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::linkToDeath(
const sp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
uint32_t /*flags*/)
@@ -144,6 +146,7 @@
return INVALID_OPERATION;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::unlinkToDeath(
const wp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
uint32_t /*flags*/, wp<DeathRecipient>* /*outRecipient*/)
@@ -208,6 +211,7 @@
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 7342126..ec170f7 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -206,6 +206,7 @@
return err;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -220,6 +221,7 @@
return DEAD_OBJECT;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
@@ -254,6 +256,7 @@
return DEAD_OBJECT;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::unlinkToDeath(
const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
wp<DeathRecipient>* outRecipient)
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index f9ec593..2f4dbee 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -49,6 +49,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnAppOpsCallback::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 068664b..fb0d521 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -129,6 +129,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnAppOpsService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index ad1e69f..b307e3e 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -136,6 +136,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnBatteryStats::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 507ce53..caf2318 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -86,7 +86,7 @@
virtual void* getBase() const;
virtual size_t getSize() const;
virtual uint32_t getFlags() const;
- virtual uint32_t getOffset() const;
+ off_t getOffset() const override;
private:
friend class IMemory;
@@ -113,7 +113,7 @@
mutable void* mBase;
mutable size_t mSize;
mutable uint32_t mFlags;
- mutable uint32_t mOffset;
+ mutable off_t mOffset;
mutable bool mRealHeap;
mutable Mutex mLock;
};
@@ -129,6 +129,7 @@
public:
explicit BpMemory(const sp<IBinder>& impl);
virtual ~BpMemory();
+ // NOLINTNEXTLINE(google-default-arguments)
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const;
private:
@@ -180,6 +181,7 @@
{
}
+// NOLINTNEXTLINE(google-default-arguments)
sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
{
if (mHeap == nullptr) {
@@ -187,13 +189,16 @@
data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
sp<IBinder> heap = reply.readStrongBinder();
- ssize_t o = reply.readInt32();
- size_t s = reply.readInt32();
if (heap != nullptr) {
mHeap = interface_cast<IMemoryHeap>(heap);
if (mHeap != nullptr) {
+ const int64_t offset64 = reply.readInt64();
+ const uint64_t size64 = reply.readUint64();
+ const ssize_t o = (ssize_t)offset64;
+ const size_t s = (size_t)size64;
size_t heapSize = mHeap->getSize();
- if (s <= heapSize
+ if (s == size64 && o == offset64 // ILP32 bounds check
+ && s <= heapSize
&& o >= 0
&& (static_cast<size_t>(o) <= heapSize - s)) {
mOffset = o;
@@ -224,6 +229,7 @@
BnMemory::~BnMemory() {
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnMemory::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -233,8 +239,8 @@
ssize_t offset;
size_t size;
reply->writeStrongBinder( IInterface::asBinder(getMemory(&offset, &size)) );
- reply->writeInt32(offset);
- reply->writeInt32(size);
+ reply->writeInt64(offset);
+ reply->writeUint64(size);
return NO_ERROR;
} break;
default:
@@ -313,18 +319,23 @@
data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
status_t err = remote()->transact(HEAP_ID, data, &reply);
int parcel_fd = reply.readFileDescriptor();
- ssize_t size = reply.readInt32();
- uint32_t flags = reply.readInt32();
- uint32_t offset = reply.readInt32();
-
- ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)",
- IInterface::asBinder(this).get(),
- parcel_fd, size, err, strerror(-err));
+ const uint64_t size64 = reply.readUint64();
+ const int64_t offset64 = reply.readInt64();
+ const uint32_t flags = reply.readUint32();
+ const size_t size = (size_t)size64;
+ const off_t offset = (off_t)offset64;
+ if (err != NO_ERROR || // failed transaction
+ size != size64 || offset != offset64) { // ILP32 size check
+ ALOGE("binder=%p transaction failed fd=%d, size=%zu, err=%d (%s)",
+ IInterface::asBinder(this).get(),
+ parcel_fd, size, err, strerror(-err));
+ return;
+ }
Mutex::Autolock _l(mLock);
if (mHeapId.load(memory_order_relaxed) == -1) {
int fd = fcntl(parcel_fd, F_DUPFD_CLOEXEC, 0);
- ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)",
+ ALOGE_IF(fd == -1, "cannot dup fd=%d, size=%zu, err=%d (%s)",
parcel_fd, size, err, strerror(errno));
int access = PROT_READ;
@@ -334,7 +345,7 @@
mRealHeap = true;
mBase = mmap(nullptr, size, access, MAP_SHARED, fd, offset);
if (mBase == MAP_FAILED) {
- ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)",
+ ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zu, fd=%d (%s)",
IInterface::asBinder(this).get(), size, fd, strerror(errno));
close(fd);
} else {
@@ -368,7 +379,7 @@
return mFlags;
}
-uint32_t BpMemoryHeap::getOffset() const {
+off_t BpMemoryHeap::getOffset() const {
assertMapped();
return mOffset;
}
@@ -383,6 +394,7 @@
BnMemoryHeap::~BnMemoryHeap() {
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnMemoryHeap::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -390,9 +402,9 @@
case HEAP_ID: {
CHECK_INTERFACE(IMemoryHeap, data, reply);
reply->writeFileDescriptor(getHeapID());
- reply->writeInt32(getSize());
- reply->writeInt32(getFlags());
- reply->writeInt32(getOffset());
+ reply->writeUint64(getSize());
+ reply->writeInt64(getOffset());
+ reply->writeUint32(getFlags());
return NO_ERROR;
} break;
default:
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 89ebc6c..6b99150 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -109,6 +109,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnPermissionController::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index 14b5259..159763d 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -48,6 +48,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnResultReceiver::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index dd4a65e..6c697de 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -58,6 +58,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnShellCallback::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 9850ad9..4c300b4 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -76,7 +76,7 @@
}
}
-MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset)
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
@@ -85,7 +85,7 @@
mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
}
-status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
+status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
{
if (mFD != -1) {
return INVALID_OPERATION;
@@ -98,13 +98,20 @@
return NO_ERROR;
}
-status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
+status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
{
if (size == 0) {
// try to figure out the size automatically
struct stat sb;
- if (fstat(fd, &sb) == 0)
- size = sb.st_size;
+ if (fstat(fd, &sb) == 0) {
+ size = (size_t)sb.st_size;
+ // sb.st_size is off_t which on ILP32 may be 64 bits while size_t is 32 bits.
+ if ((off_t)size != sb.st_size) {
+ ALOGE("%s: size of file %lld cannot fit in memory",
+ __func__, (long long)sb.st_size);
+ return INVALID_OPERATION;
+ }
+ }
// if it didn't work, let mmap() fail.
}
@@ -112,12 +119,12 @@
void* base = (uint8_t*)mmap(nullptr, size,
PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
if (base == MAP_FAILED) {
- ALOGE("mmap(fd=%d, size=%u) failed (%s)",
- fd, uint32_t(size), strerror(errno));
+ ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
+ fd, size, strerror(errno));
close(fd);
return -errno;
}
- //ALOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
+ //ALOGD("mmap(fd=%d, base=%p, size=%zu)", fd, base, size);
mBase = base;
mNeedUnmap = true;
} else {
@@ -140,7 +147,7 @@
int fd = android_atomic_or(-1, &mFD);
if (fd >= 0) {
if (mNeedUnmap) {
- //ALOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
+ //ALOGD("munmap(fd=%d, base=%p, size=%zu)", fd, mBase, mSize);
munmap(mBase, mSize);
}
mBase = nullptr;
@@ -169,7 +176,7 @@
return mDevice;
}
-uint32_t MemoryHeapBase::getOffset() const {
+off_t MemoryHeapBase::getOffset() const {
return mOffset;
}
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 0b60b4e..c251468 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -34,15 +34,18 @@
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0,
@@ -60,6 +63,7 @@
protected:
virtual ~BBinder();
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index c4c8ba3..1d4f881 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -41,14 +41,18 @@
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0);
+
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0,
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
index e5b12a9..b500219 100644
--- a/libs/binder/include/binder/IAppOpsCallback.h
+++ b/libs/binder/include/binder/IAppOpsCallback.h
@@ -43,6 +43,7 @@
class BnAppOpsCallback : public BnInterface<IAppOpsCallback>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index f0c5e17..7807851 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -67,6 +67,7 @@
class BnAppOpsService : public BnInterface<IAppOpsService>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
index 59e806c..48da865 100644
--- a/libs/binder/include/binder/IBatteryStats.h
+++ b/libs/binder/include/binder/IBatteryStats.h
@@ -68,6 +68,7 @@
class BnBatteryStats : public BnInterface<IBatteryStats>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 3f0dad0..1674516 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -47,7 +47,7 @@
* (method calls, property get and set) is down through a low-level
* protocol implemented on top of the transact() API.
*/
-class IBinder : public virtual RefBase
+class [[clang::lto_visibility_public]] IBinder : public virtual RefBase
{
public:
enum {
@@ -86,6 +86,7 @@
Vector<String16>& args, const sp<IShellCallback>& callback,
const sp<IResultReceiver>& resultReceiver);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
@@ -131,6 +132,7 @@
* (Nor should you need to, as there is nothing useful you can
* directly do with it now that it has passed on.)
*/
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0) = 0;
@@ -142,6 +144,7 @@
* supply a NULL @a recipient, and the recipient previously
* added with that cookie will be unlinked.
*/
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0,
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
index 3099bf5..071946f 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -43,7 +43,7 @@
virtual void* getBase() const = 0;
virtual size_t getSize() const = 0;
virtual uint32_t getFlags() const = 0;
- virtual uint32_t getOffset() const = 0;
+ virtual off_t getOffset() const = 0;
// these are there just for backward source compatibility
int32_t heapID() const { return getHeapID(); }
@@ -54,7 +54,8 @@
class BnMemoryHeap : public BnInterface<IMemoryHeap>
{
public:
- virtual status_t onTransact(
+ // NOLINTNEXTLINE(google-default-arguments)
+ virtual status_t onTransact(
uint32_t code,
const Parcel& data,
Parcel* reply,
@@ -72,6 +73,7 @@
public:
DECLARE_META_INTERFACE(Memory)
+ // NOLINTNEXTLINE(google-default-arguments)
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0;
// helpers
@@ -84,6 +86,7 @@
class BnMemory : public BnInterface<IMemory>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 3ec459f..26a1b23 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -56,6 +56,7 @@
class BnPermissionController : public BnInterface<IPermissionController>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h
index e494fba..00b3d89 100644
--- a/libs/binder/include/binder/IResultReceiver.h
+++ b/libs/binder/include/binder/IResultReceiver.h
@@ -41,6 +41,7 @@
class BnResultReceiver : public BnInterface<IResultReceiver>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 1d39aa3..aeea1a2 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -61,6 +61,7 @@
/**
* Register a service.
*/
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated = false,
int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
@@ -68,6 +69,7 @@
/**
* Return list of all existing services.
*/
+ // NOLINTNEXTLINE(google-default-arguments)
virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
enum {
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index b47e995..6715678 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -42,6 +42,7 @@
class BnShellCallback : public BnInterface<IShellCallback>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
index d81789e..9937ad6 100644
--- a/libs/binder/include/binder/IUidObserver.h
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -47,6 +47,7 @@
class BnUidObserver : public BnInterface<IUidObserver>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index 5e0a382..2f5039d 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -42,7 +42,7 @@
* maps the memory referenced by fd. but DOESN'T take ownership
* of the filedescriptor (it makes a copy with dup()
*/
- MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);
+ MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, off_t offset = 0);
/*
* maps memory from the given device
@@ -64,7 +64,7 @@
virtual size_t getSize() const;
virtual uint32_t getFlags() const;
- virtual uint32_t getOffset() const;
+ off_t getOffset() const override;
const char* getDevice() const;
@@ -82,11 +82,11 @@
protected:
MemoryHeapBase();
// init() takes ownership of fd
- status_t init(int fd, void *base, int size,
+ status_t init(int fd, void *base, size_t size,
int flags = 0, const char* device = nullptr);
private:
- status_t mapfd(int fd, size_t size, uint32_t offset = 0);
+ status_t mapfd(int fd, size_t size, off_t offset = 0);
int mFD;
size_t mSize;
@@ -94,7 +94,7 @@
uint32_t mFlags;
const char* mDevice;
bool mNeedUnmap;
- uint32_t mOffset;
+ off_t mOffset;
};
// ---------------------------------------------------------------------------
diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format
new file mode 100644
index 0000000..9a9d936
--- /dev/null
+++ b/libs/binder/ndk/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+ColumnLimit: 100
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Left
+TabWidth: 4
+AllowShortFunctionsOnASingleLine: Inline
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 5461b4f..d16502f 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -38,6 +38,8 @@
"libbinder",
"libutils",
],
+
+ version_script: "libbinder_ndk.map.txt",
}
ndk_headers {
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 896c5c1..f3fb9c3 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -45,7 +45,7 @@
return binder != nullptr && binder->findObject(kId) == kValue;
}
-} // namespace ABBinderTag
+} // namespace ABBinderTag
namespace ABpBinderTag {
@@ -60,7 +60,7 @@
delete static_cast<Value*>(obj);
};
-} // namespace ABpBinderTag
+} // namespace ABpBinderTag
AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
AIBinder::~AIBinder() {}
@@ -91,7 +91,7 @@
return false;
}
- CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
+ CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
String8 descriptor(getBinder()->getInterfaceDescriptor());
if (descriptor != newDescriptor) {
@@ -107,7 +107,7 @@
}
ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
- : AIBinder(clazz), BBinder(), mUserData(userData) {
+ : AIBinder(clazz), BBinder(), mUserData(userData) {
CHECK(clazz != nullptr);
}
ABBinder::~ABBinder() {
@@ -136,7 +136,7 @@
}
ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
- : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+ : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
CHECK(binder != nullptr);
}
ABpBinder::~ABpBinder() {}
@@ -214,10 +214,10 @@
AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy,
AIBinder_Class_onTransact onTransact)
- : onCreate(onCreate),
- onDestroy(onDestroy),
- onTransact(onTransact),
- mInterfaceDescriptor(interfaceDescriptor) {}
+ : onCreate(onCreate),
+ onDestroy(onDestroy),
+ onTransact(onTransact),
+ mInterfaceDescriptor(interfaceDescriptor) {}
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
AIBinder_Class_onCreate onCreate,
@@ -239,7 +239,7 @@
}
AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
- : mOnDied(onDied) {
+ : mOnDied(onDied) {
CHECK(onDied != nullptr);
}
@@ -302,7 +302,7 @@
bool AIBinder_isRemote(const AIBinder* binder) {
if (binder == nullptr) {
- return true;
+ return false;
}
return binder->isRemote();
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 5b6bc94..ac592ea 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -49,7 +49,7 @@
return binder->remoteBinder() != nullptr;
}
-private:
+ private:
// AIBinder instance is instance of this class for a local object. In order to transact on a
// remote object, this also must be set for simplicity (although right now, only the
// interfaceDescriptor from it is used).
@@ -69,7 +69,7 @@
::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
::android::Parcel* reply, binder_flags_t flags) override;
-private:
+ private:
ABBinder(const AIBinder_Class* clazz, void* userData);
// only thing that should create an ABBinder
@@ -96,7 +96,7 @@
::android::sp<::android::IBinder> getBinder() override { return remote(); }
ABpBinder* asABpBinder() override { return this; }
-private:
+ private:
ABpBinder(const ::android::sp<::android::IBinder>& binder);
};
@@ -110,7 +110,7 @@
const AIBinder_Class_onDestroy onDestroy;
const AIBinder_Class_onTransact onTransact;
-private:
+ private:
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
// one.
const ::android::String16 mInterfaceDescriptor;
@@ -128,14 +128,14 @@
struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
const AIBinder_DeathRecipient_onBinderDied& onDied)
- : mWho(who), mCookie(cookie), mOnDied(onDied) {}
+ : mWho(who), mCookie(cookie), mOnDied(onDied) {}
void binderDied(const ::android::wp<::android::IBinder>& who) override;
const ::android::wp<::android::IBinder>& getWho() { return mWho; }
void* getCookie() { return mCookie; }
- private:
+ private:
::android::wp<::android::IBinder> mWho;
void* mCookie;
const AIBinder_DeathRecipient_onBinderDied& mOnDied;
@@ -145,7 +145,7 @@
binder_status_t linkToDeath(AIBinder* binder, void* cookie);
binder_status_t unlinkToDeath(AIBinder* binder, void* cookie);
-private:
+ private:
std::mutex mDeathRecipientsMutex;
std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
AIBinder_DeathRecipient_onBinderDied mOnDied;
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
index b8f38ba..80b6c07 100644
--- a/libs/binder/ndk/include_apex/android/binder_manager.h
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -17,11 +17,18 @@
#pragma once
#include <android/binder_ibinder.h>
+#include <android/binder_status.h>
__BEGIN_DECLS
/**
- * This registers the service with the default service manager under this instance name.
+ * This registers the service with the default service manager under this instance name. This does
+ * not take ownership of binder.
+ *
+ * \param binder object to register globally with the service manager.
+ * \param instance identifier of the service. This will be used to lookup the service.
+ *
+ * \return STATUS_OK on success.
*/
binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
@@ -29,6 +36,8 @@
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
* for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index cc0a29d..5c26039 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -32,8 +32,7 @@
#include <assert.h>
-#ifdef __cplusplus
-
+#include <unistd.h>
#include <cstddef>
namespace ndk {
@@ -42,7 +41,7 @@
* Represents one strong pointer to an AIBinder object.
*/
class SpAIBinder {
-public:
+ public:
/**
* Takes ownership of one strong refcount of binder.
*/
@@ -106,30 +105,30 @@
*/
AIBinder** getR() { return &mBinder; }
-private:
+ private:
AIBinder* mBinder = nullptr;
};
/**
* This baseclass owns a single object, used to make various classes RAII.
*/
-template <typename T, void (*Destroy)(T*)>
+template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
class ScopedAResource {
-public:
+ public:
/**
* Takes ownership of t.
*/
- explicit ScopedAResource(T* t = nullptr) : mT(t) {}
+ explicit ScopedAResource(T t = DEFAULT) : mT(t) {}
/**
* This deletes the underlying object if it exists. See set.
*/
- ~ScopedAResource() { set(nullptr); }
+ ~ScopedAResource() { set(DEFAULT); }
/**
* Takes ownership of t.
*/
- void set(T* t) {
+ void set(T t) {
Destroy(mT);
mT = t;
}
@@ -137,12 +136,12 @@
/**
* This returns the underlying object to be modified but does not affect ownership.
*/
- T* get() { return mT; }
+ T get() { return mT; }
/**
* This returns the const underlying object but does not affect ownership.
*/
- const T* get() const { return mT; }
+ const T get() const { return mT; }
/**
* This allows the value in this class to be set from beneath it. If you call this method and
@@ -156,7 +155,7 @@
* Other usecases are discouraged.
*
*/
- T** getR() { return &mT; }
+ T* getR() { return &mT; }
// copy-constructing, or move/copy assignment is disallowed
ScopedAResource(const ScopedAResource&) = delete;
@@ -166,15 +165,15 @@
// move-constructing is okay
ScopedAResource(ScopedAResource&&) = default;
-private:
- T* mT;
+ private:
+ T mT;
};
/**
* Convenience wrapper. See AParcel.
*/
-class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> {
-public:
+class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
+ public:
/**
* Takes ownership of a.
*/
@@ -186,8 +185,8 @@
/**
* Convenience wrapper. See AStatus.
*/
-class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> {
-public:
+class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
+ public:
/**
* Takes ownership of a.
*/
@@ -205,13 +204,14 @@
* Convenience wrapper. See AIBinder_DeathRecipient.
*/
class ScopedAIBinder_DeathRecipient
- : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> {
-public:
+ : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+ nullptr> {
+ public:
/**
* Takes ownership of a.
*/
explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
- : ScopedAResource(a) {}
+ : ScopedAResource(a) {}
~ScopedAIBinder_DeathRecipient() {}
ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
};
@@ -219,8 +219,9 @@
/**
* Convenience wrapper. See AIBinder_Weak.
*/
-class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> {
-public:
+class ScopedAIBinder_Weak
+ : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+ public:
/**
* Takes ownership of a.
*/
@@ -234,8 +235,19 @@
SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
};
-} // namespace ndk
+/**
+ * Convenience wrapper for a file descriptor.
+ */
+class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> {
+ public:
+ /**
+ * Takes ownership of a.
+ */
+ explicit ScopedFileDescriptor(int a = -1) : ScopedAResource(a) {}
+ ~ScopedFileDescriptor() {}
+ ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
+};
-#endif // __cplusplus
+} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index c222c16..d711ad8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -126,8 +126,9 @@
/**
* This is called whenever a new AIBinder object is needed of a specific class.
*
- * These arguments are passed from AIBinder_new. The return value is stored and can be retrieved
- * using AIBinder_getUserData.
+ * \param args these can be used to construct a new class. These are passed from AIBinder_new.
+ * \return this is the userdata representing the class. It can be retrieved using
+ * AIBinder_getUserData.
*/
typedef void* (*AIBinder_Class_onCreate)(void* args);
@@ -135,23 +136,41 @@
* This is called whenever an AIBinder object is no longer referenced and needs destroyed.
*
* Typically, this just deletes whatever the implementation is.
+ *
+ * \param userData this is the same object returned by AIBinder_Class_onCreate
*/
typedef void (*AIBinder_Class_onDestroy)(void* userData);
/**
* This is called whenever a transaction needs to be processed by a local implementation.
+ *
+ * \param binder the object being transacted on.
+ * \param code implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ *
+ * \return the implementation-specific output code. This may be forwarded from another service, the
+ * result of a parcel read or write, or another error as is applicable to the specific
+ * implementation. Usually, implementation-specific error codes are written to the output parcel,
+ * and the transaction code is reserved for kernel errors or error codes that have been repeated
+ * from subsequent transactions.
*/
typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transaction_code_t code,
const AParcel* in, AParcel* out);
/**
- * An interfaceDescriptor uniquely identifies the type of object that is being created. This is used
- * internally for sanity checks on transactions.
+ * This creates a new instance of a class of binders which can be instantiated. This is called one
+ * time during library initialization and cleaned up when the process exits or execs.
*
- * None of these parameters can be nullptr.
+ * None of these parameters can be null.
*
- * This is created one time during library initialization and cleaned up when the process exits or
- * execs.
+ * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
+ * sanity checks on transactions.
+ * \param onCreate see AIBinder_Class_onCreate.
+ * \param onDestroy see AIBinder_Class_onDestroy.
+ * \param onTransact see AIBinder_Class_onTransact.
+ *
+ * \return the class object representing these parameters or null on error.
*/
__attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define(
const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
@@ -174,12 +193,21 @@
* hypothetical removeCallback function, the remote process would have no way to determine that
* these two objects are actually equal using the AIBinder pointer alone (which they should be able
* to do). Also see the suggested memory ownership model suggested above.
+ *
+ * \param clazz the type of the object to be created.
+ * \param args the args to pass to AIBinder_onCreate for that class.
+ *
+ * \return a binder object representing the newly instantiated object.
*/
__attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args)
__INTRODUCED_IN(29);
/**
* If this is hosted in a process other than the current one.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the AIBinder represents an object in another process.
*/
bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29);
@@ -189,13 +217,21 @@
* this is automatically updated to reflect the current alive status of this binder. This will be
* updated as the result of a transaction made using AIBinder_transact, but it will also be updated
* based on the results of bookkeeping or other transactions made internally.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the binder is alive.
*/
bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29);
/**
- * Built-in transaction for all binder objects. This sends a transaction which will immediately
+ * Built-in transaction for all binder objects. This sends a transaction that will immediately
* return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
* sanity check.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return STATUS_OK if the ping succeeds.
*/
binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29);
@@ -209,6 +245,12 @@
* identification and holding user data.
*
* If binder is local, this will return STATUS_INVALID_OPERATION.
+ *
+ * \param binder the binder object you want to receive death notifications from.
+ * \param recipient the callback that will receive notifications when/if the binder dies.
+ * \param cookie the value that will be passed to the death recipient on death.
+ *
+ * \return STATUS_OK on success.
*/
binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) __INTRODUCED_IN(29);
@@ -217,22 +259,37 @@
* Stops registration for the associated binder dying. Does not delete the recipient. This function
* may return a binder transaction failure and in case the death recipient cannot be found, it
* returns STATUS_NAME_NOT_FOUND.
+ *
+ * \param binder the binder object to remove a previously linked death recipient from.
+ * \param recipient the callback to remove.
+ * \param cookie the cookie used to link to death.
+ *
+ * \return STATUS_OK on success. STATUS_NAME_NOT_FOUND if the binder cannot be found to be unlinked.
*/
binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) __INTRODUCED_IN(29);
/**
* This can only be called if a strong reference to this object already exists in process.
+ *
+ * \param binder the binder object to add a refcount to.
*/
void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29);
/**
* This will delete the object and call onDestroy once the refcount reaches zero.
+ *
+ * \param binder the binder object to remove a refcount from.
*/
void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29);
/**
* For debugging only!
+ *
+ * \param binder the binder object to retrieve the refcount of.
+ *
+ * \return the number of strong-refs on this binder in this process. If binder is null, this will be
+ * -1.
*/
int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29);
@@ -244,17 +301,32 @@
*
* This returns true if the class association succeeds. If it fails, no change is made to the
* binder object.
+ *
+ * \param binder the object to attach the class to.
+ * \param clazz the clazz to attach to binder.
+ *
+ * \return true if the binder has the class clazz and if the association was successful.
*/
bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __INTRODUCED_IN(29);
/**
* Returns the class that this binder was constructed with or associated with.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the class that this binder is associated with. If this binder wasn't created with
+ * AIBinder_new, and AIBinder_associateClass hasn't been called, then this will return null.
*/
const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29);
/**
* Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
- * nullptr), this also returns nullptr. For a remote binder, this will always return nullptr.
+ * null), this also returns null. For a remote binder, this will always return null.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the userdata returned from AIBinder_onCreate when this object was created. This may be
+ * null for stateless objects. For remote objects, this is always null.
*/
void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29);
@@ -278,6 +350,12 @@
* ownership is passed to the caller. At this point, the parcel can be filled out and passed to
* AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
* deleted with AParcel_delete.
+ *
+ * \param binder the binder object to start a transaction on.
+ * \param in out parameter for input data to the transaction.
+ *
+ * \return STATUS_OK on success. This will return STATUS_INVALID_OPERATION if the binder has not yet
+ * been associated with a class (see AIBinder_new and AIBinder_associateClass).
*/
binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __INTRODUCED_IN(29);
@@ -292,6 +370,16 @@
*
* This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
* and must be released with AParcel_delete when finished reading.
+ *
+ * \param binder the binder object to transact on.
+ * \param code the implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ * \param flags possible flags to alter the way in which the transaction is conducted or 0.
+ *
+ * \return the result from the kernel or from the remote process. Usually, implementation-specific
+ * error codes are written to the output parcel, and the transaction code is reserved for kernel
+ * errors or error codes that have been repeated from subsequent transactions.
*/
binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
AParcel** out, binder_flags_t flags) __INTRODUCED_IN(29);
@@ -299,29 +387,45 @@
/**
* This does not take any ownership of the input binder, but it can be used to retrieve it if
* something else in some process still holds a reference to it.
+ *
+ * \param binder object to create a weak pointer to.
+ *
+ * \return object representing a weak pointer to binder (or null if binder is null).
*/
__attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder)
__INTRODUCED_IN(29);
/**
* Deletes the weak reference. This will have no impact on the lifetime of the binder.
+ *
+ * \param weakBinder object created with AIBinder_Weak_new.
*/
void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29);
/**
* If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
- * nullptr.
+ * null.
+ *
+ * \param weakBinder weak pointer to attempt retrieving the original object from.
+ *
+ * \return an AIBinder object with one refcount given to the caller or null.
*/
__attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder)
__INTRODUCED_IN(29);
/**
* This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ *
+ * \param cookie the cookie passed to AIBinder_linkToDeath.
*/
typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
/**
* Creates a new binder death recipient. This can be attached to multiple different binder objects.
+ *
+ * \param onBinderDied the callback to call when this death recipient is invoked.
+ *
+ * \return the newly constructed object (or null if onBinderDied is null).
*/
__attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);
@@ -329,10 +433,12 @@
/**
* Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
* calling this as these will all be automatically unlinked.
+ *
+ * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
*/
void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index 81fb3c5..124f36c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -39,6 +39,12 @@
* If either env or the binder is null, null is returned. If this binder object was originally an
* AIBinder object, the original object is returned. The returned object has one refcount
* associated with it, and so this should be accompanied with an AIBinder_decStrong call.
+ *
+ * \param env Java environment.
+ * \param binder android.os.IBinder java object.
+ *
+ * \return an AIBinder object representing the Java binder object. If either parameter is null, or
+ * the Java object is of the wrong type, this will return null.
*/
__attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder)
__INTRODUCED_IN(29);
@@ -48,11 +54,16 @@
*
* If either env or the binder is null, null is returned. If this binder object was originally an
* IBinder object, the original java object will be returned.
+ *
+ * \param env Java environment.
+ * \param binder the object to convert.
+ *
+ * \return an android.os.IBinder object or null if the parameters were null.
*/
__attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
__INTRODUCED_IN(29);
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index e37c388..1532725 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -32,8 +32,6 @@
#include <assert.h>
-#ifdef __cplusplus
-
#include <memory>
#include <mutex>
@@ -46,7 +44,7 @@
* construct this object is with SharedRefBase::make.
*/
class SharedRefBase {
-public:
+ public:
SharedRefBase() {}
virtual ~SharedRefBase() {
std::call_once(mFlagThis, [&]() {
@@ -83,7 +81,7 @@
return t->template ref<T>();
}
-private:
+ private:
std::once_flag mFlagThis;
std::weak_ptr<SharedRefBase> mThis;
};
@@ -92,7 +90,7 @@
* wrapper analog to IInterface
*/
class ICInterface : public SharedRefBase {
-public:
+ public:
ICInterface() {}
virtual ~ICInterface() {}
@@ -113,7 +111,7 @@
*/
template <typename INTERFACE>
class BnCInterface : public INTERFACE {
-public:
+ public:
BnCInterface() {}
virtual ~BnCInterface() {}
@@ -121,15 +119,15 @@
bool isRemote() override { return true; }
-protected:
+ protected:
/**
* This function should only be called by asBinder. Otherwise, there is a possibility of
* multiple AIBinder* objects being created for the same instance of an object.
*/
virtual SpAIBinder createBinder() = 0;
-private:
- std::mutex mMutex; // for asBinder
+ private:
+ std::mutex mMutex; // for asBinder
ScopedAIBinder_Weak mWeakBinder;
};
@@ -138,7 +136,7 @@
*/
template <typename INTERFACE>
class BpCInterface : public INTERFACE {
-public:
+ public:
BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
virtual ~BpCInterface() {}
@@ -146,7 +144,7 @@
bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
-private:
+ private:
SpAIBinder mBinder;
};
@@ -171,8 +169,6 @@
return mBinder;
}
-} // namespace ndk
-
-#endif // __cplusplus
+} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index d36b3c0..4ee1b67 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -47,110 +47,264 @@
/**
* Cleans up a parcel.
+ *
+ * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a
+ * transaction is being aborted.
*/
void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
/**
- * This is called to allocate an array with a given length. If allocation fails, null should be
- * returned.
+ * This is called to allocate a buffer for a C-style string (null-terminated). The returned buffer
+ * should be at least length bytes. This includes space for a null terminator. length will always be
+ * strictly less than or equal to the maximum size that can be held in a size_t and will always be
+ * greater than 0.
+ *
+ * See also AParcel_readString.
+ *
+ * If allocation fails, null should be returned.
+ *
+ * \param stringData some external representation of a string
+ * \param length the length of the buffer needed to fill (including the null-terminator)
+ *
+ * \return a buffer of size 'length' or null if allocation failed.
*/
-typedef void* (*AParcel_arrayReallocator)(void* vectorData, size_t length);
+typedef char* (*AParcel_stringAllocator)(void* stringData, size_t length);
+
+/**
+ * This is called to allocate an array of size 'length'.
+ *
+ * See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array
+ * \param length the length to allocate this array to
+ *
+ * \return true if allocation succeeded
+ */
+typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, size_t length);
+
+/**
+ * This is called to allocate a string inside of an array that was allocated by an
+ * AParcel_stringArrayAllocator.
+ *
+ * The index returned will always be within the range [0, length of arrayData). The returned buffer
+ * should be at least length bytes. This includes space for a null-terminator. length will always be
+ * strictly less than or equal to the maximum size that can be held in a size_t and will always be
+ * greater than 0.
+ *
+ * See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param length the length of the string to be allocated at this index. See also
+ * AParcel_stringAllocator. This includes the length required for a null-terminator.
+ *
+ * \return a buffer of size 'length' or null if allocation failed.
+ */
+typedef char* (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, size_t length);
+
+/**
+ * This returns the length and buffer of an array at a specific index in an arrayData object.
+ *
+ * See also AParcel_writeStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param outLength an out parameter for the length of the string at the specified index. This
+ * should not include the length for a null-terminator if there is one.
+ *
+ * \param a buffer of size outLength or more representing the string at the provided index. This is
+ * not required to be null-terminated.
+ */
+typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index,
+ size_t* outLength);
// @START-PRIMITIVE-VECTOR-GETTERS
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readInt32Array
+ *
+ * \param arrayData some external representation of an array of int32_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of int32_t of size 'length'.
*/
-typedef int32_t* (*AParcel_int32ArrayGetter)(void* arrayData);
+typedef int32_t* (*AParcel_int32ArrayAllocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readUint32Array
+ *
+ * \param arrayData some external representation of an array of uint32_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of uint32_t of size 'length'.
*/
-typedef uint32_t* (*AParcel_uint32ArrayGetter)(void* arrayData);
+typedef uint32_t* (*AParcel_uint32ArrayAllocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readInt64Array
+ *
+ * \param arrayData some external representation of an array of int64_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of int64_t of size 'length'.
*/
-typedef int64_t* (*AParcel_int64ArrayGetter)(void* arrayData);
+typedef int64_t* (*AParcel_int64ArrayAllocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readUint64Array
+ *
+ * \param arrayData some external representation of an array of uint64_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of uint64_t of size 'length'.
*/
-typedef uint64_t* (*AParcel_uint64ArrayGetter)(void* arrayData);
+typedef uint64_t* (*AParcel_uint64ArrayAllocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readFloatArray
+ *
+ * \param arrayData some external representation of an array of float.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of float of size 'length'.
*/
-typedef float* (*AParcel_floatArrayGetter)(void* arrayData);
+typedef float* (*AParcel_floatArrayAllocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readDoubleArray
+ *
+ * \param arrayData some external representation of an array of double.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of double of size 'length'.
*/
-typedef double* (*AParcel_doubleArrayGetter)(void* arrayData);
+typedef double* (*AParcel_doubleArrayAllocator)(void* arrayData, size_t length);
/**
- * This is called to get the underlying data from an arrayData object.
+ * This allocates an array of size 'length' inside of arrayData and returns whether or not there was
+ * a success.
*
- * This will never be called for an empty array.
+ * See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return whether the allocation succeeded.
+ */
+typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, size_t length);
+
+/**
+ * This is called to get the underlying data from an arrayData object at index.
+ *
+ * See also AParcel_writeBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be retrieved.
+ *
+ * \return the value of the array at index index.
*/
typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index);
/**
* This is called to set an underlying value in an arrayData object at index.
+ *
+ * See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be set.
+ * \param value the value to set at index index.
*/
typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readCharArray
+ *
+ * \param arrayData some external representation of an array of char16_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of char16_t of size 'length'.
*/
-typedef char16_t* (*AParcel_charArrayGetter)(void* arrayData);
+typedef char16_t* (*AParcel_charArrayAllocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readByteArray
+ *
+ * \param arrayData some external representation of an array of int8_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of int8_t of size 'length'.
*/
-typedef int8_t* (*AParcel_byteArrayGetter)(void* arrayData);
+typedef int8_t* (*AParcel_byteArrayAllocator)(void* arrayData, size_t length);
// @END-PRIMITIVE-VECTOR-GETTERS
/**
- * This is called to allocate a buffer
+ * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any
+ * refcounts of ownership of the binder from the client.
*
- * The length here includes the space required to insert a '\0' for a properly formed c-str. If the
- * buffer returned from this function is retStr, it will be filled by AParcel_readString with the
- * data from the remote process, and it will be filled such that retStr[length] == '\0'.
+ * \param parcel the parcel to write to.
+ * \param binder the value to write to the parcel.
*
- * If allocation fails, null should be returned.
- */
-typedef void* (*AParcel_stringReallocator)(void* stringData, size_t length);
-
-/**
- * This is called to get the buffer from a stringData object.
- */
-typedef char* (*AParcel_stringGetter)(void* stringData);
-
-/**
- * Writes an AIBinder to the next location in a non-null parcel. Can be null.
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29);
/**
* Reads an AIBinder from the next location in a non-null parcel. This will fail if the binder is
* non-null. One strong ref-count of ownership is passed to the caller of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel. This will not be null on
+ * success.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder)
__INTRODUCED_IN(29);
@@ -158,11 +312,44 @@
/**
* Reads an AIBinder from the next location in a non-null parcel. This may read a null. One strong
* ref-count of ownership is passed to the caller of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel. This may be null even on
+ * success.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder)
__INTRODUCED_IN(29);
/**
+ * Writes a file descriptor to the next location in a non-null parcel. This does not take ownership
+ * of fd.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to write to.
+ * \param fd the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
+
+/**
+ * Reads an int from the next location in a non-null parcel.
+ *
+ * The returned fd must be closed.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
+
+/**
* Writes an AStatus object to the next location in a non-null parcel.
*
* If the status is considered to be a low-level status and has no additional information other
@@ -170,6 +357,11 @@
* status will be returned from this method and nothing will be written to the parcel. If either
* this happens or if writing the status object itself fails, the return value from this function
* should be propagated to the client, and AParcel_readStatusHeader shouldn't be called.
+ *
+ * \param parcel the parcel to write to.
+ * \param status the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status)
__INTRODUCED_IN(29);
@@ -177,243 +369,527 @@
/**
* Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
* of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param status the out parameter for what is read from the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status)
__INTRODUCED_IN(29);
/**
- * Writes string value to the next location in a non-null parcel.
+ * Writes utf-8 string value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param string the null-terminated string to write to the parcel, at least of size 'length'.
+ * \param length the length of the string to be written.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length)
__INTRODUCED_IN(29);
/**
- * Reads and allocates string value from the next location in a non-null parcel.
+ * Reads and allocates utf-8 string value from the next location in a non-null parcel.
*
- * Data is passed to the string allocator once the string size is known. This data should be used to
- * point to some kind of string data. For instance, it could be a char*, and the string allocator
- * could be realloc. Then the getter would simply be a cast to char*. In more complicated cases,
- * stringData could be a structure containing additional string data.
+ * Data is passed to the string allocator once the string size is known. This size includes the
+ * space for the null-terminator of this string. This allocator returns a buffer which is used as
+ * the output buffer from this read.
*
- * If this function returns a success, the buffer returned by allocator when passed stringData will
- * contain a null-terminated c-str read from the binder.
+ * \param parcel the parcel to read from.
+ * \param stringData some external representation of a string.
+ * \param allocator allocator that will be called once the size of the string is known.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator,
- AParcel_stringGetter getter, void** stringData)
+binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
+ AParcel_stringAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Writes utf-8 string array data to the next location in a non-null parcel.
+ *
+ * length is the length of the array. AParcel_stringArrayElementGetter will be called for all
+ * indices in range [0, length) with the arrayData provided here. The string length and buffer
+ * returned from this function will be used to fill out the data from the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of the array to be written.
+ * \param getter the callback that will be called for every index of the array to retrieve the
+ * corresponding string buffer.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+ AParcel_stringArrayElementGetter getter)
+ __INTRODUCED_IN(29);
+
+/**
+ * Reads and allocates utf-8 string array value from the next location in a non-null parcel.
+ *
+ * First, AParcel_stringArrayAllocator will be called with the size of the array to be read where
+ * length is the length of the array to be read from the parcel. Then, for each index i in [0,
+ * length), AParcel_stringArrayElementAllocator will be called with the length of the string to be
+ * read from the parcel. The resultant buffer from each of these calls will be filled according to
+ * the contents of the string that is read.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called with arrayData once the size of the output
+ * array is known.
+ * \param elementAllocator the callback that will be called on every index of arrayData to allocate
+ * the string at that location.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+ AParcel_stringArrayAllocator allocator,
+ AParcel_stringArrayElementAllocator elementAllocator)
__INTRODUCED_IN(29);
// @START-PRIMITIVE-READ-WRITE
/**
* Writes int32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_IN(29);
/**
* Writes uint32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCED_IN(29);
/**
* Writes int64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_IN(29);
/**
* Writes uint64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCED_IN(29);
/**
* Writes float value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN(29);
/**
* Writes double value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_IN(29);
/**
* Writes bool value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(29);
/**
* Writes char16_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_IN(29);
/**
* Writes int8_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN(29);
/**
* Reads into int32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRODUCED_IN(29);
/**
* Reads into uint32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INTRODUCED_IN(29);
/**
* Reads into int64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRODUCED_IN(29);
/**
* Reads into uint64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INTRODUCED_IN(29);
/**
* Reads into float value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODUCED_IN(29);
/**
* Reads into double value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRODUCED_IN(29);
/**
* Reads into bool value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCED_IN(29);
/**
* Reads into char16_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRODUCED_IN(29);
/**
* Reads into int8_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29);
/**
* Writes an array of int32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length)
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, size_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of uint32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length)
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, size_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of int64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length)
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, size_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of uint64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length)
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, size_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of float to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length)
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, size_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of double to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length)
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, size_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of bool to the next location in a non-null parcel.
+ *
+ * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying
+ * values to write to the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of arrayData.
+ * \param getter the callback to retrieve data at specific locations in the array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData,
- AParcel_boolArrayGetter getter, size_t length)
- __INTRODUCED_IN(29);
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, size_t length,
+ AParcel_boolArrayGetter getter) __INTRODUCED_IN(29);
/**
* Writes an array of char16_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length)
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, size_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of int8_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length)
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, size_t length)
__INTRODUCED_IN(29);
/**
* Reads an array of int32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_int32ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+ AParcel_int32ArrayAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of uint32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_uint32ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+ AParcel_uint32ArrayAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of int64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_int64ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+ AParcel_int64ArrayAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of uint64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_uint64ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+ AParcel_uint64ArrayAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of float from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_floatArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+ AParcel_floatArrayAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of double from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_doubleArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+ AParcel_doubleArrayAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of bool from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. Then, for every i in [0, length),
+ * setter(arrayData, i, x) will be called where x is the value at the associated index.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ * \param setter the callback that will be called to set a value at a specific location in the
+ * array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+ AParcel_boolArrayAllocator allocator,
AParcel_boolArraySetter setter) __INTRODUCED_IN(29);
/**
* Reads an array of char16_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_charArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+ AParcel_charArrayAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of int8_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
-binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_byteArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+ AParcel_byteArrayAllocator allocator) __INTRODUCED_IN(29);
// @END-PRIMITIVE-READ-WRITE
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index faeb78f..2ccbe5a 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -28,32 +28,40 @@
#include <android/binder_parcel.h>
-#ifdef __cplusplus
-
#include <string>
#include <vector>
namespace ndk {
/**
- * This resizes a std::vector of some underlying type to the given length.
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
*/
template <typename T>
-static inline void* AParcel_stdVectorReallocator(void* vectorData, size_t length) {
+static inline T* AParcel_stdVectorAllocator(void* vectorData, size_t length) {
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
if (length > vec->max_size()) return nullptr;
vec->resize(length);
- return vec;
+ return vec->data();
}
/**
- * This retrieves the underlying contiguous vector from a corresponding vectorData.
+ * This allocates a vector to size 'length' and returns whether the allocation is successful.
+ *
+ * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined
+ * externally with respect to the NDK, and that size information is not passed into the NDK.
+ * Instead, it is used in cases where callbacks are used.
+ *
+ * See AParcel_readVector(const AParcel* parcel, std::vector<bool>)
+ * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>)
*/
template <typename T>
-static inline T* AParcel_stdVectorGetter(void* vectorData) {
+static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, size_t length) {
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
- return vec->data();
+ if (length > vec->max_size()) return false;
+
+ vec->resize(length);
+ return true;
}
/**
@@ -76,212 +84,180 @@
(*vec)[index] = value;
}
-/**
- * Writes a vector to the next location in a non-null parcel.
- */
-template <typename T>
-static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<T>& vec);
-
-/**
- * Reads a vector to the next location in a non-null parcel.
- */
-template <typename T>
-static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<T>* vec);
-
// @START
/**
* Writes a vector of int32_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<int32_t>(AParcel* parcel,
- const std::vector<int32_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of int32_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<int32_t>(const AParcel* parcel,
- std::vector<int32_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readInt32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int32_t>,
- AParcel_stdVectorGetter<int32_t>);
+ return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
}
/**
* Writes a vector of uint32_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<uint32_t>(AParcel* parcel,
- const std::vector<uint32_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of uint32_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<uint32_t>(const AParcel* parcel,
- std::vector<uint32_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readUint32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint32_t>,
- AParcel_stdVectorGetter<uint32_t>);
+ return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>);
}
/**
* Writes a vector of int64_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<int64_t>(AParcel* parcel,
- const std::vector<int64_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of int64_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<int64_t>(const AParcel* parcel,
- std::vector<int64_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readInt64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int64_t>,
- AParcel_stdVectorGetter<int64_t>);
+ return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
}
/**
* Writes a vector of uint64_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<uint64_t>(AParcel* parcel,
- const std::vector<uint64_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of uint64_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<uint64_t>(const AParcel* parcel,
- std::vector<uint64_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readUint64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint64_t>,
- AParcel_stdVectorGetter<uint64_t>);
+ return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>);
}
/**
* Writes a vector of float to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<float>(AParcel* parcel, const std::vector<float>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of float from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<float>(const AParcel* parcel, std::vector<float>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readFloatArray(parcel, &vectorData, &AParcel_stdVectorReallocator<float>,
- AParcel_stdVectorGetter<float>);
+ return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>);
}
/**
* Writes a vector of double to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<double>(AParcel* parcel,
- const std::vector<double>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of double from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<double>(const AParcel* parcel, std::vector<double>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readDoubleArray(parcel, &vectorData, &AParcel_stdVectorReallocator<double>,
- AParcel_stdVectorGetter<double>);
+ return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>);
}
/**
* Writes a vector of bool to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<bool>(AParcel* parcel, const std::vector<bool>& vec) {
- return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
- AParcel_stdVectorGetter<bool>, vec.size());
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
+ return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
+ AParcel_stdVectorGetter<bool>);
}
/**
* Reads a vector of bool from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<bool>(const AParcel* parcel, std::vector<bool>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readBoolArray(parcel, &vectorData, &AParcel_stdVectorReallocator<bool>,
+ return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<bool>,
AParcel_stdVectorSetter<bool>);
}
/**
* Writes a vector of char16_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<char16_t>(AParcel* parcel,
- const std::vector<char16_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
return AParcel_writeCharArray(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of char16_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<char16_t>(const AParcel* parcel,
- std::vector<char16_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readCharArray(parcel, &vectorData, &AParcel_stdVectorReallocator<char16_t>,
- AParcel_stdVectorGetter<char16_t>);
+ return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>);
}
/**
* Writes a vector of int8_t to the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_writeVector<int8_t>(AParcel* parcel,
- const std::vector<int8_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
return AParcel_writeByteArray(parcel, vec.data(), vec.size());
}
/**
* Reads a vector of int8_t from the next location in a non-null parcel.
*/
-template <>
-inline binder_status_t AParcel_readVector<int8_t>(const AParcel* parcel, std::vector<int8_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readByteArray(parcel, &vectorData, &AParcel_stdVectorReallocator<int8_t>,
- AParcel_stdVectorGetter<int8_t>);
+ return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
}
// @END
/**
- * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString.
- * See use below in AParcel_readString.
+ * Allocates a std::string to length and returns the underlying buffer. For use with
+ * AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*).
*/
-static inline void* AParcel_stdStringReallocator(void* stringData, size_t length) {
+static inline char* AParcel_stdStringAllocator(void* stringData, size_t length) {
std::string* str = static_cast<std::string*>(stringData);
str->resize(length - 1);
- return stringData;
+ return &(*str)[0];
}
/**
- * Takes a std::string and returns the inner char*.
+ * Allocates a std::string inside of a std::vector<std::string> at index index to size 'length'.
*/
-static inline char* AParcel_stdStringGetter(void* stringData) {
- std::string* str = static_cast<std::string*>(stringData);
- return &(*str)[0];
+static inline char* AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index,
+ size_t length) {
+ std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData);
+
+ std::string& element = vec->at(index);
+ element.resize(length - 1);
+ return &element[0];
+}
+
+/**
+ * This gets the length and buffer of a std::string inside of a std::vector<std::string> at index
+ * index.
+ */
+static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index,
+ size_t* outLength) {
+ const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
+
+ const std::string& element = vec->at(index);
+
+ *outLength = element.size();
+ return element.c_str();
}
/**
@@ -296,10 +272,33 @@
*/
static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
void* stringData = static_cast<void*>(str);
- return AParcel_readString(parcel, AParcel_stdStringReallocator, AParcel_stdStringGetter,
- &stringData);
+ return AParcel_readString(parcel, stringData, AParcel_stdStringAllocator);
}
+/**
+ * Convenience API for writing a std::vector<std::string>
+ */
+static inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::vector<std::string>& vec) {
+ const void* vectorData = static_cast<const void*>(&vec);
+ return AParcel_writeStringArray(parcel, vectorData, vec.size(),
+ AParcel_stdVectorStringElementGetter);
+}
+
+/**
+ * Convenience API for reading a std::vector<std::string>
+ */
+static inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::vector<std::string>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readStringArray(parcel, vectorData,
+ AParcel_stdVectorExternalAllocator<std::string>,
+ AParcel_stdVectorStringElementAllocator);
+}
+
+/**
+ * Convenience API for writing the size of a vector.
+ */
template <typename T>
static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) {
if (vec.size() > INT32_MAX) {
@@ -309,6 +308,9 @@
return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size()));
}
+/**
+ * Convenience API for resizing a vector.
+ */
template <typename T>
static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) {
int32_t size;
@@ -321,8 +323,6 @@
return STATUS_OK;
}
-} // namespace ndk
-
-#endif // __cplusplus
+} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 2d8b7fa..2671b9b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -35,7 +35,7 @@
enum {
STATUS_OK = 0,
- STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value
+ STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value
STATUS_NO_MEMORY = -ENOMEM,
STATUS_INVALID_OPERATION = -ENOSYS,
STATUS_BAD_VALUE = -EINVAL,
@@ -95,24 +95,39 @@
* along with service specific errors.
*
* It is not required to be used in order to parcel/receive transactions, but it is required in
- * order to be compatible with standard AIDL transactions.
+ * order to be compatible with standard AIDL transactions since it is written as the header to the
+ * out parcel for transactions which get executed (don't fail during unparceling of input arguments
+ * or sooner).
*/
struct AStatus;
typedef struct AStatus AStatus;
/**
* New status which is considered a success.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29);
/**
* New status with exception code.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_exception_t exception)
__INTRODUCED_IN(29);
/**
* New status with exception code and message.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessage(
binder_exception_t exception, const char* message) __INTRODUCED_IN(29);
@@ -121,6 +136,10 @@
* New status with a service speciic error.
*
* This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError(
int32_t serviceSpecific) __INTRODUCED_IN(29);
@@ -129,6 +148,11 @@
* New status with a service specific error and message.
*
* This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWithMessage(
int32_t serviceSpecific, const char* message) __INTRODUCED_IN(29);
@@ -137,6 +161,10 @@
* New status with binder_status_t. This is typically for low level failures when a binder_status_t
* is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
* an AStatus instance.
+ *
+ * \param a low-level error to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status)
__INTRODUCED_IN(29);
@@ -144,11 +172,19 @@
/**
* Whether this object represents a successful transaction. If this function returns true, then
* AStatus_getExceptionCode will return EX_NONE.
+ *
+ * \param status the status being queried.
+ *
+ * \return whether the status represents a successful transaction. For more details, see below.
*/
bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29);
/**
* The exception that this status object represents.
+ *
+ * \param status the status being queried.
+ *
+ * \return the exception code that this object represents.
*/
binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_IN(29);
@@ -157,6 +193,10 @@
* non-zero result if AStatus_getExceptionCode returns EX_SERVICE_SPECIFIC. If this function returns
* 0, the status object may still represent a different exception or status. To find out if this
* transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0.
*/
int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(29);
@@ -165,6 +205,10 @@
* if AStatus_getExceptionCode returns EX_TRANSACTION_FAILED. If this function return 0, the status
* object may represent a different exception or a service specific error. To find out if this
* transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0.
*/
binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29);
@@ -173,15 +217,21 @@
* message, this will return an empty string.
*
* The returned string has the lifetime of the status object passed into this function.
+ *
+ * \param status the status being queried.
+ *
+ * \return the message associated with this error.
*/
const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29);
/**
* Deletes memory associated with the status instance.
+ *
+ * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs.
*/
void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f84814f..d2c1a3d 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -38,8 +38,10 @@
AParcel_readInt64;
AParcel_readInt64Array;
AParcel_readNullableStrongBinder;
+ AParcel_readParcelFileDescriptor;
AParcel_readStatusHeader;
AParcel_readString;
+ AParcel_readStringArray;
AParcel_readStrongBinder;
AParcel_readUint32;
AParcel_readUint32Array;
@@ -59,8 +61,10 @@
AParcel_writeInt32Array;
AParcel_writeInt64;
AParcel_writeInt64Array;
+ AParcel_writeParcelFileDescriptor;
AParcel_writeStatusHeader;
AParcel_writeString;
+ AParcel_writeStringArray;
AParcel_writeStrongBinder;
AParcel_writeUint32;
AParcel_writeUint32Array;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 29094db..8e5b477 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -23,16 +23,23 @@
#include <limits>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <binder/Parcel.h>
+#include <binder/ParcelFileDescriptor.h>
#include <utils/Unicode.h>
using ::android::IBinder;
using ::android::Parcel;
using ::android::sp;
using ::android::status_t;
+using ::android::base::unique_fd;
+using ::android::os::ParcelFileDescriptor;
template <typename T>
-using ContiguousArrayGetter = T* (*)(void* arrayData);
+using ContiguousArrayAllocator = T* (*)(void* arrayData, size_t length);
+
+template <typename T>
+using ArrayAllocator = bool (*)(void* arrayData, size_t length);
template <typename T>
using ArrayGetter = T (*)(const void* arrayData, size_t index);
template <typename T>
@@ -81,8 +88,8 @@
}
template <typename T>
-binder_status_t ReadArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator, ContiguousArrayGetter<T> getter) {
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData,
+ ContiguousArrayAllocator<T> allocator) {
const Parcel* rawParcel = parcel->get();
int32_t length;
@@ -91,12 +98,8 @@
if (status != STATUS_OK) return PruneStatusT(status);
if (length < 0) return STATUS_UNEXPECTED_NULL;
- *arrayData = reallocator(*arrayData, length);
- if (*arrayData == nullptr) return STATUS_NO_MEMORY;
-
+ T* array = allocator(arrayData, length);
if (length == 0) return STATUS_OK;
-
- T* array = getter(*arrayData);
if (array == nullptr) return STATUS_NO_MEMORY;
int32_t size = 0;
@@ -112,9 +115,8 @@
// Each element in a char16_t array is converted to an int32_t (not packed)
template <>
-binder_status_t ReadArray<char16_t>(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- ContiguousArrayGetter<char16_t> getter) {
+binder_status_t ReadArray<char16_t>(const AParcel* parcel, void* arrayData,
+ ContiguousArrayAllocator<char16_t> allocator) {
const Parcel* rawParcel = parcel->get();
int32_t length;
@@ -123,12 +125,8 @@
if (status != STATUS_OK) return PruneStatusT(status);
if (length < 0) return STATUS_UNEXPECTED_NULL;
- *arrayData = reallocator(*arrayData, length);
- if (*arrayData == nullptr) return STATUS_NO_MEMORY;
-
+ char16_t* array = allocator(arrayData, length);
if (length == 0) return STATUS_OK;
-
- char16_t* array = getter(*arrayData);
if (array == nullptr) return STATUS_NO_MEMORY;
int32_t size = 0;
@@ -144,8 +142,8 @@
}
template <typename T>
-binder_status_t WriteArray(AParcel* parcel, const void* arrayData, ArrayGetter<T> getter,
- size_t length, status_t (Parcel::*write)(T)) {
+binder_status_t WriteArray(AParcel* parcel, const void* arrayData, size_t length,
+ ArrayGetter<T> getter, status_t (Parcel::*write)(T)) {
if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
Parcel* rawParcel = parcel->get();
@@ -163,9 +161,8 @@
}
template <typename T>
-binder_status_t ReadArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator, ArraySetter<T> setter,
- status_t (Parcel::*read)(T*) const) {
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData, ArrayAllocator<T> allocator,
+ ArraySetter<T> setter, status_t (Parcel::*read)(T*) const) {
const Parcel* rawParcel = parcel->get();
int32_t length;
@@ -174,15 +171,14 @@
if (status != STATUS_OK) return PruneStatusT(status);
if (length < 0) return STATUS_UNEXPECTED_NULL;
- *arrayData = reallocator(*arrayData, length);
- if (*arrayData == nullptr) return STATUS_NO_MEMORY;
+ if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
for (size_t i = 0; i < length; i++) {
T readTarget;
status = (rawParcel->*read)(&readTarget);
if (status != STATUS_OK) return PruneStatusT(status);
- setter(*arrayData, i, readTarget);
+ setter(arrayData, i, readTarget);
}
return STATUS_OK;
@@ -218,16 +214,38 @@
*binder = ret.get();
return PruneStatusT(status);
}
+
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) {
+ ParcelFileDescriptor parcelFd((unique_fd(fd)));
+
+ status_t status = parcel->get()->writeParcelable(parcelFd);
+
+ // ownership is retained by caller
+ (void)parcelFd.release().release();
+
+ return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
+ ParcelFileDescriptor parcelFd;
+ // status_t status = parcelFd.readFromParcel(parcel->get());
+ status_t status = parcel->get()->readParcelable(&parcelFd);
+ if (status != STATUS_OK) return PruneStatusT(status);
+
+ *fd = parcelFd.release().release();
+ return STATUS_OK;
+}
+
binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
return PruneStatusT(status->get()->writeToParcel(parcel->get()));
}
binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) {
::android::binder::Status bstatus;
binder_status_t ret = PruneStatusT(bstatus.readFromParcel(*parcel->get()));
- if (ret == EX_NONE) {
+ if (ret == STATUS_OK) {
*status = new AStatus(std::move(bstatus));
}
- return ret;
+ return PruneStatusT(ret);
}
binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) {
@@ -255,8 +273,8 @@
return STATUS_OK;
}
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator,
- AParcel_stringGetter getter, void** stringData) {
+binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
+ AParcel_stringAllocator allocator) {
size_t len16;
const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
@@ -273,21 +291,15 @@
len8 = utf16_to_utf8_length(str16, len16) + 1;
}
- if (len8 <= 0 || len8 >= std::numeric_limits<int32_t>::max()) {
+ if (len8 <= 0 || len8 > std::numeric_limits<int32_t>::max()) {
LOG(WARNING) << __func__ << ": Invalid string length: " << len8;
return STATUS_BAD_VALUE;
}
- *stringData = reallocator(*stringData, len8);
-
- if (*stringData == nullptr) {
- return STATUS_NO_MEMORY;
- }
-
- char* str8 = getter(*stringData);
+ char* str8 = allocator(stringData, len8);
if (str8 == nullptr) {
- LOG(WARNING) << __func__ << ": AParcel_stringReallocator failed to allocate.";
+ LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate.";
return STATUS_NO_MEMORY;
}
@@ -296,6 +308,68 @@
return STATUS_OK;
}
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+ AParcel_stringArrayElementGetter getter) {
+ if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+
+ Parcel* rawParcel = parcel->get();
+
+ status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
+ if (status != STATUS_OK) return PruneStatusT(status);
+
+ for (size_t i = 0; i < length; i++) {
+ size_t length = 0;
+ const char* str = getter(arrayData, i, &length);
+ if (str == nullptr) return STATUS_BAD_VALUE;
+
+ binder_status_t status = AParcel_writeString(parcel, str, length);
+ if (status != STATUS_OK) return status;
+ }
+
+ return STATUS_OK;
+}
+
+// This implements AParcel_stringAllocator for a string using an array, index, and element
+// allocator.
+struct StringArrayElementAllocationAdapter {
+ void* arrayData; // stringData from the NDK
+ size_t index; // index into the string array
+ AParcel_stringArrayElementAllocator elementAllocator;
+
+ static char* Allocator(void* stringData, size_t length) {
+ StringArrayElementAllocationAdapter* adapter =
+ static_cast<StringArrayElementAllocationAdapter*>(stringData);
+ return adapter->elementAllocator(adapter->arrayData, adapter->index, length);
+ }
+};
+
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+ AParcel_stringArrayAllocator allocator,
+ AParcel_stringArrayElementAllocator elementAllocator) {
+ const Parcel* rawParcel = parcel->get();
+
+ int32_t length;
+ status_t status = rawParcel->readInt32(&length);
+
+ if (status != STATUS_OK) return PruneStatusT(status);
+ if (length < 0) return STATUS_UNEXPECTED_NULL;
+
+ if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+ StringArrayElementAllocationAdapter adapter{
+ .arrayData = arrayData,
+ .index = 0,
+ .elementAllocator = elementAllocator,
+ };
+
+ for (; adapter.index < length; adapter.index++) {
+ AParcel_readString(parcel, static_cast<void*>(&adapter),
+ StringArrayElementAllocationAdapter::Allocator);
+ }
+
+ return STATUS_OK;
+}
+
// See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
// libbinder and this library.
// @START
@@ -389,95 +463,89 @@
return PruneStatusT(status);
}
-binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length) {
- return WriteArray<int32_t>(parcel, value, length);
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, size_t length) {
+ return WriteArray<int32_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length) {
- return WriteArray<uint32_t>(parcel, value, length);
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData,
+ size_t length) {
+ return WriteArray<uint32_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length) {
- return WriteArray<int64_t>(parcel, value, length);
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, size_t length) {
+ return WriteArray<int64_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length) {
- return WriteArray<uint64_t>(parcel, value, length);
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData,
+ size_t length) {
+ return WriteArray<uint64_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length) {
- return WriteArray<float>(parcel, value, length);
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, size_t length) {
+ return WriteArray<float>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length) {
- return WriteArray<double>(parcel, value, length);
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, size_t length) {
+ return WriteArray<double>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData,
- AParcel_boolArrayGetter getter, size_t length) {
- return WriteArray<bool>(parcel, arrayData, getter, length, &Parcel::writeBool);
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, size_t length,
+ AParcel_boolArrayGetter getter) {
+ return WriteArray<bool>(parcel, arrayData, length, getter, &Parcel::writeBool);
}
-binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length) {
- return WriteArray<char16_t>(parcel, value, length);
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, size_t length) {
+ return WriteArray<char16_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length) {
- return WriteArray<int8_t>(parcel, value, length);
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, size_t length) {
+ return WriteArray<int8_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_int32ArrayGetter getter) {
- return ReadArray<int32_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+ AParcel_int32ArrayAllocator allocator) {
+ return ReadArray<int32_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_uint32ArrayGetter getter) {
- return ReadArray<uint32_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+ AParcel_uint32ArrayAllocator allocator) {
+ return ReadArray<uint32_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_int64ArrayGetter getter) {
- return ReadArray<int64_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+ AParcel_int64ArrayAllocator allocator) {
+ return ReadArray<int64_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_uint64ArrayGetter getter) {
- return ReadArray<uint64_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+ AParcel_uint64ArrayAllocator allocator) {
+ return ReadArray<uint64_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_floatArrayGetter getter) {
- return ReadArray<float>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+ AParcel_floatArrayAllocator allocator) {
+ return ReadArray<float>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_doubleArrayGetter getter) {
- return ReadArray<double>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+ AParcel_doubleArrayAllocator allocator) {
+ return ReadArray<double>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+ AParcel_boolArrayAllocator allocator,
AParcel_boolArraySetter setter) {
- return ReadArray<bool>(parcel, arrayData, reallocator, setter, &Parcel::readBool);
+ return ReadArray<bool>(parcel, arrayData, allocator, setter, &Parcel::readBool);
}
-binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_charArrayGetter getter) {
- return ReadArray<char16_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+ AParcel_charArrayAllocator allocator) {
+ return ReadArray<char16_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_byteArrayGetter getter) {
- return ReadArray<int8_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+ AParcel_byteArrayAllocator allocator) {
+ return ReadArray<int8_t>(parcel, arrayData, allocator);
}
// @END
diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h
index d69971f..f292309 100644
--- a/libs/binder/ndk/parcel_internal.h
+++ b/libs/binder/ndk/parcel_internal.h
@@ -29,7 +29,7 @@
AParcel(const AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
- : mBinder(binder), mParcel(parcel), mOwns(owns) {}
+ : mBinder(binder), mParcel(parcel), mOwns(owns) {}
~AParcel() {
if (mOwns) {
@@ -43,7 +43,7 @@
const AIBinder* getBinder() { return mBinder; }
-private:
+ private:
// This object is associated with a calls to a specific AIBinder object. This is used for sanity
// checking to make sure that a parcel is one that is expected.
const AIBinder* mBinder;
diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh
index 2257eb2..a0c49fb 100755
--- a/libs/binder/ndk/runtests.sh
+++ b/libs/binder/ndk/runtests.sh
@@ -22,12 +22,13 @@
set -ex
function run_libbinder_ndk_test() {
- adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
- local pid=$!
- trap "kill $pid" ERR
- adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client
- trap '' ERR
- kill $pid
+ adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
+
+ # avoid getService 1s delay for most runs, non-critical
+ sleep 0.1
+
+ adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \
+ adb shell killall libbinder_ndk_test_server
}
[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
@@ -40,4 +41,5 @@
# very simple unit tests, tests things outside of the NDK as well
run_libbinder_ndk_test
-atest android.binder.cts.NdkBinderTest
+# CTS tests (much more comprehensive, new tests should ideally go here)
+atest android.binder.cts
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 45f8d06..bb76254 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -69,6 +69,11 @@
for pretty, cpp in data_types:
header += "/**\n"
header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n"
+ header += " *\n"
+ header += " * \\param parcel the parcel to write to.\n"
+ header += " * \\param value the value to write to the parcel.\n"
+ header += " *\n"
+ header += " * \\return STATUS_OK on successful write.\n"
header += " */\n"
header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) __INTRODUCED_IN(29);\n\n"
source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n"
@@ -79,6 +84,11 @@
for pretty, cpp in data_types:
header += "/**\n"
header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n"
+ header += " *\n"
+ header += " * \\param parcel the parcel to read from.\n"
+ header += " * \\param value the value to read from the parcel.\n"
+ header += " *\n"
+ header += " * \\return STATUS_OK on successful read.\n"
header += " */\n"
header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) __INTRODUCED_IN(29);\n\n"
source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n"
@@ -89,87 +99,151 @@
for pretty, cpp in data_types:
nca = pretty in non_contiguously_addressable
- arg_type = "const " + cpp + "* value"
- if nca: arg_type = "const void* arrayData, AParcel_" + pretty.lower() + "ArrayGetter getter"
- args = "value, length"
- if nca: args = "arrayData, getter, length, &Parcel::write" + pretty
+ arg_types = "const " + cpp + "* arrayData, size_t length"
+ if nca: arg_types = "const void* arrayData, size_t length, AParcel_" + pretty.lower() + "ArrayGetter getter"
+ args = "arrayData, length"
+ if nca: args = "arrayData, length, getter, &Parcel::write" + pretty
header += "/**\n"
header += " * Writes an array of " + cpp + " to the next location in a non-null parcel.\n"
+ if nca:
+ header += " *\n"
+ header += " * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying values to write "
+ header += "to the parcel.\n"
+ header += " *\n"
+ header += " * \\param parcel the parcel to write to.\n"
+ if nca:
+ header += " * \\param arrayData some external representation of an array.\n"
+ header += " * \\param length the length of arrayData.\n"
+ header += " * \\param getter the callback to retrieve data at specific locations in the array.\n"
+ else:
+ header += " * \\param arrayData an array of size 'length'.\n"
+ header += " * \\param length the length of arrayData.\n"
+ header += " *\n"
+ header += " * \\return STATUS_OK on successful write.\n"
header += " */\n"
- header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) __INTRODUCED_IN(29);\n\n"
- source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) {\n"
+ header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") __INTRODUCED_IN(29);\n\n"
+ source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") {\n"
source += " return WriteArray<" + cpp + ">(parcel, " + args + ");\n";
source += "}\n\n"
for pretty, cpp in data_types:
nca = pretty in non_contiguously_addressable
- extra_getter_args = ""
- if nca: extra_getter_args = ", size_t index"
- getter_return = cpp + "*"
- if nca: getter_return = cpp
- getter_array_data = "void* arrayData"
- if nca: getter_array_data = "const void* arrayData"
-
+ read_func = "AParcel_read" + pretty + "Array"
+ write_func = "AParcel_write" + pretty + "Array"
+ allocator_type = "AParcel_" + pretty.lower() + "ArrayAllocator"
getter_type = "AParcel_" + pretty.lower() + "ArrayGetter"
setter_type = "AParcel_" + pretty.lower() + "ArraySetter"
- pre_header += "/**\n"
- pre_header += " * This is called to get the underlying data from an arrayData object.\n"
- pre_header += " *\n"
- pre_header += " * This will never be called for an empty array.\n"
- pre_header += " */\n"
- pre_header += "typedef " + getter_return + " (*" + getter_type + ")(" + getter_array_data + extra_getter_args + ");\n\n"
-
if nca:
pre_header += "/**\n"
+ pre_header += " * This allocates an array of size 'length' inside of arrayData and returns whether or not there was "
+ pre_header += "a success.\n"
+ pre_header += " *\n"
+ pre_header += " * See also " + read_func + "\n"
+ pre_header += " *\n"
+ pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+ pre_header += " * \\param length the length to allocate arrayData to.\n"
+ pre_header += " *\n"
+ pre_header += " * \\return whether the allocation succeeded.\n"
+ pre_header += " */\n"
+ pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
+
+ pre_header += "/**\n"
+ pre_header += " * This is called to get the underlying data from an arrayData object at index.\n"
+ pre_header += " *\n"
+ pre_header += " * See also " + write_func + "\n"
+ pre_header += " *\n"
+ pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+ pre_header += " * \\param index the index of the value to be retrieved.\n"
+ pre_header += " *\n"
+ pre_header += " * \\return the value of the array at index index.\n"
+ pre_header += " */\n"
+ pre_header += "typedef " + cpp + " (*" + getter_type + ")(const void* arrayData, size_t index);\n\n"
+
+ pre_header += "/**\n"
pre_header += " * This is called to set an underlying value in an arrayData object at index.\n"
+ pre_header += " *\n"
+ pre_header += " * See also " + read_func + "\n"
+ pre_header += " *\n"
+ pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+ pre_header += " * \\param index the index of the value to be set.\n"
+ pre_header += " * \\param value the value to set at index index.\n"
pre_header += " */\n"
pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n"
+ else:
+ pre_header += "/**\n"
+ pre_header += " * This is called to get the underlying data from an arrayData object.\n"
+ pre_header += " *\n"
+ pre_header += " * The implementation of this function should allocate a contiguous array of size 'length' and "
+ pre_header += "return that underlying buffer to be filled out. If there is an error or length is 0, null may be "
+ pre_header += "returned.\n"
+ pre_header += " *\n"
+ pre_header += " * See also " + read_func + "\n"
+ pre_header += " *\n"
+ pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+ pre_header += " * \\param length the length to allocate arrayData to.\n"
+ pre_header += " *\n"
+ pre_header += " * \\return a buffer of " + cpp + " of size 'length'.\n"
+ pre_header += " */\n"
+ pre_header += "typedef " + cpp + "* (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
- read_using = "getter"
- if nca: read_using = "setter"
- read_type = getter_type
- if nca: read_type = setter_type
+ read_array_args = [("const AParcel*", "parcel")]
+ read_array_args += [("void*", "arrayData")]
+ read_array_args += [(allocator_type, "allocator")]
+ if nca: read_array_args += [(setter_type, "setter")]
- arguments = ["const AParcel* parcel"]
- arguments += ["void** arrayData"]
- arguments += ["AParcel_arrayReallocator reallocator"]
- arguments += [read_type + " " + read_using]
- arguments = ", ".join(arguments)
+ read_type_args = ", ".join((varType + " " + name for varType, name in read_array_args))
+ read_call_args = ", ".join((name for varType, name in read_array_args))
header += "/**\n"
header += " * Reads an array of " + cpp + " from the next location in a non-null parcel.\n"
+ header += " *\n"
+ if nca:
+ header += " * First, allocator will be called with the length of the array. Then, for every i in [0, length), "
+ header += "setter(arrayData, i, x) will be called where x is the value at the associated index.\n"
+ else:
+ header += " * First, allocator will be called with the length of the array. If the allocation succeeds and the "
+ header += "length is greater than zero, the buffer returned by the allocator will be filled with the corresponding data\n"
+ header += " *\n"
+ header += " * \\param parcel the parcel to read from.\n"
+ header += " * \\param arrayData some external representation of an array.\n"
+ header += " * \\param allocator the callback that will be called to allocate the array.\n"
+ if nca:
+ header += " * \\param setter the callback that will be called to set a value at a specific location in the array.\n"
+ header += " *\n"
+ header += " * \\return STATUS_OK on successful read.\n"
header += " */\n"
- header += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") __INTRODUCED_IN(29);\n\n"
- source += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") {\n"
+ header += "binder_status_t " + read_func + "(" + read_type_args + ") __INTRODUCED_IN(29);\n\n"
+ source += "binder_status_t " + read_func + "(" + read_type_args + ") {\n"
additional_args = ""
if nca: additional_args = ", &Parcel::read" + pretty
- source += " return ReadArray<" + cpp + ">(parcel, arrayData, reallocator, " + read_using + additional_args + ");\n";
+ source += " return ReadArray<" + cpp + ">(" + read_call_args + additional_args + ");\n";
source += "}\n\n"
cpp_helper += "/**\n"
cpp_helper += " * Writes a vector of " + cpp + " to the next location in a non-null parcel.\n"
cpp_helper += " */\n"
- cpp_helper += "template<>\n"
- cpp_helper += "inline binder_status_t AParcel_writeVector<" + cpp + ">(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n"
- write_args = "vec.data()"
- if nca: write_args = "static_cast<const void*>(&vec), AParcel_stdVectorGetter<" + cpp + ">"
- cpp_helper += " return AParcel_write" + pretty + "Array(parcel, " + write_args + ", vec.size());\n"
+ cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n"
+ write_args = "vec.data(), vec.size()"
+ if nca: write_args = "static_cast<const void*>(&vec), vec.size(), AParcel_stdVectorGetter<" + cpp + ">"
+ cpp_helper += " return AParcel_write" + pretty + "Array(parcel, " + write_args + ");\n"
cpp_helper += "}\n\n"
cpp_helper += "/**\n"
cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n"
cpp_helper += " */\n"
- cpp_helper += "template<>\n"
- cpp_helper += "inline binder_status_t AParcel_readVector<" + cpp + ">(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
+ cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
cpp_helper += " void* vectorData = static_cast<void*>(vec);\n"
read_args = []
read_args += ["parcel"]
- read_args += ["&vectorData"]
- read_args += ["&AParcel_stdVectorReallocator<" + cpp + ">"]
- read_args += ["AParcel_stdVector" + read_using.capitalize() + "<" + cpp + ">"]
+ read_args += ["vectorData"]
+ if nca:
+ read_args += ["AParcel_stdVectorExternalAllocator<bool>"]
+ read_args += ["AParcel_stdVectorSetter<" + cpp + ">"]
+ else:
+ read_args += ["AParcel_stdVectorAllocator<" + cpp + ">"]
cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
cpp_helper += "}\n\n"
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
index 8c32baf..d39f0d8 100644
--- a/libs/binder/ndk/status_internal.h
+++ b/libs/binder/ndk/status_internal.h
@@ -22,13 +22,13 @@
#include <utils/Errors.h>
struct AStatus {
- AStatus() {} // ok
+ AStatus() {} // ok
AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
::android::binder::Status* get() { return &mStatus; }
const ::android::binder::Status* get() const { return &mStatus; }
-private:
+ private:
::android::binder::Status mStatus;
};
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8e40a01..b29b6e7 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -14,9 +14,6 @@
* limitations under the License.
*/
-// This test is a unit test of the low-level API that is presented here.
-// Actual users should use AIDL to generate these complicated stubs.
-
cc_defaults {
name: "test_libbinder_ndk_defaults",
shared_libs: [
@@ -55,6 +52,9 @@
],
}
+// This test is a unit test of the low-level API that is presented here,
+// specifically the parts which are outside of the NDK. Actual users should
+// also instead use AIDL to generate these stubs. See android.binder.cts.
cc_test {
name: "libbinder_ndk_test_client",
defaults: ["test_libbinder_ndk_test_defaults"],
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
index 0dc3cc4..6ef964e 100644
--- a/libs/binder/ndk/test/iface.cpp
+++ b/libs/binder/ndk/test/iface.cpp
@@ -18,10 +18,13 @@
#include <android/binder_manager.h>
#include <iface/iface.h>
+#include <android/binder_auto_utils.h>
+
using ::android::sp;
using ::android::wp;
const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
+const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
const char* kIFooDescriptor = "my-special-IFoo-class";
struct IFoo_Class_Data {
@@ -49,12 +52,18 @@
switch (code) {
case IFoo::DOFOO: {
int32_t valueIn;
+ int32_t valueOut;
stat = AParcel_readInt32(in, &valueIn);
if (stat != STATUS_OK) break;
- int32_t valueOut = foo->doubleNumber(valueIn);
+ stat = foo->doubleNumber(valueIn, &valueOut);
+ if (stat != STATUS_OK) break;
stat = AParcel_writeInt32(out, valueOut);
break;
}
+ case IFoo::DIE: {
+ stat = foo->die();
+ break;
+ }
}
return stat;
@@ -64,29 +73,43 @@
IFoo_Class_onDestroy, IFoo_Class_onTransact);
class BpFoo : public IFoo {
-public:
+ public:
BpFoo(AIBinder* binder) : mBinder(binder) {}
virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
- virtual int32_t doubleNumber(int32_t in) {
+ virtual binder_status_t doubleNumber(int32_t in, int32_t* out) {
+ binder_status_t stat = STATUS_OK;
+
AParcel* parcelIn;
- CHECK(STATUS_OK == AIBinder_prepareTransaction(mBinder, &parcelIn));
+ stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+ if (stat != STATUS_OK) return stat;
- CHECK(STATUS_OK == AParcel_writeInt32(parcelIn, in));
+ stat = AParcel_writeInt32(parcelIn, in);
+ if (stat != STATUS_OK) return stat;
- AParcel* parcelOut;
- CHECK(STATUS_OK ==
- AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/));
+ ::ndk::ScopedAParcel parcelOut;
+ stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+ if (stat != STATUS_OK) return stat;
- int32_t out;
- CHECK(STATUS_OK == AParcel_readInt32(parcelOut, &out));
+ stat = AParcel_readInt32(parcelOut.get(), out);
+ if (stat != STATUS_OK) return stat;
- AParcel_delete(parcelOut);
-
- return out;
+ return stat;
}
-private:
+ virtual binder_status_t die() {
+ binder_status_t stat = STATUS_OK;
+
+ AParcel* parcelIn;
+ stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+
+ ::ndk::ScopedAParcel parcelOut;
+ stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+
+ return stat;
+ }
+
+ private:
// Always assumes one refcount
AIBinder* mBinder;
};
@@ -117,8 +140,8 @@
return status;
}
-sp<IFoo> IFoo::getService(const char* instance) {
- AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
+sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) {
+ AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
if (binder == nullptr) {
return nullptr;
}
@@ -128,14 +151,19 @@
return nullptr;
}
+ if (outBinder != nullptr) {
+ AIBinder_incStrong(binder);
+ *outBinder = binder;
+ }
+
if (AIBinder_isRemote(binder)) {
- sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
+ sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
return ret;
}
IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder));
- CHECK(data != nullptr); // always created with non-null data
+ CHECK(data != nullptr); // always created with non-null data
sp<IFoo> ret = data->foo;
@@ -143,7 +171,6 @@
CHECK(held == binder);
AIBinder_decStrong(held);
- // IFoo only keeps a weak reference to AIBinder, so we can drop this
AIBinder_decStrong(binder);
return ret;
}
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h
index 4c61e9d..cdf5493 100644
--- a/libs/binder/ndk/test/include/iface/iface.h
+++ b/libs/binder/ndk/test/include/iface/iface.h
@@ -19,22 +19,33 @@
#include <android/binder_ibinder.h>
#include <utils/RefBase.h>
+// warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of
+// the other niceties make sure that, for instance, binder proxies are always the same. They also
+// don't use internal Android APIs like refbase which are used here only for convenience.
+
class IFoo : public virtual ::android::RefBase {
-public:
+ public:
static const char* kSomeInstanceName;
+ static const char* kInstanceNameToDieFor;
+
static AIBinder_Class* kClass;
// Takes ownership of IFoo
binder_status_t addService(const char* instance);
- static ::android::sp<IFoo> getService(const char* instance);
+ static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr);
enum Call {
DOFOO = FIRST_CALL_TRANSACTION + 0,
+ DIE = FIRST_CALL_TRANSACTION + 1,
};
virtual ~IFoo();
- virtual int32_t doubleNumber(int32_t in) = 0;
-private:
- AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder
+ virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0;
+ virtual binder_status_t die() = 0;
+
+ private:
+ // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not
+ // for BpFoo.
+ AIBinder_Weak* mWeakBinder = nullptr;
};
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 6945cac..c159d71 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -21,6 +21,10 @@
#include <gtest/gtest.h>
#include <iface/iface.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
using ::android::sp;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
@@ -34,7 +38,47 @@
TEST(NdkBinder, DoubleNumber) {
sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
ASSERT_NE(foo, nullptr);
- EXPECT_EQ(2, foo->doubleNumber(1));
+
+ int32_t out;
+ EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out));
+ EXPECT_EQ(2, out);
+}
+
+void LambdaOnDeath(void* cookie) {
+ auto onDeath = static_cast<std::function<void(void)>*>(cookie);
+ (*onDeath)();
+};
+TEST(NdkBinder, DeathRecipient) {
+ using namespace std::chrono_literals;
+
+ AIBinder* binder;
+ sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder);
+ ASSERT_NE(nullptr, foo.get());
+ ASSERT_NE(nullptr, binder);
+
+ std::mutex deathMutex;
+ std::condition_variable deathCv;
+ bool deathRecieved = false;
+
+ std::function<void(void)> onDeath = [&] {
+ std::cerr << "Binder died (as requested)." << std::endl;
+ deathRecieved = true;
+ deathCv.notify_one();
+ };
+
+ AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+
+ EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
+
+ // the binder driver should return this if the service dies during the transaction
+ EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+
+ std::unique_lock<std::mutex> lock(deathMutex);
+ EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
+ EXPECT_TRUE(deathRecieved);
+
+ AIBinder_DeathRecipient_delete(recipient);
+ AIBinder_decStrong(binder);
}
TEST(NdkBinder, RetrieveNonNdkService) {
@@ -52,9 +96,6 @@
}
TEST(NdkBinder, LinkToDeath) {
- ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications
- ABinderProcess_startThreadPool();
-
AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
ASSERT_NE(nullptr, binder);
@@ -72,9 +113,14 @@
}
class MyTestFoo : public IFoo {
- int32_t doubleNumber(int32_t in) override {
- LOG(INFO) << "doubleNumber " << in;
- return 2 * in;
+ binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+ *out = 2 * in;
+ LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+ return STATUS_OK;
+ }
+ binder_status_t die() override {
+ ADD_FAILURE() << "die called on local instance";
+ return STATUS_OK;
}
};
@@ -87,7 +133,9 @@
sp<IFoo> getFoo = IFoo::getService(kInstanceName);
EXPECT_EQ(foo.get(), getFoo.get());
- EXPECT_EQ(2, getFoo->doubleNumber(1));
+ int32_t out;
+ EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out));
+ EXPECT_EQ(2, out);
}
TEST(NdkBinder, EqualityOfRemoteBinderPointer) {
@@ -132,6 +180,15 @@
EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
}
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks
+ ABinderProcess_startThreadPool();
+
+ return RUN_ALL_TESTS();
+}
+
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
#include <android/binder_parcel_utils.h>
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
index 0718a69..a6e17e8 100644
--- a/libs/binder/ndk/test/main_server.cpp
+++ b/libs/binder/ndk/test/main_server.cpp
@@ -21,23 +21,37 @@
using ::android::sp;
class MyFoo : public IFoo {
- int32_t doubleNumber(int32_t in) override {
- LOG(INFO) << "doubling " << in;
- return 2 * in;
+ binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+ *out = 2 * in;
+ LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+ return STATUS_OK;
+ }
+
+ binder_status_t die() override {
+ LOG(FATAL) << "IFoo::die called!";
+ return STATUS_UNKNOWN_ERROR;
}
};
-int main() {
+int service(const char* instance) {
ABinderProcess_setThreadPoolMaxThreadCount(0);
// Strong reference to MyFoo kept by service manager.
- binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName);
+ binder_status_t status = (new MyFoo)->addService(instance);
if (status != STATUS_OK) {
- LOG(FATAL) << "Could not register: " << status;
+ LOG(FATAL) << "Could not register: " << status << " " << instance;
}
ABinderProcess_joinThreadPool();
- return 1;
+ return 1; // should not return
+}
+
+int main() {
+ if (fork() == 0) {
+ return service(IFoo::kInstanceNameToDieFor);
+ }
+
+ return service(IFoo::kSomeInstanceName);
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 024d72b..afa32b6 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -68,8 +68,7 @@
}
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
- const std::string appPref, bool developerOptIn,
- const int rulesFd, const long rulesOffset,
+ bool developerOptIn, const int rulesFd, const long rulesOffset,
const long rulesLength) {
if (!mAnglePath.empty()) {
ALOGV("ignoring attempt to change ANGLE path from '%s' to '%s'", mAnglePath.c_str(),
@@ -87,14 +86,6 @@
mAngleAppName = appName;
}
- if (!mAngleAppPref.empty()) {
- ALOGV("ignoring attempt to change ANGLE application opt-in from '%s' to '%s'",
- mAngleAppPref.c_str(), appPref.c_str());
- } else {
- ALOGV("setting ANGLE application opt-in to '%s'", appPref.c_str());
- mAngleAppPref = appPref;
- }
-
mAngleDeveloperOptIn = developerOptIn;
ALOGV("setting ANGLE rules file descriptor to '%i'", rulesFd);
@@ -128,11 +119,6 @@
return mAngleDeveloperOptIn;
}
-const char* GraphicsEnv::getAngleAppPref() {
- if (mAngleAppPref.empty()) return nullptr;
- return mAngleAppPref.c_str();
-}
-
int GraphicsEnv::getAngleRulesFd() {
return mAngleRulesFd;
}
@@ -145,18 +131,26 @@
return mAngleRulesLength;
}
-const std::string GraphicsEnv::getLayerPaths(){
+const std::string& GraphicsEnv::getLayerPaths() {
return mLayerPaths;
}
-const std::string GraphicsEnv::getDebugLayers() {
+const std::string& GraphicsEnv::getDebugLayers() {
return mDebugLayers;
}
+const std::string& GraphicsEnv::getDebugLayersGLES() {
+ return mDebugLayersGLES;
+}
+
void GraphicsEnv::setDebugLayers(const std::string layers) {
mDebugLayers = layers;
}
+void GraphicsEnv::setDebugLayersGLES(const std::string layers) {
+ mDebugLayersGLES = layers;
+}
+
android_namespace_t* GraphicsEnv::getDriverNamespace() {
static std::once_flag once;
std::call_once(once, [this]() {
@@ -196,36 +190,3 @@
}
} // namespace android
-
-extern "C" {
-android_namespace_t* android_getDriverNamespace() {
- return android::GraphicsEnv::getInstance().getDriverNamespace();
-}
-android_namespace_t* android_getAngleNamespace() {
- return android::GraphicsEnv::getInstance().getAngleNamespace();
-}
-const char* android_getAngleAppName() {
- return android::GraphicsEnv::getInstance().getAngleAppName();
-}
-bool android_getAngleDeveloperOptIn() {
- return android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
-}
-const char* android_getAngleAppPref() {
- return android::GraphicsEnv::getInstance().getAngleAppPref();
-}
-int android_getAngleRulesFd() {
- return android::GraphicsEnv::getInstance().getAngleRulesFd();
-}
-long android_getAngleRulesOffset() {
- return android::GraphicsEnv::getInstance().getAngleRulesOffset();
-}
-long android_getAngleRulesLength() {
- return android::GraphicsEnv::getInstance().getAngleRulesLength();
-}
-const char* android_getLayerPaths() {
- return android::GraphicsEnv::getInstance().getLayerPaths().c_str();
-}
-const char* android_getDebugLayers() {
- return android::GraphicsEnv::getInstance().getDebugLayers().c_str();
-}
-}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 404823a..20e4d66 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -44,9 +44,8 @@
// (libraries must be stored uncompressed and page aligned); such elements
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
- void setAngleInfo(const std::string path, const std::string appName, const std::string appPref,
- bool devOptIn, const int rulesFd, const long rulesOffset,
- const long rulesLength);
+ void setAngleInfo(const std::string path, const std::string appName, bool devOptIn,
+ const int rulesFd, const long rulesOffset, const long rulesLength);
android_namespace_t* getAngleNamespace();
const char* getAngleAppName();
const char* getAngleAppPref();
@@ -58,22 +57,24 @@
void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
NativeLoaderNamespace* getAppNamespace();
- const std::string getLayerPaths();
+ const std::string& getLayerPaths();
void setDebugLayers(const std::string layers);
- const std::string getDebugLayers();
+ void setDebugLayersGLES(const std::string layers);
+ const std::string& getDebugLayers();
+ const std::string& getDebugLayersGLES();
private:
GraphicsEnv() = default;
std::string mDriverPath;
std::string mAnglePath;
std::string mAngleAppName;
- std::string mAngleAppPref;
bool mAngleDeveloperOptIn;
int mAngleRulesFd;
long mAngleRulesOffset;
long mAngleRulesLength;
std::string mDebugLayers;
+ std::string mDebugLayersGLES;
std::string mLayerPaths;
android_namespace_t* mDriverNamespace = nullptr;
android_namespace_t* mAngleNamespace = nullptr;
@@ -82,28 +83,4 @@
} // namespace android
-/* FIXME
- * Export an un-mangled function that just does
- * return android::GraphicsEnv::getInstance().getDriverNamespace();
- * This allows libEGL to get the function pointer via dlsym, since it can't
- * directly link against libgui. In a future release, we'll fix this so that
- * libgui does not depend on graphics API libraries, and libEGL can link
- * against it. The current dependencies from libgui -> libEGL are:
- * - the GLConsumer class, which should be moved to its own library
- * - the EGLsyncKHR synchronization in BufferQueue, which is deprecated and
- * will be removed soon.
- */
-extern "C" {
- android_namespace_t* android_getDriverNamespace();
- android_namespace_t* android_getAngleNamespace();
- const char* android_getAngleAppName();
- const char* android_getAngleAppPref();
- bool android_getAngleDeveloperOptIn();
- int android_getAngleRulesFd();
- long android_getAngleRulesOffset();
- long android_getAngleRulesLength();
- const char* android_getLayerPaths();
- const char* android_getDebugLayers();
-}
-
#endif // ANDROID_UI_GRAPHICS_ENV_H
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 98264ac..7677c3a 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -107,6 +107,7 @@
"IProducerListener.cpp",
"ISurfaceComposer.cpp",
"ISurfaceComposerClient.cpp",
+ "ITransactionCompletedListener.cpp",
"LayerDebugInfo.cpp",
"LayerState.cpp",
"OccupancyTracker.cpp",
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 1a7c2d3..ed773e0 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -20,7 +20,6 @@
#include <log/log.h>
#include <system/window.h>
#include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
namespace android {
@@ -276,14 +275,10 @@
status_or_handle.error());
return BAD_VALUE;
}
- std::unique_ptr<DetachedBufferHandle> handle =
- DetachedBufferHandle::Create(status_or_handle.take());
- if (!handle->isValid()) {
- ALOGE("detachBuffer: Failed to create a DetachedBufferHandle at slot %zu.", slot);
- return BAD_VALUE;
- }
- return graphic_buffer->setDetachedBufferHandle(std::move(handle));
+ // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+ // be directly backed by BufferHub.
+ return INVALID_OPERATION;
}
status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
@@ -373,7 +368,7 @@
ALOGE("attachBuffer: out_slot cannot be NULL.");
return BAD_VALUE;
}
- if (buffer == nullptr || !buffer->isDetachedBuffer()) {
+ if (buffer == nullptr) {
ALOGE("attachBuffer: invalid GraphicBuffer.");
return BAD_VALUE;
}
@@ -394,45 +389,9 @@
return BAD_VALUE;
}
- // Creates a BufferProducer from the GraphicBuffer.
- std::unique_ptr<DetachedBufferHandle> detached_handle = buffer->takeDetachedBufferHandle();
- if (detached_handle == nullptr) {
- ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
- return BAD_VALUE;
- }
- std::shared_ptr<BufferProducer> buffer_producer =
- BufferProducer::Import(std::move(detached_handle->handle()));
- if (buffer_producer == nullptr) {
- ALOGE("attachBuffer: Failed to import BufferProducer.");
- return BAD_VALUE;
- }
-
- // Adds the BufferProducer into the Queue.
- auto status_or_slot = queue_->InsertBuffer(buffer_producer);
- if (!status_or_slot.ok()) {
- ALOGE("attachBuffer: Failed to insert buffer, error=%d.", status_or_slot.error());
- return BAD_VALUE;
- }
-
- size_t slot = status_or_slot.get();
- ALOGV("attachBuffer: returning slot %zu.", slot);
- if (slot >= static_cast<size_t>(max_buffer_count_)) {
- ALOGE("attachBuffer: Invalid slot: %zu.", slot);
- return BAD_VALUE;
- }
-
- // The just attached buffer should be in dequeued state according to IGraphicBufferProducer
- // interface. In BufferHub's language the buffer should be in Gained state.
- buffers_[slot].mGraphicBuffer = buffer;
- buffers_[slot].mBufferState.attachProducer();
- buffers_[slot].mEglFence = EGL_NO_SYNC_KHR;
- buffers_[slot].mFence = Fence::NO_FENCE;
- buffers_[slot].mRequestBufferCalled = true;
- buffers_[slot].mAcquireCalled = false;
- buffers_[slot].mNeedsReallocation = false;
-
- *out_slot = static_cast<int>(slot);
- return NO_ERROR;
+ // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+ // be directly backed by BufferHub.
+ return INVALID_OPERATION;
}
status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index f99bc53..69e5379 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -103,11 +103,15 @@
}
virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+ const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ ISurfaceComposer::Rotation rotation) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
+ data.writeInt32(static_cast<int32_t>(reqDataspace));
+ data.writeInt32(static_cast<int32_t>(reqPixelFormat));
data.write(sourceCrop);
data.writeUint32(reqWidth);
data.writeUint32(reqHeight);
@@ -126,15 +130,19 @@
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
+
return result;
}
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
- sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
float frameScale, bool childrenOnly) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(layerHandleBinder);
+ data.writeInt32(static_cast<int32_t>(reqDataspace));
+ data.writeInt32(static_cast<int32_t>(reqPixelFormat));
data.write(sourceCrop);
data.writeFloat(frameScale);
data.writeBool(childrenOnly);
@@ -148,6 +156,7 @@
ALOGE("captureLayers failed to readInt32: %d", result);
return result;
}
+
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
@@ -556,8 +565,10 @@
return reply.readParcelableVector(outLayers);
}
- virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat) const {
+ virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+ ui::PixelFormat* defaultPixelFormat,
+ ui::Dataspace* wideColorGamutDataspace,
+ ui::PixelFormat* wideColorGamutPixelFormat) const {
Parcel data, reply;
status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (error != NO_ERROR) {
@@ -569,11 +580,25 @@
}
error = static_cast<status_t>(reply.readInt32());
if (error == NO_ERROR) {
- *dataSpace = static_cast<ui::Dataspace>(reply.readInt32());
- *pixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+ *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+ *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+ *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+ *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
}
return error;
}
+
+ virtual status_t getColorManagement(bool* outGetColorManagement) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply);
+ bool result;
+ status_t err = reply.readBool(&result);
+ if (err == NO_ERROR) {
+ *outGetColorManagement = result;
+ }
+ return err;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -609,10 +634,10 @@
if (count > data.dataSize()) {
return BAD_VALUE;
}
- ComposerState s;
Vector<ComposerState> state;
state.setCapacity(count);
for (size_t i = 0; i < count; i++) {
+ ComposerState s;
if (s.read(data) == BAD_VALUE) {
return BAD_VALUE;
}
@@ -645,6 +670,8 @@
case CAPTURE_SCREEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = data.readStrongBinder();
+ ui::Dataspace reqDataspace = static_cast<ui::Dataspace>(data.readInt32());
+ ui::PixelFormat reqPixelFormat = static_cast<ui::PixelFormat>(data.readInt32());
sp<GraphicBuffer> outBuffer;
Rect sourceCrop(Rect::EMPTY_RECT);
data.read(sourceCrop);
@@ -653,8 +680,8 @@
bool useIdentityTransform = static_cast<bool>(data.readInt32());
int32_t rotation = data.readInt32();
- status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight,
- useIdentityTransform,
+ status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat,
+ sourceCrop, reqWidth, reqHeight, useIdentityTransform,
static_cast<ISurfaceComposer::Rotation>(rotation));
reply->writeInt32(res);
if (res == NO_ERROR) {
@@ -665,14 +692,16 @@
case CAPTURE_LAYERS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> layerHandleBinder = data.readStrongBinder();
+ ui::Dataspace reqDataspace = static_cast<ui::Dataspace>(data.readInt32());
+ ui::PixelFormat reqPixelFormat = static_cast<ui::PixelFormat>(data.readInt32());
sp<GraphicBuffer> outBuffer;
Rect sourceCrop(Rect::EMPTY_RECT);
data.read(sourceCrop);
float frameScale = data.readFloat();
bool childrenOnly = data.readBool();
- status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale,
- childrenOnly);
+ status_t res = captureLayers(layerHandleBinder, &outBuffer, reqDataspace,
+ reqPixelFormat, sourceCrop, frameScale, childrenOnly);
reply->writeInt32(res);
if (res == NO_ERROR) {
reply->write(*outBuffer);
@@ -897,16 +926,31 @@
}
case GET_COMPOSITION_PREFERENCE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- ui::Dataspace dataSpace;
- ui::PixelFormat pixelFormat;
- status_t error = getCompositionPreference(&dataSpace, &pixelFormat);
+ ui::Dataspace defaultDataspace;
+ ui::PixelFormat defaultPixelFormat;
+ ui::Dataspace wideColorGamutDataspace;
+ ui::PixelFormat wideColorGamutPixelFormat;
+ status_t error =
+ getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
+ &wideColorGamutDataspace, &wideColorGamutPixelFormat);
reply->writeInt32(error);
if (error == NO_ERROR) {
- reply->writeInt32(static_cast<int32_t>(dataSpace));
- reply->writeInt32(static_cast<int32_t>(pixelFormat));
+ reply->writeInt32(static_cast<int32_t>(defaultDataspace));
+ reply->writeInt32(static_cast<int32_t>(defaultPixelFormat));
+ reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
+ reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
}
return NO_ERROR;
}
+ case GET_COLOR_MANAGEMENT: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ bool result;
+ status_t error = getColorManagement(&result);
+ if (error == NO_ERROR) {
+ reply->writeBool(result);
+ }
+ return result;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
new file mode 100644
index 0000000..95b1038
--- /dev/null
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ITransactionCompletedListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/ITransactionCompletedListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+ ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
+ LAST = ON_TRANSACTION_COMPLETED,
+};
+
+} // Anonymous namespace
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeStrongBinder(surfaceControl);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64(acquireTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return output->writeBool(releasePreviousBuffer);
+}
+
+status_t SurfaceStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readStrongBinder(&surfaceControl);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64(&acquireTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return input->readBool(&releasePreviousBuffer);
+}
+
+status_t TransactionStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeInt64(latchTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64(presentTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return output->writeParcelableVector(surfaceStats);
+}
+
+status_t TransactionStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readInt64(&latchTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64(&presentTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return input->readParcelableVector(&surfaceStats);
+}
+
+status_t ListenerStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeInt32(static_cast<int32_t>(transactionStats.size()));
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ for (const auto& [callbackIds, stats] : transactionStats) {
+ err = output->writeParcelable(stats);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64Vector(callbackIds);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t ListenerStats::readFromParcel(const Parcel* input) {
+ int32_t transactionStats_size = input->readInt32();
+
+ for (int i = 0; i < transactionStats_size; i++) {
+ TransactionStats stats;
+ std::vector<CallbackId> callbackIds;
+
+ status_t err = input->readParcelable(&stats);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64Vector(&callbackIds);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transactionStats.emplace(callbackIds, stats);
+ }
+ return NO_ERROR;
+}
+
+ListenerStats ListenerStats::createEmpty(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbackIds) {
+ ListenerStats listenerStats;
+ listenerStats.listener = listener;
+ TransactionStats transactionStats;
+ listenerStats.transactionStats.emplace(std::piecewise_construct,
+ std::forward_as_tuple(callbackIds.begin(),
+ callbackIds.end()),
+ std::forward_as_tuple(transactionStats));
+ return listenerStats;
+}
+
+class BpTransactionCompletedListener : public SafeBpInterface<ITransactionCompletedListener> {
+public:
+ explicit BpTransactionCompletedListener(const sp<IBinder>& impl)
+ : SafeBpInterface<ITransactionCompletedListener>(impl, "BpTransactionCompletedListener") {
+ }
+
+ ~BpTransactionCompletedListener() override;
+
+ void onTransactionCompleted(ListenerStats stats) override {
+ callRemoteAsync<decltype(&ITransactionCompletedListener::
+ onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED,
+ stats);
+ }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpTransactionCompletedListener::~BpTransactionCompletedListener() = default;
+
+IMPLEMENT_META_INTERFACE(TransactionCompletedListener, "android.gui.ITransactionComposerListener");
+
+status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::ON_TRANSACTION_COMPLETED:
+ return callLocalAsync(data, reply,
+ &ITransactionCompletedListener::onTransactionCompleted);
+ }
+}
+
+}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 2b0a461..7b71b39 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -80,6 +80,13 @@
memcpy(output.writeInplace(16 * sizeof(float)),
colorTransform.asArray(), 16 * sizeof(float));
+ if (output.writeVectorSize(listenerCallbacks) == NO_ERROR) {
+ for (const auto& [listener, callbackIds] : listenerCallbacks) {
+ output.writeStrongBinder(IInterface::asBinder(listener));
+ output.writeInt64Vector(callbackIds);
+ }
+ }
+
return NO_ERROR;
}
@@ -135,6 +142,14 @@
colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
+ int32_t listenersSize = input.readInt32();
+ for (int32_t i = 0; i < listenersSize; i++) {
+ auto listener = interface_cast<ITransactionCompletedListener>(input.readStrongBinder());
+ std::vector<CallbackId> callbackIds;
+ input.readInt64Vector(&callbackIds);
+ listenerCallbacks.emplace_back(listener, callbackIds);
+ }
+
return NO_ERROR;
}
@@ -323,6 +338,10 @@
what |= eColorTransformChanged;
colorTransform = other.colorTransform;
}
+ if (other.what & eListenerCallbacksChanged) {
+ what |= eListenerCallbacksChanged;
+ listenerCallbacks = other.listenerCallbacks;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1ac9609..e10bda4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -25,7 +25,9 @@
#include <utils/String8.h>
#include <utils/threads.h>
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <system/graphics.h>
@@ -98,6 +100,61 @@
// ---------------------------------------------------------------------------
+// TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
+// to be able to return a sp<> to its instance to pass to SurfaceFlinger.
+// ANDROID_SINGLETON_STATIC_INSTANCE only allows a reference to an instance.
+
+// 0 is an invalid callback id
+TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {}
+
+CallbackId TransactionCompletedListener::getNextIdLocked() {
+ return mCallbackIdCounter++;
+}
+
+sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
+ static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener;
+ return sInstance;
+}
+
+sp<ITransactionCompletedListener> TransactionCompletedListener::getIInstance() {
+ return static_cast<sp<ITransactionCompletedListener>>(getInstance());
+}
+
+void TransactionCompletedListener::startListeningLocked() {
+ if (mListening) {
+ return;
+ }
+ ProcessState::self()->startThreadPool();
+ mListening = true;
+}
+
+CallbackId TransactionCompletedListener::addCallback(const TransactionCompletedCallback& callback) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ startListeningLocked();
+
+ CallbackId callbackId = getNextIdLocked();
+ mCallbacks.emplace(callbackId, callback);
+ return callbackId;
+}
+
+void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
+ std::lock_guard lock(mMutex);
+
+ for (const auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+ for (auto callbackId : callbackIds) {
+ const auto& callback = mCallbacks[callbackId];
+ if (!callback) {
+ ALOGE("cannot call null callback function, skipping");
+ continue;
+ }
+ callback(transactionStats);
+ mCallbacks.erase(callbackId);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
@@ -127,6 +184,17 @@
}
other.mDisplayStates.clear();
+ for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) {
+ auto& [callbackIds, surfaceControls] = callbackInfo;
+ mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
+ callbackIds.begin()),
+ std::make_move_iterator(callbackIds.end()));
+ mListenerCallbacks[listener]
+ .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
+ std::make_move_iterator(surfaceControls.end()));
+ }
+ other.mListenerCallbacks.clear();
+
return *this;
}
@@ -137,6 +205,32 @@
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ // For every listener with registered callbacks
+ for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
+ auto& [callbackIds, surfaceControls] = callbackInfo;
+ if (callbackIds.empty()) {
+ continue;
+ }
+
+ // If the listener does not have any SurfaceControls set on this Transaction, send the
+ // callback now
+ if (surfaceControls.empty()) {
+ listener->onTransactionCompleted(ListenerStats::createEmpty(listener, callbackIds));
+ }
+
+ // If the listener has any SurfaceControls set on this Transaction update the surface state
+ for (const auto& surfaceControl : surfaceControls) {
+ layer_state_t* s = getLayerState(surfaceControl);
+ if (!s) {
+ ALOGE("failed to get layer state");
+ continue;
+ }
+ s->what |= layer_state_t::eListenerCallbacksChanged;
+ s->listenerCallbacks.emplace_back(listener, std::move(callbackIds));
+ }
+ }
+ mListenerCallbacks.clear();
+
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
uint32_t flags = 0;
@@ -206,6 +300,11 @@
return &(mComposerStates[sc].state);
}
+void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
+ const sp<SurfaceControl>& sc) {
+ mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls.insert(sc);
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
const sp<SurfaceControl>& sc, float x, float y) {
layer_state_t* s = getLayerState(sc);
@@ -216,6 +315,8 @@
s->what |= layer_state_t::ePositionChanged;
s->x = x;
s->y = y;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -240,6 +341,7 @@
s->w = w;
s->h = h;
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -252,6 +354,8 @@
}
s->what |= layer_state_t::eLayerChanged;
s->z = z;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -264,6 +368,8 @@
s->what |= layer_state_t::eRelativeLayerChanged;
s->relativeLayerHandle = relativeTo;
s->z = z;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -283,6 +389,8 @@
s->flags &= ~mask;
s->flags |= (flags & mask);
s->mask |= mask;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -296,6 +404,8 @@
}
s->what |= layer_state_t::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -308,6 +418,8 @@
}
s->what |= layer_state_t::eAlphaChanged;
s->alpha = alpha;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -320,6 +432,8 @@
}
s->what |= layer_state_t::eLayerStackChanged;
s->layerStack = layerStack;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -338,6 +452,8 @@
matrix.dsdy = dsdy;
matrix.dtdy = dtdy;
s->matrix = matrix;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -350,6 +466,8 @@
}
s->what |= layer_state_t::eCropChanged_legacy;
s->crop_legacy = crop;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -365,6 +483,8 @@
s->what |= layer_state_t::eDeferTransaction_legacy;
s->barrierHandle_legacy = handle;
s->frameNumber_legacy = frameNumber;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -380,6 +500,8 @@
s->what |= layer_state_t::eDeferTransaction_legacy;
s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer();
s->frameNumber_legacy = frameNumber;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -393,6 +515,8 @@
}
s->what |= layer_state_t::eReparentChildren;
s->reparentHandle = newParentHandle;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -406,6 +530,8 @@
}
s->what |= layer_state_t::eReparent;
s->parentHandleForChild = newParentHandle;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -419,6 +545,8 @@
}
s->what |= layer_state_t::eColorChanged;
s->color = color;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -431,6 +559,8 @@
}
s->what |= layer_state_t::eTransformChanged;
s->transform = transform;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -444,6 +574,8 @@
}
s->what |= layer_state_t::eTransformToDisplayInverseChanged;
s->transformToDisplayInverse = transformToDisplayInverse;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -456,6 +588,8 @@
}
s->what |= layer_state_t::eCropChanged;
s->crop = crop;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -468,6 +602,8 @@
}
s->what |= layer_state_t::eBufferChanged;
s->buffer = buffer;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -480,6 +616,8 @@
}
s->what |= layer_state_t::eAcquireFenceChanged;
s->acquireFence = fence;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -492,6 +630,8 @@
}
s->what |= layer_state_t::eDataspaceChanged;
s->dataspace = dataspace;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -504,6 +644,8 @@
}
s->what |= layer_state_t::eHdrMetadataChanged;
s->hdrMetadata = hdrMetadata;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -516,6 +658,8 @@
}
s->what |= layer_state_t::eSurfaceDamageRegionChanged;
s->surfaceDamageRegion = surfaceDamageRegion;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -528,6 +672,8 @@
}
s->what |= layer_state_t::eApiChanged;
s->api = api;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -540,6 +686,22 @@
}
s->what |= layer_state_t::eSidebandStreamChanged;
s->sidebandStream = sidebandStream;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+ auto listener = TransactionCompletedListener::getInstance();
+
+ auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1);
+
+ CallbackId callbackId = listener->addCallback(callbackWithContext);
+
+ mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
+ callbackId);
return *this;
}
@@ -550,6 +712,8 @@
mStatus = BAD_INDEX;
}
s->what |= layer_state_t::eDetachChildren;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -577,6 +741,8 @@
s->what |= layer_state_t::eOverrideScalingModeChanged;
s->overrideScalingMode = overrideScalingMode;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -588,6 +754,8 @@
return *this;
}
s->what |= layer_state_t::eGeometryAppliesWithResize;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -611,6 +779,8 @@
}
s->what |= layer_state_t::eColorTransformChanged;
s->colorTransform = mat4(matrix, translation);
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -866,9 +1036,12 @@
ComposerService::getComposerService()->setPowerMode(token, mode);
}
-status_t SurfaceComposerClient::getCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat) {
- return ComposerService::getComposerService()->getCompositionPreference(dataSpace, pixelFormat);
+status_t SurfaceComposerClient::getCompositionPreference(
+ ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat,
+ ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) {
+ return ComposerService::getComposerService()
+ ->getCompositionPreference(defaultDataspace, defaultPixelFormat,
+ wideColorGamutDataspace, wideColorGamutPixelFormat);
}
status_t SurfaceComposerClient::clearAnimationFrameStats() {
@@ -887,13 +1060,14 @@
// ----------------------------------------------------------------------------
-status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
- uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation,
- sp<GraphicBuffer>* outBuffer) {
+status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight,
- useIdentityTransform,
+ status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
+ reqWidth, reqHeight, useIdentityTransform,
static_cast<ISurfaceComposer::Rotation>(rotation));
if (ret != NO_ERROR) {
return ret;
@@ -901,21 +1075,25 @@
return ret;
}
-status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
+ const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
- false /* childrenOnly */);
+ status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
+ sourceCrop, frameScale, false /* childrenOnly */);
return ret;
}
-status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle,
+ const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
- true /* childrenOnly */);
+ status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
+ sourceCrop, frameScale, true /* childrenOnly */);
return ret;
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a55cfe0..761f31a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -180,6 +180,36 @@
* The subregion can be optionally rotated. It will also be scaled to
* match the size of the output buffer.
*
+ * reqDataspace and reqPixelFormat specify the data space and pixel format
+ * of the buffer. The caller should pick the data space and pixel format
+ * that it can consume.
+ *
+ * At the moment, sourceCrop is ignored and is always set to the visible
+ * region (projected display viewport) of the screen.
+ *
+ * reqWidth and reqHeight specifies the size of the buffer. When either
+ * of them is 0, they are set to the size of the logical display viewport.
+ *
+ * When useIdentityTransform is true, layer transformations are disabled.
+ *
+ * rotation specifies the rotation of the source crop (and the pixels in
+ * it) around its center.
+ */
+ virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+ const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ Rotation rotation = eRotateNone) = 0;
+ /**
+ * Capture the specified screen. This requires READ_FRAME_BUFFER
+ * permission. This function will fail if there is a secure window on
+ * screen.
+ *
+ * This function can capture a subregion (the source crop) of the screen
+ * into an sRGB buffer with RGBA_8888 pixel format.
+ * The subregion can be optionally rotated. It will also be scaled to
+ * match the size of the output buffer.
+ *
* At the moment, sourceCrop is ignored and is always set to the visible
* region (projected display viewport) of the screen.
*
@@ -193,15 +223,34 @@
*/
virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, Rotation rotation = eRotateNone) = 0;
+ bool useIdentityTransform, Rotation rotation = eRotateNone) {
+ return captureScreen(display, outBuffer, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+ sourceCrop, reqWidth, reqHeight, useIdentityTransform, rotation);
+ }
/**
* Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+ *
+ * reqDataspace and reqPixelFormat specify the data space and pixel format
+ * of the buffer. The caller should pick the data space and pixel format
+ * that it can consume.
*/
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
- sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
float frameScale = 1.0, bool childrenOnly = false) = 0;
+ /**
+ * Capture a subtree of the layer hierarchy into an sRGB buffer with RGBA_8888 pixel format,
+ * potentially ignoring the root node.
+ */
+ status_t captureLayers(const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+ const Rect& sourceCrop, float frameScale = 1.0,
+ bool childrenOnly = false) {
+ return captureLayers(layerHandleBinder, outBuffer, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, sourceCrop, frameScale, childrenOnly);
+ }
+
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
@@ -231,8 +280,19 @@
*/
virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
- virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat) const = 0;
+ virtual status_t getColorManagement(bool* outGetColorManagement) const = 0;
+
+ /* Gets the composition preference of the default data space and default pixel format,
+ * as well as the wide color gamut data space and wide color gamut pixel format.
+ * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+ * has no wide color gamut support.
+ *
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+ ui::PixelFormat* defaultPixelFormat,
+ ui::Dataspace* wideColorGamutDataspace,
+ ui::PixelFormat* wideColorGamutPixelFormat) const = 0;
};
// ----------------------------------------------------------------------------
@@ -271,6 +331,7 @@
GET_LAYER_DEBUG_INFO,
CREATE_SCOPED_CONNECTION,
GET_COMPOSITION_PREFERENCE,
+ GET_COLOR_MANAGEMENT,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
new file mode 100644
index 0000000..5c41c21
--- /dev/null
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/SafeInterface.h>
+
+#include <utils/Timers.h>
+
+#include <cstdint>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+
+class ITransactionCompletedListener;
+
+using CallbackId = int64_t;
+
+struct CallbackIdsHash {
+ // CallbackId vectors have several properties that let us get away with this simple hash.
+ // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is
+ // empty we can still hash 0.
+ // 2) CallbackId vectors for the same listener either are identical or contain none of the
+ // same members. It is sufficient to just check the first CallbackId in the vectors. If
+ // they match, they are the same. If they do not match, they are not the same.
+ std::size_t operator()(const std::vector<CallbackId> callbackIds) const {
+ return std::hash<CallbackId>{}((callbackIds.size() == 0) ? 0 : callbackIds.front());
+ }
+};
+
+class SurfaceStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ SurfaceStats() = default;
+ SurfaceStats(const sp<IBinder>& sc, nsecs_t time, bool releasePrevBuffer)
+ : surfaceControl(sc), acquireTime(time), releasePreviousBuffer(releasePrevBuffer) {}
+
+ sp<IBinder> surfaceControl;
+ nsecs_t acquireTime = -1;
+ bool releasePreviousBuffer = false;
+};
+
+class TransactionStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ nsecs_t latchTime = -1;
+ nsecs_t presentTime = -1;
+ std::vector<SurfaceStats> surfaceStats;
+};
+
+class ListenerStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ static ListenerStats createEmpty(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbackIds);
+
+ sp<ITransactionCompletedListener> listener;
+ std::unordered_map<std::vector<CallbackId>, TransactionStats, CallbackIdsHash> transactionStats;
+};
+
+class ITransactionCompletedListener : public IInterface {
+public:
+ DECLARE_META_INTERFACE(TransactionCompletedListener)
+
+ virtual void onTransactionCompleted(ListenerStats stats) = 0;
+};
+
+class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
+public:
+ BnTransactionCompletedListener()
+ : SafeBnInterface<ITransactionCompletedListener>("BnTransactionCompletedListener") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
+};
+
+class ListenerCallbacks {
+public:
+ ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbacks)
+ : transactionCompletedListener(listener),
+ callbackIds(callbacks.begin(), callbacks.end()) {}
+
+ ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+ const std::vector<CallbackId>& ids)
+ : transactionCompletedListener(listener), callbackIds(ids) {}
+
+ sp<ITransactionCompletedListener> transactionCompletedListener;
+ std::vector<CallbackId> callbackIds;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index e06e2b1..ddbac7b 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
#include <math/vec3.h>
#include <ui/GraphicTypes.h>
@@ -74,6 +75,7 @@
eApiChanged = 0x04000000,
eSidebandStreamChanged = 0x08000000,
eColorTransformChanged = 0x10000000,
+ eListenerCallbacksChanged = 0x20000000,
};
layer_state_t()
@@ -154,6 +156,8 @@
int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
+
+ std::vector<ListenerCallbacks> listenerCallbacks;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 69a759f..1cafb77 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,7 +19,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <set>
#include <unordered_map>
+#include <unordered_set>
#include <binder/IBinder.h>
@@ -33,9 +35,10 @@
#include <ui/PixelFormat.h>
#include <gui/CpuConsumer.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <gui/LayerState.h>
#include <gui/SurfaceControl.h>
#include <math/vec3.h>
-#include <gui/LayerState.h>
namespace android {
@@ -49,6 +52,37 @@
// ---------------------------------------------------------------------------
+using TransactionCompletedCallbackTakesContext =
+ std::function<void(void* /*context*/, const TransactionStats&)>;
+using TransactionCompletedCallback = std::function<void(const TransactionStats&)>;
+
+class TransactionCompletedListener : public BnTransactionCompletedListener {
+ TransactionCompletedListener();
+
+ CallbackId getNextIdLocked() REQUIRES(mMutex);
+
+ std::mutex mMutex;
+
+ bool mListening GUARDED_BY(mMutex) = false;
+
+ CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
+
+ std::map<CallbackId, TransactionCompletedCallback> mCallbacks GUARDED_BY(mMutex);
+
+public:
+ static sp<TransactionCompletedListener> getInstance();
+ static sp<ITransactionCompletedListener> getIInstance();
+
+ void startListeningLocked() REQUIRES(mMutex);
+
+ CallbackId addCallback(const TransactionCompletedCallback& callback);
+
+ // Overrides BnTransactionCompletedListener's onTransactionCompleted
+ void onTransactionCompleted(ListenerStats stats) override;
+};
+
+// ---------------------------------------------------------------------------
+
class SurfaceComposerClient : public RefBase
{
friend class Composer;
@@ -101,9 +135,15 @@
/* Triggers screen on/off or low power mode and waits for it to complete */
static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
- //
- static status_t getCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat);
+ /* Returns the composition preference of the default data space and default pixel format,
+ * as well as the wide color gamut data space and wide color gamut pixel format.
+ * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+ * has no wide color gamut support.
+ */
+ static status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+ ui::PixelFormat* defaultPixelFormat,
+ ui::Dataspace* wideColorGamutDataspace,
+ ui::PixelFormat* wideColorGamutPixelFormat);
// ------------------------------------------------------------------------
// surface creation / destruction
@@ -152,9 +192,27 @@
}
};
+ struct TCLHash {
+ std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
+ return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
+ }
+ };
+
+ struct CallbackInfo {
+ // All the callbacks that have been requested for a TransactionCompletedListener in the
+ // Transaction
+ std::unordered_set<CallbackId> callbackIds;
+ // All the SurfaceControls that have been modified in this TransactionCompletedListener's
+ // process that require a callback if there is one or more callbackIds set.
+ std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
+ };
+
class Transaction {
std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
+ std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+ mListenerCallbacks;
+
uint32_t mForceSynchronous = 0;
uint32_t mTransactionNestCount = 0;
bool mAnimation = false;
@@ -165,6 +223,8 @@
layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
DisplayState& getDisplayState(const sp<IBinder>& token);
+ void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
+
public:
Transaction() = default;
virtual ~Transaction() = default;
@@ -244,6 +304,9 @@
Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
const sp<NativeHandle>& sidebandStream);
+ Transaction& addTransactionCompletedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
// The child SurfaceControls will not throw exceptions or return errors,
@@ -329,16 +392,21 @@
public:
// if cropping isn't required, callers may pass in a default Rect, e.g.:
// capture(display, producer, Rect(), reqWidth, ...);
- static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
- uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation,
- sp<GraphicBuffer>* outBuffer);
- static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale,
- sp<GraphicBuffer>* outBuffer);
- static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+ static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ uint32_t rotation, sp<GraphicBuffer>* outBuffer);
+ static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ float frameScale, sp<GraphicBuffer>* outBuffer);
+ static status_t captureChildLayers(const sp<IBinder>& layerHandle,
+ const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer);
};
// ---------------------------------------------------------------------------
+
}; // namespace android
#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 6d03374..aef7aed 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -777,14 +777,6 @@
ASSERT_OK(mProducer->detachBuffer(slot));
EXPECT_OK(buffer->initCheck());
- if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
- // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
- // isDetachedBuffer() set. Note that this only applies to BufferHub.
- EXPECT_TRUE(buffer->isDetachedBuffer());
- } else {
- EXPECT_FALSE(buffer->isDetachedBuffer());
- }
-
ASSERT_OK(mProducer->disconnect(TEST_API));
ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
@@ -801,16 +793,7 @@
ASSERT_OK(mProducer->detachBuffer(slot));
EXPECT_OK(buffer->initCheck());
- if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
- // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
- // isDetachedBuffer() set. Note that this only applies to BufferHub.
- EXPECT_TRUE(buffer->isDetachedBuffer());
- } else {
- EXPECT_FALSE(buffer->isDetachedBuffer());
- }
-
EXPECT_OK(mProducer->attachBuffer(&slot, buffer));
- EXPECT_FALSE(buffer->isDetachedBuffer());
EXPECT_OK(buffer->initCheck());
}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index bc80899..d0600da 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -134,8 +134,9 @@
sp<IBinder> display(sf->getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
- 64, 64, false));
+ ASSERT_EQ(NO_ERROR,
+ sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
NATIVE_WINDOW_API_CPU));
@@ -165,8 +166,9 @@
&buf));
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
- 64, 64, false));
+ ASSERT_EQ(NO_ERROR,
+ sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
}
TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
@@ -596,14 +598,19 @@
}
status_t setActiveColorMode(const sp<IBinder>& /*display*/,
ColorMode /*colorMode*/) override { return NO_ERROR; }
- status_t captureScreen(const sp<IBinder>& /*display*/,
- sp<GraphicBuffer>* /*outBuffer*/,
- Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
- bool /*useIdentityTransform*/,
- Rotation /*rotation*/) override { return NO_ERROR; }
+ status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/,
+ const ui::Dataspace /*reqDataspace*/,
+ const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
+ uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
+ bool /*useIdentityTransform*/, Rotation /*rotation*/) override {
+ return NO_ERROR;
+ }
virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
- sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/,
- float /*frameScale*/, bool /*childrenOnly*/) override {
+ sp<GraphicBuffer>* /*outBuffer*/,
+ const ui::Dataspace /*reqDataspace*/,
+ const ui::PixelFormat /*reqPixelFormat*/,
+ const Rect& /*sourceCrop*/, float /*frameScale*/,
+ bool /*childrenOnly*/) override {
return NO_ERROR;
}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
@@ -621,11 +628,15 @@
status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
return NO_ERROR;
}
- status_t getCompositionPreference(ui::Dataspace* /*outDataSpace*/,
- ui::PixelFormat* /*outPixelFormat*/) const override {
+ status_t getCompositionPreference(
+ ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/,
+ ui::Dataspace* /*outWideColorGamutDataspace*/,
+ ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override {
return NO_ERROR;
}
+ virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 5fbb3b2..fba319d 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -13,13 +13,20 @@
// limitations under the License.
ndk_headers {
- name: "libnativewindow_headers",
+ name: "libnativewindow_ndk_headers",
from: "include/android",
to: "android",
srcs: ["include/android/*.h"],
license: "NOTICE",
}
+// TODO(b/118715870): cleanup header files
+cc_library_headers {
+ name: "libnativewindow_headers",
+ export_include_dirs: ["include"],
+ vendor_available: false,
+}
+
ndk_library {
name: "libnativewindow",
symbol_file: "libnativewindow.map.txt",
@@ -40,6 +47,7 @@
cflags: [
"-Wall",
"-Werror",
+ "-Wno-enum-compare",
"-Wno-unused-function",
],
@@ -70,6 +78,7 @@
header_libs: [
"libnativebase_headers",
+ "libnativewindow_headers",
],
// headers we include in our public headers
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 9ca4941..23ac60b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -15,12 +15,31 @@
*/
/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
* @file hardware_buffer.h
+ * @brief API for native hardware buffers.
+ */
+/**
+ * @defgroup AHardwareBuffer Native Hardware Buffer
+ *
+ * AHardwareBuffer objects represent chunks of memory that can be
+ * accessed by various hardware components in the system. It can be
+ * easily converted to the Java counterpart
+ * android.hardware.HardwareBuffer and passed between processes using
+ * Binder. All operations involving AHardwareBuffer and HardwareBuffer
+ * are zero-copy, i.e., passing AHardwareBuffer to another process
+ * creates a shared view of the same region of memory.
+ *
+ * AHardwareBuffers can be bound to EGL/OpenGL and Vulkan primitives.
+ * For EGL, use the extension function eglGetNativeClientBufferANDROID
+ * to obtain an EGLClientBuffer and pass it directly to
+ * eglCreateImageKHR. Refer to the EGL extensions
+ * EGL_ANDROID_get_native_client_buffer and
+ * EGL_ANDROID_image_native_buffer for more information. In Vulkan,
+ * the contents of the AHardwareBuffer can be accessed as external
+ * memory. See the VK_ANDROID_external_memory_android_hardware_buffer
+ * extension for details.
+ *
+ * @{
*/
#ifndef ANDROID_HARDWARE_BUFFER_H
@@ -37,7 +56,7 @@
/**
* Buffer pixel formats.
*/
-enum {
+enum AHardwareBuffer_Format {
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R8G8B8A8_UNORM
@@ -134,27 +153,47 @@
/**
* Buffer usage flags, specifying how the buffer will be accessed.
*/
-enum {
- /// The buffer will never be read by the CPU.
+enum AHardwareBuffer_UsageFlags {
+ /// The buffer will never be locked for direct CPU reads using the
+ /// AHardwareBuffer_lock() function. Note that reading the buffer
+ /// using OpenGL or Vulkan functions or memory mappings is still
+ /// allowed.
AHARDWAREBUFFER_USAGE_CPU_READ_NEVER = 0UL,
- /// The buffer will sometimes be read by the CPU.
+ /// The buffer will sometimes be locked for direct CPU reads using
+ /// the AHardwareBuffer_lock() function. Note that reading the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_READ_RARELY = 2UL,
- /// The buffer will often be read by the CPU.
+ /// The buffer will often be locked for direct CPU reads using
+ /// the AHardwareBuffer_lock() function. Note that reading the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN = 3UL,
/// CPU read value mask.
AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL,
- /// The buffer will never be written by the CPU.
+ /// The buffer will never be locked for direct CPU writes using the
+ /// AHardwareBuffer_lock() function. Note that writing the buffer
+ /// using OpenGL or Vulkan functions or memory mappings is still
+ /// allowed.
AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER = 0UL << 4,
- /// The buffer will sometimes be written to by the CPU.
+ /// The buffer will sometimes be locked for direct CPU writes using
+ /// the AHardwareBuffer_lock() function. Note that writing the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY = 2UL << 4,
- /// The buffer will often be written to by the CPU.
+ /// The buffer will often be locked for direct CPU writes using
+ /// the AHardwareBuffer_lock() function. Note that writing the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN = 3UL << 4,
/// CPU write value mask.
AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4,
/// The buffer will be read from by the GPU as a texture.
AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8,
+ /// The buffer will be written to by the GPU as a framebuffer attachment.
+ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9,
/**
* The buffer will be written to by the GPU as a framebuffer attachment.
* Note that the name of this flag is somewhat misleading: it does not imply
@@ -162,16 +201,33 @@
* format that will be used as a framebuffer attachment should also have
* this flag.
*/
- AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = 1UL << 9,
- /// The buffer must not be used outside of a protected hardware path.
+ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
+ /**
+ * The buffer is protected from direct CPU access or being read by non-secure
+ * hardware, such as video encoders. This flag is incompatible with CPU
+ * read and write flags. It is mainly used when handling DRM video.
+ * Refer to the EGL extension EGL_EXT_protected_content and GL extension
+ * EXT_protected_textures for more information on how these buffers are expected
+ * to behave.
+ */
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
/// The buffer will be read by a hardware video encoder.
AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
- /// The buffer will be used for direct writes from sensors.
+ /**
+ * The buffer will be used for direct writes from sensors.
+ * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+ */
AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23,
- /// The buffer will be used as a shader storage or uniform buffer object.
+ /**
+ * The buffer will be used as a shader storage or uniform buffer object.
+ * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+ */
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
- /// The buffer will be used as a cube map texture.
+ /**
+ * The buffer will be used as a cube map texture.
+ * When this flag is present, the buffer must have a layer count that is
+ * a multiple of 6.
+ */
AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25,
/// The buffer contains a complete mipmap hierarchy.
AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
@@ -206,20 +262,27 @@
uint32_t width; ///< Width in pixels.
uint32_t height; ///< Height in pixels.
uint32_t layers; ///< Number of images in an image array.
- uint32_t format; ///< One of AHARDWAREBUFFER_FORMAT_*
- uint64_t usage; ///< Combination of AHARDWAREBUFFER_USAGE_*
+ uint32_t format; ///< One of AHardwareBuffer_Format.
+ uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags.
uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
uint32_t rfu0; ///< Initialize to zero, reserved for future use.
uint64_t rfu1; ///< Initialize to zero, reserved for future use.
} AHardwareBuffer_Desc;
+/**
+ * Opaque handle for a native hardware buffer.
+ */
typedef struct AHardwareBuffer AHardwareBuffer;
#if __ANDROID_API__ >= 26
/**
- * Allocates a buffer that backs an AHardwareBuffer using the passed
- * AHardwareBuffer_Desc.
+ * Allocates a buffer that matches the passed AHardwareBuffer_Desc.
+ *
+ * If allocation succeeds, the buffer can be used according to the
+ * usage flags specified in its description. If a buffer is used in ways
+ * not compatible with its usage flags, the results are undefined and
+ * may include program termination.
*
* \return 0 on success, or an error number of the allocation fails for
* any reason. The returned buffer has a reference count of 1.
@@ -234,7 +297,7 @@
/**
* Remove a reference that was previously acquired with
- * AHardwareBuffer_acquire().
+ * AHardwareBuffer_acquire() or AHardwareBuffer_allocate().
*/
void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6831f91..6730596 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -15,7 +15,13 @@
*/
/**
- * @addtogroup NativeActivity Native Activity
+ * @defgroup ANativeWindow Native Window
+ *
+ * ANativeWindow represents the producer end of an image queue.
+ * It is the C counterpart of the android.view.Surface object in Java,
+ * and can be converted both ways. Depending on the consumer, images
+ * submitted to ANativeWindow can be shown on the display or sent to
+ * other consumers, such as video encoders.
* @{
*/
@@ -41,7 +47,7 @@
* Legacy window pixel format names, kept for backwards compatibility.
* New code and APIs should use AHARDWAREBUFFER_FORMAT_*.
*/
-enum {
+enum ANativeWindow_LegacyFormat {
// NOTE: these values must match the values from graphics/common/x.x/types.hal
/** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
@@ -95,7 +101,7 @@
/// memory. This may be >= width.
int32_t stride;
- /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+ /// The format of the buffer. One of AHardwareBuffer_Format.
int32_t format;
/// The actual bits.
@@ -151,7 +157,7 @@
*
* \param width width of the buffers in pixels.
* \param height height of the buffers in pixels.
- * \param format one of AHARDWAREBUFFER_FORMAT_* constants.
+ * \param format one of the AHardwareBuffer_Format constants.
* \return 0 for success, or a negative value on error.
*/
int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
diff --git a/services/surfaceflinger/RenderEngine/Android.bp b/libs/renderengine/Android.bp
similarity index 93%
rename from services/surfaceflinger/RenderEngine/Android.bp
rename to libs/renderengine/Android.bp
index 79145c2..7efc8bd 100644
--- a/services/surfaceflinger/RenderEngine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -1,4 +1,3 @@
-// TODO(b/112585051) Add to VNDK once moved to libs/
cc_defaults {
name: "renderengine_defaults",
cflags: [
@@ -26,7 +25,7 @@
"libGLESv2",
"libgui",
"liblog",
- "libnativewindow",
+ "libnativewindow",
"libui",
"libutils",
],
@@ -60,8 +59,11 @@
cc_library_static {
name: "librenderengine",
defaults: ["librenderengine_defaults"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
double_loadable: true,
-
clang: true,
cflags: [
"-fvisibility=hidden",
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/libs/renderengine/Description.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/Description.cpp
rename to libs/renderengine/Description.cpp
index 9696d28..b9cea10 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/libs/renderengine/Description.cpp
@@ -52,5 +52,5 @@
return colorMatrix != identity;
}
-} // namespace renderengine
-} // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/libs/renderengine/Mesh.cpp
similarity index 97%
rename from services/surfaceflinger/RenderEngine/Mesh.cpp
rename to libs/renderengine/Mesh.cpp
index 809a0d7..6a40c6c 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/libs/renderengine/Mesh.cpp
@@ -91,5 +91,5 @@
return mStride;
}
-} // namespace renderengine
-} // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
similarity index 90%
rename from services/surfaceflinger/RenderEngine/RenderEngine.cpp
rename to libs/renderengine/RenderEngine.cpp
index 3b54873..8be1c3c 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -39,8 +39,7 @@
namespace impl {
-RenderEngine::RenderEngine(uint32_t featureFlags)
- : mFeatureFlags(featureFlags) {}
+RenderEngine::RenderEngine(uint32_t featureFlags) : mFeatureFlags(featureFlags) {}
RenderEngine::~RenderEngine() = default;
@@ -52,6 +51,6 @@
return SyncFeatures::getInstance().useWaitSync();
}
-} // namespace impl
-} // namespace renderengine
-} // namespace android
+} // namespace impl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/TEST_MAPPING b/libs/renderengine/TEST_MAPPING
similarity index 100%
rename from services/surfaceflinger/RenderEngine/TEST_MAPPING
rename to libs/renderengine/TEST_MAPPING
diff --git a/services/surfaceflinger/RenderEngine/Texture.cpp b/libs/renderengine/Texture.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/Texture.cpp
rename to libs/renderengine/Texture.cpp
index 5eabbcf..154cde8 100644
--- a/services/surfaceflinger/RenderEngine/Texture.cpp
+++ b/libs/renderengine/Texture.cpp
@@ -73,5 +73,5 @@
return mHeight;
}
-} // namespace renderengine
-} // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLES20RenderEngine.cpp
similarity index 89%
rename from services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
rename to libs/renderengine/gl/GLES20RenderEngine.cpp
index dbf50c5..e244a83 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/libs/renderengine/gl/GLES20RenderEngine.cpp
@@ -261,7 +261,7 @@
contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
contextAttributes.push_back(contextClientVersion);
bool useContextPriority = extensions.hasContextPriority() &&
- (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
+ (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
if (useContextPriority) {
contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
@@ -275,6 +275,8 @@
// now figure out what version of GL did we actually get
// NOTE: a dummy surface is not needed if KHR_create_context is supported
+ // TODO(alecmouri): don't create this surface if EGL_KHR_surfaceless_context
+ // is supported.
EGLConfig dummyConfig = config;
if (dummyConfig == EGL_NO_CONFIG) {
@@ -301,10 +303,10 @@
break;
case GLES_VERSION_2_0:
case GLES_VERSION_3_0:
- engine = std::make_unique<GLES20RenderEngine>(featureFlags);
+ engine = std::make_unique<GLES20RenderEngine>(featureFlags, display, config, ctxt,
+ dummy);
break;
}
- engine->setEGLHandles(display, config, ctxt);
ALOGI("OpenGL ES informations:");
ALOGI("vendor : %s", extensions.getVendor());
@@ -314,9 +316,6 @@
ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
- eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(display, dummy);
-
return engine;
}
@@ -359,11 +358,13 @@
return config;
}
-GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
+ EGLContext ctxt, EGLSurface dummy)
: renderengine::impl::RenderEngine(featureFlags),
- mEGLDisplay(EGL_NO_DISPLAY),
- mEGLConfig(nullptr),
- mEGLContext(EGL_NO_CONTEXT),
+ mEGLDisplay(display),
+ mEGLConfig(config),
+ mEGLContext(ctxt),
+ mDummySurface(dummy),
mVpWidth(0),
mVpHeight(0),
mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
@@ -385,17 +386,9 @@
// mColorBlindnessCorrection = M;
if (mUseColorManagement) {
- ColorSpace srgb(ColorSpace::sRGB());
- ColorSpace displayP3(ColorSpace::DisplayP3());
- ColorSpace bt2020(ColorSpace::BT2020());
-
- // Compute sRGB to Display P3 transform matrix.
- // NOTE: For now, we are limiting output wide color space support to
- // Display-P3 only.
- mSrgbToDisplayP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
-
- // Compute Display P3 to sRGB transform matrix.
- mDisplayP3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
+ const ColorSpace srgb(ColorSpace::sRGB());
+ const ColorSpace displayP3(ColorSpace::DisplayP3());
+ const ColorSpace bt2020(ColorSpace::BT2020());
// no chromatic adaptation needed since all color spaces use D65 for their white points.
mSrgbToXyz = mat4(srgb.getRGBtoXYZ());
@@ -404,6 +397,20 @@
mXyzToSrgb = mat4(srgb.getXYZtoRGB());
mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB());
mXyzToBt2020 = mat4(bt2020.getXYZtoRGB());
+
+ // Compute sRGB to Display P3 and BT2020 transform matrix.
+ // NOTE: For now, we are limiting output wide color space support to
+ // Display-P3 and BT2020 only.
+ mSrgbToDisplayP3 = mXyzToDisplayP3 * mSrgbToXyz;
+ mSrgbToBt2020 = mXyzToBt2020 * mSrgbToXyz;
+
+ // Compute Display P3 to sRGB and BT2020 transform matrix.
+ mDisplayP3ToSrgb = mXyzToSrgb * mDisplayP3ToXyz;
+ mDisplayP3ToBt2020 = mXyzToBt2020 * mDisplayP3ToXyz;
+
+ // Compute BT2020 to sRGB and Display P3 transform matrix
+ mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz;
+ mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz;
}
}
@@ -589,15 +596,13 @@
glDeleteTextures(count, names);
}
-void GLES20RenderEngine::bindExternalTextureImage(uint32_t texName,
- const Image& image) {
+void GLES20RenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) {
const GLImage& glImage = static_cast<const GLImage&>(image);
const GLenum target = GL_TEXTURE_EXTERNAL_OES;
glBindTexture(target, texName);
if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
- glEGLImageTargetTexture2DOES(target,
- static_cast<GLeglImageOES>(glImage.getEGLImage()));
+ glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(glImage.getEGLImage()));
}
}
@@ -613,16 +618,15 @@
// Bind the Framebuffer to render into
glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, textureName, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
mRenderToFbo = true;
mFboHeight = glFramebuffer->getBufferHeight();
uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES,
- "glCheckFramebufferStatusOES error %d", glStatus);
+ ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
+ glStatus);
return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
}
@@ -633,12 +637,6 @@
// back to main framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
- // Workaround for b/77935566 to force the EGL driver to release the
- // screenshot buffer
- setScissor(Rect::EMPTY_RECT);
- clearWithColor(0.0, 0.0, 0.0, 0.0);
- disableScissor();
}
void GLES20RenderEngine::checkErrors() const {
@@ -790,12 +788,19 @@
Description managedState = mState;
Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
- Dataspace outputStandard = static_cast<Dataspace>(mOutputDataSpace &
- Dataspace::STANDARD_MASK);
- Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
- Dataspace::TRANSFER_MASK);
+ Dataspace outputStandard =
+ static_cast<Dataspace>(mOutputDataSpace & Dataspace::STANDARD_MASK);
+ Dataspace outputTransfer =
+ static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK);
bool needsXYZConversion = needsXYZTransformMatrix();
+ // NOTE: if the input standard of the input dataspace is not STANDARD_DCI_P3 or
+ // STANDARD_BT2020, it will be treated as STANDARD_BT709
+ if (inputStandard != Dataspace::STANDARD_DCI_P3 &&
+ inputStandard != Dataspace::STANDARD_BT2020) {
+ inputStandard = Dataspace::STANDARD_BT709;
+ }
+
if (needsXYZConversion) {
// The supported input color spaces are standard RGB, Display P3 and BT2020.
switch (inputStandard) {
@@ -830,13 +835,33 @@
// - scRGB non-linear
// - sRGB
// - Display P3
+ // - BT2020
// The output data spaces could be
// - sRGB
// - Display P3
- if (outputStandard == Dataspace::STANDARD_BT709) {
- managedState.outputTransformMatrix = mDisplayP3ToSrgb;
- } else if (outputStandard == Dataspace::STANDARD_DCI_P3) {
- managedState.outputTransformMatrix = mSrgbToDisplayP3;
+ // - BT2020
+ switch (outputStandard) {
+ case Dataspace::STANDARD_BT2020:
+ if (inputStandard == Dataspace::STANDARD_BT709) {
+ managedState.outputTransformMatrix = mSrgbToBt2020;
+ } else if (inputStandard == Dataspace::STANDARD_DCI_P3) {
+ managedState.outputTransformMatrix = mDisplayP3ToBt2020;
+ }
+ break;
+ case Dataspace::STANDARD_DCI_P3:
+ if (inputStandard == Dataspace::STANDARD_BT709) {
+ managedState.outputTransformMatrix = mSrgbToDisplayP3;
+ } else if (inputStandard == Dataspace::STANDARD_BT2020) {
+ managedState.outputTransformMatrix = mBt2020ToDisplayP3;
+ }
+ break;
+ default:
+ if (inputStandard == Dataspace::STANDARD_DCI_P3) {
+ managedState.outputTransformMatrix = mDisplayP3ToSrgb;
+ } else if (inputStandard == Dataspace::STANDARD_BT2020) {
+ managedState.outputTransformMatrix = mBt2020ToSrgb;
+ }
+ break;
}
}
@@ -847,9 +872,9 @@
if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() ||
inputTransfer != outputTransfer) {
managedState.inputTransferFunction =
- Description::dataSpaceToTransferFunction(inputTransfer);
+ Description::dataSpaceToTransferFunction(inputTransfer);
managedState.outputTransferFunction =
- Description::dataSpaceToTransferFunction(outputTransfer);
+ Description::dataSpaceToTransferFunction(outputTransfer);
}
ProgramCache::getInstance().useProgram(managedState);
@@ -921,7 +946,7 @@
const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
return standard == Dataspace::STANDARD_BT2020 &&
- (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
+ (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
}
// For convenience, we want to convert the input color space to XYZ color space first,
@@ -938,18 +963,12 @@
const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
- const Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
- Dataspace::TRANSFER_MASK);
+ const Dataspace outputTransfer =
+ static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK);
return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
}
-void GLES20RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
- mEGLDisplay = display;
- mEGLConfig = config;
- mEGLContext = ctxt;
-}
-
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLES20RenderEngine.h
similarity index 92%
rename from services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
rename to libs/renderengine/gl/GLES20RenderEngine.h
index b08e096..aebb319 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
+++ b/libs/renderengine/gl/GLES20RenderEngine.h
@@ -47,7 +47,8 @@
static std::unique_ptr<GLES20RenderEngine> create(int hwcFormat, uint32_t featureFlags);
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
- GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
+ GLES20RenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
+ EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
~GLES20RenderEngine() override;
std::unique_ptr<Framebuffer> createFramebuffer() override;
@@ -120,11 +121,12 @@
// with PQ or HLG transfer function.
bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
bool needsXYZTransformMatrix() const;
- void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
+ void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
EGLContext mEGLContext;
+ EGLSurface mDummySurface;
GLuint mProtectedTexName;
GLint mMaxViewportDims[2];
GLint mMaxTextureSize;
@@ -132,14 +134,18 @@
GLuint mVpHeight;
Description mState;
- mat4 mSrgbToDisplayP3;
- mat4 mDisplayP3ToSrgb;
mat4 mSrgbToXyz;
- mat4 mBt2020ToXyz;
mat4 mDisplayP3ToXyz;
+ mat4 mBt2020ToXyz;
mat4 mXyzToSrgb;
mat4 mXyzToDisplayP3;
mat4 mXyzToBt2020;
+ mat4 mSrgbToDisplayP3;
+ mat4 mSrgbToBt2020;
+ mat4 mDisplayP3ToSrgb;
+ mat4 mDisplayP3ToBt2020;
+ mat4 mBt2020ToSrgb;
+ mat4 mBt2020ToDisplayP3;
bool mRenderToFbo = false;
int32_t mSurfaceHeight = 0;
@@ -156,8 +162,8 @@
const bool mUseColorManagement = false;
};
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
#endif /* SF_GLES20RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp
similarity index 97%
rename from services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
rename to libs/renderengine/gl/GLExtensions.cpp
index 0fdb9aa..784693b 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
+++ b/libs/renderengine/gl/GLExtensions.cpp
@@ -122,6 +122,6 @@
return mEGLExtensions.string();
}
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLExtensions.h b/libs/renderengine/gl/GLExtensions.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/GLExtensions.h
rename to libs/renderengine/gl/GLExtensions.h
index 02ad965..382c23a 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
+++ b/libs/renderengine/gl/GLExtensions.h
@@ -75,8 +75,8 @@
char const* getEGLExtensions() const;
};
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
#endif // ANDROID_SF_GLEXTENSION_H
diff --git a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
similarity index 88%
rename from services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp
rename to libs/renderengine/gl/GLFramebuffer.cpp
index 83d2bde..2bd4e7f 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -28,8 +28,7 @@
namespace gl {
GLFramebuffer::GLFramebuffer(const GLES20RenderEngine& engine)
- : mEGLDisplay(engine.getEGLDisplay()),
- mEGLImage(EGL_NO_IMAGE_KHR) {
+ : mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
glGenTextures(1, &mTextureName);
glGenFramebuffers(1, &mFramebufferName);
}
@@ -49,8 +48,7 @@
}
if (nativeBuffer) {
- mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID,
+ mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
nativeBuffer, nullptr);
if (mEGLImage == EGL_NO_IMAGE_KHR) {
return false;
@@ -61,6 +59,6 @@
return true;
}
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
similarity index 95%
rename from services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h
rename to libs/renderengine/gl/GLFramebuffer.h
index 193cbdc..90c6f4a 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -51,6 +51,6 @@
int32_t mBufferWidth = 0;
};
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/GLImage.cpp
rename to libs/renderengine/gl/GLImage.cpp
index 746f3e7..5a92093 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -19,8 +19,8 @@
#include <vector>
#include <log/log.h>
-#include "GLExtensions.h"
#include "GLES20RenderEngine.h"
+#include "GLExtensions.h"
namespace android {
namespace renderengine {
@@ -70,6 +70,6 @@
return true;
}
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLImage.h b/libs/renderengine/gl/GLImage.h
similarity index 94%
rename from services/surfaceflinger/RenderEngine/gl/GLImage.h
rename to libs/renderengine/gl/GLImage.h
index f670783..0e451f8 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLImage.h
+++ b/libs/renderengine/gl/GLImage.h
@@ -47,6 +47,6 @@
DISALLOW_COPY_AND_ASSIGN(GLImage);
};
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLSurface.cpp b/libs/renderengine/gl/GLSurface.cpp
similarity index 91%
rename from services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
rename to libs/renderengine/gl/GLSurface.cpp
index 104af56..2d694e9 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
+++ b/libs/renderengine/gl/GLSurface.cpp
@@ -29,8 +29,8 @@
: mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
// RE does not assume any config when EGL_KHR_no_config_context is supported
if (mEGLConfig == EGL_NO_CONFIG_KHR) {
- mEGLConfig = GLES20RenderEngine::chooseEglConfig(mEGLDisplay,
- PIXEL_FORMAT_RGBA_8888, false);
+ mEGLConfig =
+ GLES20RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false);
}
}
@@ -100,6 +100,6 @@
return mSurfaceHeight;
}
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLSurface.h b/libs/renderengine/gl/GLSurface.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/GLSurface.h
rename to libs/renderengine/gl/GLSurface.h
index 8aa223a..092d371 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLSurface.h
+++ b/libs/renderengine/gl/GLSurface.h
@@ -71,6 +71,6 @@
DISALLOW_COPY_AND_ASSIGN(GLSurface);
};
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/Program.cpp
rename to libs/renderengine/gl/Program.cpp
index 7ae5736..7d2ea90 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.cpp
+++ b/libs/renderengine/gl/Program.cpp
@@ -130,16 +130,15 @@
// The output transform matrix and color matrix can be combined as one matrix
// that is applied right before applying OETF.
mat4 outputTransformMatrix = desc.colorMatrix * desc.outputTransformMatrix;
- glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE,
- outputTransformMatrix.asArray());
+ glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE, outputTransformMatrix.asArray());
}
if (mDisplayMaxLuminanceLoc >= 0) {
- glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance) ;
+ glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance);
}
// these uniforms are always present
glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.projectionMatrix.asArray());
}
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.h b/libs/renderengine/gl/Program.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/Program.h
rename to libs/renderengine/gl/Program.h
index b1ce8cf..99bf0f0 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.h
+++ b/libs/renderengine/gl/Program.h
@@ -87,8 +87,8 @@
GLint mOutputTransformMatrixLoc;
};
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_PROGRAM_H */
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
similarity index 97%
rename from services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
rename to libs/renderengine/gl/ProgramCache.cpp
index 6d431b6..464fc15 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -130,18 +130,18 @@
: 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::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)
.set(Key::OPACITY_MASK,
description.isOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
.set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK,
- description.hasInputTransformMatrix() ?
- Key::INPUT_TRANSFORM_MATRIX_ON : Key::INPUT_TRANSFORM_MATRIX_OFF)
+ description.hasInputTransformMatrix() ? Key::INPUT_TRANSFORM_MATRIX_ON
+ : Key::INPUT_TRANSFORM_MATRIX_OFF)
.set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK,
- description.hasOutputTransformMatrix() || description.hasColorMatrix() ?
- Key::OUTPUT_TRANSFORM_MATRIX_ON : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
+ description.hasOutputTransformMatrix() || description.hasColorMatrix()
+ ? Key::OUTPUT_TRANSFORM_MATRIX_ON
+ : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
needs.set(Key::Y410_BT2020_MASK,
description.isY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
@@ -631,7 +631,8 @@
// avoid divide by 0 by adding 0.5/256 to the alpha channel
fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
}
- fs << "gl_FragColor.rgb = OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
+ fs << "gl_FragColor.rgb = "
+ "OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
if (!needs.isOpaque() && needs.isPremultiplied()) {
// and re-premultiply if needed after gamma correction
fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
@@ -678,6 +679,6 @@
}
}
-} // namespace gl
-} // namespace renderengine
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
similarity index 95%
rename from services/surfaceflinger/RenderEngine/gl/ProgramCache.h
rename to libs/renderengine/gl/ProgramCache.h
index 120b3d1..d60fee6 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -159,14 +159,10 @@
// for use by std::unordered_map
- bool operator==(const Key& other) const {
- return mKey == other.mKey;
- }
+ bool operator==(const Key& other) const { return mKey == other.mKey; }
struct Hash {
- size_t operator()(const Key& key) const {
- return static_cast<size_t>(key.mKey);
- }
+ size_t operator()(const Key& key) const { return static_cast<size_t>(key.mKey); }
};
};
@@ -205,11 +201,11 @@
std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash> mCache;
};
-} // namespace gl
-} // namespace renderengine
+} // namespace gl
+} // namespace renderengine
ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key)
-} // namespace android
+} // namespace android
#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
similarity index 100%
rename from services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h
rename to libs/renderengine/include/renderengine/DisplaySettings.h
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h b/libs/renderengine/include/renderengine/Framebuffer.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
rename to libs/renderengine/include/renderengine/Framebuffer.h
index 6595466..558b9c7 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
+++ b/libs/renderengine/include/renderengine/Framebuffer.h
@@ -30,5 +30,5 @@
virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) = 0;
};
-} // namespace renderengine
-} // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Image.h b/libs/renderengine/include/renderengine/Image.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Image.h
rename to libs/renderengine/include/renderengine/Image.h
index 85ec91a..3bb4731 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Image.h
+++ b/libs/renderengine/include/renderengine/Image.h
@@ -27,6 +27,5 @@
virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0;
};
-} // namespace renderengine
-} // namespace android
-
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
similarity index 100%
rename from services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h
rename to libs/renderengine/include/renderengine/LayerSettings.h
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h b/libs/renderengine/include/renderengine/Mesh.h
similarity index 97%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
rename to libs/renderengine/include/renderengine/Mesh.h
index 15d2a11..fe9022d 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
+++ b/libs/renderengine/include/renderengine/Mesh.h
@@ -101,6 +101,6 @@
Primitive mPrimitive;
};
-} // namespace renderengine
-} // namespace android
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
rename to libs/renderengine/include/renderengine/RenderEngine.h
index f5d3d6b..becb3c3 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -58,7 +58,7 @@
class RenderEngine {
public:
enum FeatureFlag {
- USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color
+ USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color
USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
};
@@ -100,8 +100,8 @@
virtual bool waitFence(base::unique_fd fenceFd) = 0;
virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
- virtual void fillRegionWithColor(const Region& region, float red, float green,
- float blue, float alpha) = 0;
+ virtual void fillRegionWithColor(const Region& region, float red, float green, float blue,
+ float alpha) = 0;
virtual void setScissor(const Rect& region) = 0;
virtual void disableScissor() = 0;
@@ -176,11 +176,10 @@
class BindNativeBufferAsFramebuffer {
public:
BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
- : mEngine(engine),
- mFramebuffer(mEngine.createFramebuffer()),
- mStatus(NO_ERROR) {
- mStatus = mFramebuffer->setNativeWindowBuffer(buffer) ?
- mEngine.bindFrameBuffer(mFramebuffer.get()) : NO_MEMORY;
+ : mEngine(engine), mFramebuffer(mEngine.createFramebuffer()), mStatus(NO_ERROR) {
+ mStatus = mFramebuffer->setNativeWindowBuffer(buffer)
+ ? mEngine.bindFrameBuffer(mFramebuffer.get())
+ : NO_MEMORY;
}
~BindNativeBufferAsFramebuffer() {
mFramebuffer->setNativeWindowBuffer(nullptr);
@@ -209,8 +208,8 @@
const uint32_t mFeatureFlags;
};
-} // namespace impl
-} // namespace renderengine
-} // namespace android
+} // namespace impl
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h b/libs/renderengine/include/renderengine/Surface.h
similarity index 95%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
rename to libs/renderengine/include/renderengine/Surface.h
index 3999ddc..ba7331d 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
+++ b/libs/renderengine/include/renderengine/Surface.h
@@ -42,5 +42,5 @@
virtual int32_t getHeight() const = 0;
};
-} // namespace renderengine
-} // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h b/libs/renderengine/include/renderengine/Texture.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
rename to libs/renderengine/include/renderengine/Texture.h
index fb3e0cc..c69ace0 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
+++ b/libs/renderengine/include/renderengine/Texture.h
@@ -55,6 +55,6 @@
mat4 mTextureMatrix;
};
-} // namespace renderengine
-} // namespace android
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_TEXTURE_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h
similarity index 95%
rename from services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
rename to libs/renderengine/include/renderengine/private/Description.h
index 911bb7a..eadd656 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
+++ b/libs/renderengine/include/renderengine/private/Description.h
@@ -17,8 +17,8 @@
#ifndef SF_RENDER_ENGINE_DESCRIPTION_H_
#define SF_RENDER_ENGINE_DESCRIPTION_H_
-#include <ui/GraphicTypes.h>
#include <renderengine/Texture.h>
+#include <ui/GraphicTypes.h>
namespace android {
namespace renderengine {
@@ -33,7 +33,7 @@
LINEAR,
SRGB,
ST2084,
- HLG, // Hybrid Log-Gamma for HDR.
+ HLG, // Hybrid Log-Gamma for HDR.
};
static TransferFunction dataSpaceToTransferFunction(ui::Dataspace dataSpace);
@@ -75,7 +75,7 @@
mat4 outputTransformMatrix;
};
-} // namespace renderengine
-} // namespace android
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */
diff --git a/services/surfaceflinger/RenderEngine/tests/Android.bp b/libs/renderengine/tests/Android.bp
similarity index 100%
rename from services/surfaceflinger/RenderEngine/tests/Android.bp
rename to libs/renderengine/tests/Android.bp
diff --git a/services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
similarity index 100%
rename from services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp
rename to libs/renderengine/tests/RenderEngineTest.cpp
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 44a947e..8cc1a4e 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -37,7 +37,6 @@
#pragma clang diagnostic pop
#include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
#include <poll.h>
@@ -159,7 +158,7 @@
// If all imports succeed, replace the previous buffer and id.
mId = bufferId;
- mBufferStateBit = bufferTraits.buffer_state_bit();
+ mClientStateMask = bufferTraits.client_state_mask();
// TODO(b/112012161) Set up shared fences.
ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c50d1d0..5a1ddee 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -22,7 +22,6 @@
#include <grallocusage/GrallocUsageConversion.h>
-#include <ui/DetachedBufferHandle.h>
#include <ui/Gralloc2.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
@@ -490,24 +489,6 @@
return NO_ERROR;
}
-bool GraphicBuffer::isDetachedBuffer() const {
- return mDetachedBufferHandle && mDetachedBufferHandle->isValid();
-}
-
-status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) {
- if (isDetachedBuffer()) {
- ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this "
- "GraphicBuffer. Replacing the old one.");
- }
-
- mDetachedBufferHandle = std::move(channel);
- return NO_ERROR;
-}
-
-std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() {
- return std::move(mDetachedBufferHandle);
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index cefe5b3..daf6192 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -88,7 +88,7 @@
// A state mask which is unique to a buffer hub client among all its siblings sharing the same
// concrete graphic buffer.
- uint64_t buffer_state_bit() const { return mBufferStateBit; }
+ uint64_t client_state_mask() const { return mClientStateMask; }
size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
@@ -126,7 +126,7 @@
// Global id for the buffer that is consistent across processes.
int mId = -1;
- uint64_t mBufferStateBit = 0;
+ uint64_t mClientStateMask = 0;
// Wrapps the gralloc buffer handle of this buffer.
dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h
deleted file mode 100644
index f3c328d..0000000
--- a/libs/ui/include/ui/DetachedBufferHandle.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-
-#include <pdx/channel_handle.h>
-
-#include <memory>
-
-namespace android {
-
-// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be
-// created. Current implementation assumes that the underlying transport is using libpdx (thus
-// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder
-// backend if ever needed.
-class DetachedBufferHandle {
-public:
- static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) {
- return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle)));
- }
-
- // Accessors to get or take the internal pdx::LocalChannelHandle.
- pdx::LocalChannelHandle& handle() { return mHandle; }
- const pdx::LocalChannelHandle& handle() const { return mHandle; }
-
- // Returns whether the DetachedBufferHandle holds a BufferHub channel.
- bool isValid() const { return mHandle.valid(); }
-
-private:
- // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle.
- explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {}
-
- pdx::LocalChannelHandle mHandle;
-};
-
-} // namespace android
-
-#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index cc38982..e794462 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -34,7 +34,6 @@
namespace android {
-class DetachedBufferHandle;
class GraphicBufferMapper;
// ===========================================================================
@@ -191,11 +190,6 @@
status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
- // Sets and takes DetachedBuffer. Should only be called from BufferHub.
- bool isDetachedBuffer() const;
- status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer);
- std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle();
-
private:
~GraphicBuffer();
@@ -246,17 +240,6 @@
// match the BufferQueue's internal generation number (set through
// IGBP::setGenerationNumber), attempts to attach the buffer will fail.
uint32_t mGenerationNumber;
-
- // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a
- // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub,
- // there are three different modes:
- // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be
- // invalid.
- // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer
- // set. In this mode, mDetachedBufferHandle must be valid.
- // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer
- // set. In this mode, mDetachedBufferHandle must be invalid.
- std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle;
};
}; // namespace android
diff --git a/libs/ui/include_vndk/ui/Transform.h b/libs/ui/include_vndk/ui/Transform.h
new file mode 120000
index 0000000..60633c2
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Transform.h
@@ -0,0 +1 @@
+../../include/ui/Transform.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 228d202..1521e1d 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -29,16 +29,19 @@
}
cc_test {
- name: "GraphicBuffer_test",
- shared_libs: ["libpdx_default_transport", "libui", "libutils"],
- srcs: ["GraphicBuffer_test.cpp"],
- cflags: ["-Wall", "-Werror"],
-}
-
-cc_test {
name: "BufferHubBuffer_test",
- header_libs: ["libbufferhub_headers", "libdvr_headers"],
- shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+ header_libs: [
+ "libbufferhub_headers",
+ "libdvr_headers"
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libhidlbase",
+ "libhwbinder",
+ "libpdx_default_transport",
+ "libui",
+ "libutils"
+ ],
srcs: ["BufferHubBuffer_test.cpp"],
cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index be06ad2..606aee60 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,7 +16,11 @@
#define LOG_TAG "BufferHubBufferTest"
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
#include <ui/BufferHubBuffer.h>
namespace android {
@@ -30,15 +34,20 @@
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
-} // namespace
-
-using BufferHubBufferTest = ::testing::Test;
-
using dvr::BufferHubDefs::IsBufferGained;
+using dvr::BufferHubDefs::kFirstClientBitMask;
using dvr::BufferHubDefs::kMetadataHeaderSize;
-using dvr::BufferHubDefs::kProducerStateBit;
+using frameworks::bufferhub::V1_0::BufferHubStatus;
+using frameworks::bufferhub::V1_0::IBufferClient;
+using frameworks::bufferhub::V1_0::IBufferHub;
+using hardware::hidl_handle;
+using hidl::base::V1_0::IBase;
using pdx::LocalChannelHandle;
+class BufferHubBufferTest : public ::testing::Test {
+ void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
+};
+
TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
// Buffer Creation will fail: BLOB format requires height to be 1.
auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
@@ -75,6 +84,8 @@
auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
kUserMetadataSize);
int id1 = b1->id();
+ uint64_t bufferStateMask1 = b1->client_state_mask();
+ EXPECT_NE(bufferStateMask1, 0ULL);
EXPECT_TRUE(b1->IsValid());
EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
@@ -96,16 +107,14 @@
EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
int id2 = b2->id();
+ uint64_t bufferStateMask2 = b2->client_state_mask();
+ EXPECT_NE(bufferStateMask2, 0ULL);
// These two buffer instances are based on the same physical buffer under the
// hood, so they should share the same id.
EXPECT_EQ(id1, id2);
- // We use buffer_state_bit() to tell those two instances apart.
- EXPECT_NE(b1->buffer_state_bit(), b2->buffer_state_bit());
- EXPECT_NE(b1->buffer_state_bit(), 0ULL);
- EXPECT_NE(b2->buffer_state_bit(), 0ULL);
- EXPECT_NE(b1->buffer_state_bit(), kProducerStateBit);
- EXPECT_NE(b2->buffer_state_bit(), kProducerStateBit);
+ // We use client_state_mask() to tell those two instances apart.
+ EXPECT_NE(bufferStateMask1, bufferStateMask2);
// Both buffer instances should be in gained state.
EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
@@ -115,4 +124,20 @@
return;
}
+TEST_F(BufferHubBufferTest, ConnectHidlServer) {
+ sp<IBufferHub> bufferhub = IBufferHub::getService();
+ ASSERT_NE(nullptr, bufferhub.get());
+
+ // TODO(b/116681016): Fill in real test once the interface gets implemented..
+ hidl_handle handle;
+ EXPECT_TRUE(bufferhub
+ ->importBuffer(handle,
+ [](const auto& client, const auto& ret) {
+ EXPECT_EQ(client, nullptr);
+ EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+ })
+ .isOk());
+}
+
+} // namespace
} // namespace android
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
deleted file mode 100644
index eb679ac..0000000
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GraphicBufferTest"
-
-#include <ui/DetachedBufferHandle.h>
-#include <ui/GraphicBuffer.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-
-namespace {
-
-constexpr uint32_t kTestWidth = 1024;
-constexpr uint32_t kTestHeight = 1;
-constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
-constexpr uint32_t kTestLayerCount = 1;
-constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
-
-} // namespace
-
-class GraphicBufferTest : public testing::Test {};
-
-TEST_F(GraphicBufferTest, DetachedBuffer) {
- sp<GraphicBuffer> buffer(
- new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage));
-
- // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with
- // BufferHub. But this may change in the future.
- EXPECT_FALSE(buffer->isDetachedBuffer());
-
- pdx::LocalChannelHandle channel{nullptr, 1234};
- EXPECT_TRUE(channel.valid());
-
- std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel));
- EXPECT_FALSE(channel.valid());
- EXPECT_TRUE(handle->isValid());
- EXPECT_TRUE(handle->handle().valid());
-
- buffer->setDetachedBufferHandle(std::move(handle));
- EXPECT_TRUE(handle == nullptr);
- EXPECT_TRUE(buffer->isDetachedBuffer());
-
- handle = buffer->takeDetachedBufferHandle();
- EXPECT_TRUE(handle != nullptr);
- EXPECT_TRUE(handle->isValid());
- EXPECT_FALSE(buffer->isDetachedBuffer());
-}
-
-} // namespace android
diff --git a/libs/vr/CleanSpec.mk b/libs/vr/CleanSpec.mk
deleted file mode 100644
index a17c9b2..0000000
--- a/libs/vr/CleanSpec.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2012 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.
-#
-
-# If you don't need to do a full clean build but would like to touch
-# a file or delete some intermediate files, add a clean step to the end
-# of the list. These steps will only be run once, if they haven't been
-# run before.
-#
-# E.g.:
-# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
-#
-# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
-# files that are missing or have been moved.
-#
-# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
-# Use $(OUT_DIR) to refer to the "out" directory.
-#
-# If you need to re-do something that's already mentioned, just copy
-# the command and add it to the bottom of the list. E.g., if a change
-# that you made last week required touching a file and a change you
-# made today requires touching the same file, just copy the old
-# touch step and add it to the end of the list.
-#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-
-# For example:
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
-#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
-#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp
index 6bef98a..30cbb9f 100644
--- a/libs/vr/libbufferhub/buffer_client_impl.cpp
+++ b/libs/vr/libbufferhub/buffer_client_impl.cpp
@@ -10,6 +10,8 @@
: BpInterface<IBufferClient>(impl) {}
bool isValid() override;
+
+ status_t duplicate(uint64_t* outToken) override;
};
IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient");
@@ -17,6 +19,7 @@
// Transaction code
enum {
IS_VALID = IBinder::FIRST_CALL_TRANSACTION,
+ DUPLICATE,
};
bool BpBufferClient::isValid() {
@@ -38,13 +41,42 @@
}
}
+status_t BpBufferClient::duplicate(uint64_t* outToken) {
+ Parcel data, reply;
+ status_t ret =
+ data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferClient::duplicate: failed to write into parcel; errno=%d",
+ ret);
+ return ret;
+ }
+
+ ret = remote()->transact(DUPLICATE, data, &reply);
+ if (ret == NO_ERROR) {
+ *outToken = reply.readUint64();
+ return NO_ERROR;
+ } else {
+ ALOGE("BpBufferClient::duplicate: failed to transact; errno=%d", ret);
+ return ret;
+ }
+}
+
status_t BnBufferClient::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
case IS_VALID: {
CHECK_INTERFACE(IBufferClient, data, reply);
return reply->writeBool(isValid());
- } break;
+ }
+ case DUPLICATE: {
+ CHECK_INTERFACE(IBufferClient, data, reply);
+ uint64_t token = 0;
+ status_t ret = duplicate(&token);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ return reply->writeUint64(token);
+ }
default:
// Should not reach except binder defined transactions such as dumpsys
return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 8c6e7e2..73ca69b 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -5,7 +5,6 @@
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
#include <mutex>
#include <thread>
@@ -29,8 +28,8 @@
using android::dvr::BufferHubDefs::IsBufferPosted;
using android::dvr::BufferHubDefs::IsBufferReleased;
using android::dvr::BufferHubDefs::kConsumerStateMask;
+using android::dvr::BufferHubDefs::kFirstClientBitMask;
using android::dvr::BufferHubDefs::kMetadataHeaderSize;
-using android::dvr::BufferHubDefs::kProducerStateBit;
using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
using android::pdx::Status;
@@ -41,7 +40,10 @@
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
-const size_t kMaxConsumerCount = 63;
+// Maximum number of consumers for the buffer that only has one producer in the
+// test.
+const size_t kMaxConsumerCount =
+ android::dvr::BufferHubDefs::kMaxNumberOfClients - 1;
const int kPollTimeoutMs = 100;
using LibBufferHubTest = ::testing::Test;
@@ -59,19 +61,19 @@
ASSERT_TRUE(c2.get() != nullptr);
// Producer state mask is unique, i.e. 1.
- EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit);
+ EXPECT_EQ(p->client_state_mask(), kFirstClientBitMask);
// Consumer state mask cannot have producer bit on.
- EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0U);
+ EXPECT_EQ(c->client_state_mask() & kFirstClientBitMask, 0U);
// Consumer state mask must be a single, i.e. power of 2.
- EXPECT_NE(c->buffer_state_bit(), 0U);
- EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0U);
+ EXPECT_NE(c->client_state_mask(), 0U);
+ EXPECT_EQ(c->client_state_mask() & (c->client_state_mask() - 1), 0U);
// Consumer state mask cannot have producer bit on.
- EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0U);
+ EXPECT_EQ(c2->client_state_mask() & kFirstClientBitMask, 0U);
// Consumer state mask must be a single, i.e. power of 2.
- EXPECT_NE(c2->buffer_state_bit(), 0U);
- EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0U);
+ EXPECT_NE(c2->client_state_mask(), 0U);
+ EXPECT_EQ(c2->client_state_mask() & (c2->client_state_mask() - 1), 0U);
// Each consumer should have unique bit.
- EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0U);
+ EXPECT_EQ(c->client_state_mask() & c2->client_state_mask(), 0U);
// Initial state: producer not available, consumers not available.
EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
@@ -178,16 +180,16 @@
ASSERT_TRUE(p.get() != nullptr);
// It's ok to create up to kMaxConsumerCount consumer buffers.
- uint64_t buffer_state_bits = p->buffer_state_bit();
+ uint64_t client_state_masks = p->client_state_mask();
std::array<std::unique_ptr<ConsumerBuffer>, kMaxConsumerCount> cs;
for (size_t i = 0; i < kMaxConsumerCount; i++) {
cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(cs[i].get() != nullptr);
// Expect all buffers have unique state mask.
- EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
- buffer_state_bits |= cs[i]->buffer_state_bit();
+ EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
+ client_state_masks |= cs[i]->client_state_mask();
}
- EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+ EXPECT_EQ(client_state_masks, kFirstClientBitMask | kConsumerStateMask);
// The 64th creation will fail with out-of-memory error.
auto state = p->CreateConsumer();
@@ -195,14 +197,14 @@
// Release any consumer should allow us to re-create.
for (size_t i = 0; i < kMaxConsumerCount; i++) {
- buffer_state_bits &= ~cs[i]->buffer_state_bit();
+ client_state_masks &= ~cs[i]->client_state_mask();
cs[i] = nullptr;
cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(cs[i].get() != nullptr);
// The released state mask will be reused.
- EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
- buffer_state_bits |= cs[i]->buffer_state_bit();
- EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+ EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
+ client_state_masks |= cs[i]->client_state_mask();
+ EXPECT_EQ(client_state_masks, kFirstClientBitMask | kConsumerStateMask);
}
}
@@ -214,13 +216,12 @@
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
- uint64_t context;
LocalHandle fence;
// The producer buffer starts in gained state.
// Acquire, release, and gain in gained state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
EXPECT_EQ(-EALREADY, p->Gain(&fence));
@@ -233,10 +234,10 @@
EXPECT_EQ(-EBUSY, p->Gain(&fence));
// Acquire in posted state should succeed.
- EXPECT_LE(0, c->Acquire(&fence, &context));
+ EXPECT_LE(0, c->Acquire(&fence));
// Acquire, post, and gain in acquired state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
EXPECT_EQ(-EBUSY, p->Gain(&fence));
@@ -246,14 +247,14 @@
// Release, acquire, and post in released state should fail.
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
// Gain in released state should succeed.
EXPECT_EQ(0, p->Gain(&fence));
// Acquire, release, and gain in gained state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
EXPECT_EQ(-EALREADY, p->Gain(&fence));
}
@@ -329,6 +330,36 @@
EXPECT_FALSE(invalid_fence.IsValid());
}
+TEST_F(LibBufferHubTest, TestGainPostedBuffer) {
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ // The producer buffer starts in gained state. Post the buffer.
+ ASSERT_EQ(0, p->Post(LocalHandle()));
+
+ // Gain in posted state should only succeed with gain_posted_buffer = true.
+ LocalHandle invalid_fence;
+ EXPECT_EQ(-EBUSY, p->Gain(&invalid_fence, false));
+ EXPECT_EQ(0, p->Gain(&invalid_fence, true));
+}
+
+TEST_F(LibBufferHubTest, TestGainPostedBufferAsync) {
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ // The producer buffer starts in gained state. Post the buffer.
+ ASSERT_EQ(0, p->Post(LocalHandle()));
+
+ // GainAsync in posted state should only succeed with gain_posted_buffer
+ // equals true.
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+ EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence, false));
+ EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence, true));
+}
+
TEST_F(LibBufferHubTest, TestZeroConsumer) {
std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
@@ -373,7 +404,7 @@
EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
for (size_t i = 0; i < kMaxConsumerCount; i++) {
EXPECT_TRUE(
- IsBufferPosted(cs[i]->buffer_state(), cs[i]->buffer_state_bit()));
+ IsBufferPosted(cs[i]->buffer_state(), cs[i]->client_state_mask()));
EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs)));
EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
EXPECT_TRUE(IsBufferAcquired(p->buffer_state()));
@@ -491,7 +522,7 @@
EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
LocalHandle fence;
Metadata m2 = {};
- EXPECT_EQ(0, c->Acquire(&fence, &m2));
+ EXPECT_EQ(0, c->Acquire(&fence, &m2, sizeof(m2)));
EXPECT_EQ(m.field1, m2.field1);
EXPECT_EQ(m.field2, m2.field2);
EXPECT_EQ(0, c->Release(LocalHandle()));
@@ -552,11 +583,11 @@
// It is illegal to acquire metadata larger than originally requested during
// buffer allocation.
- EXPECT_NE(0, c->Acquire(&fence, &e));
+ EXPECT_NE(0, c->Acquire(&fence, &e, sizeof(e)));
// It is ok to acquire metadata smaller than originally requested during
// buffer allocation.
- EXPECT_EQ(0, c->Acquire(&fence, &sequence));
+ EXPECT_EQ(0, c->Acquire(&fence, &sequence, sizeof(sequence)));
EXPECT_EQ(m.field1, sequence);
}
@@ -678,7 +709,7 @@
std::unique_ptr<ConsumerBuffer> c1 =
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c1.get() != nullptr);
- const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
+ const uint64_t client_state_mask1 = c1->client_state_mask();
DvrNativeBufferMetadata meta;
EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
@@ -694,8 +725,8 @@
std::unique_ptr<ConsumerBuffer> c2 =
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
- const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
- EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
+ const uint64_t client_state_mask2 = c2->client_state_mask();
+ EXPECT_NE(client_state_mask1, client_state_mask2);
// The new consumer is available for acquire.
EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
@@ -710,8 +741,8 @@
std::unique_ptr<ConsumerBuffer> c3 =
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c3.get() != nullptr);
- const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
- EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
+ const uint64_t client_state_mask3 = c3->client_state_mask();
+ EXPECT_NE(client_state_mask2, client_state_mask3);
// The consumer buffer is not acquirable.
EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
@@ -859,6 +890,7 @@
int b1_id = b1->id();
EXPECT_TRUE(b1->IsValid());
EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
+ EXPECT_NE(b1->client_state_mask(), 0ULL);
auto status_or_handle = b1->Duplicate();
EXPECT_TRUE(status_or_handle);
@@ -876,18 +908,15 @@
ASSERT_TRUE(b2 != nullptr);
EXPECT_TRUE(b2->IsValid());
EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
+ EXPECT_NE(b2->client_state_mask(), 0ULL);
int b2_id = b2->id();
// These two buffer instances are based on the same physical buffer under the
// hood, so they should share the same id.
EXPECT_EQ(b1_id, b2_id);
- // We use buffer_state_bit() to tell those two instances apart.
- EXPECT_NE(b1->buffer_state_bit(), b2->buffer_state_bit());
- EXPECT_NE(b1->buffer_state_bit(), 0ULL);
- EXPECT_NE(b2->buffer_state_bit(), 0ULL);
- EXPECT_NE(b1->buffer_state_bit(), kProducerStateBit);
- EXPECT_NE(b2->buffer_state_bit(), kProducerStateBit);
+ // We use client_state_mask() to tell those two instances apart.
+ EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
// Both buffer instances should be in gained state.
EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index bc6aece..68cc766 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -114,7 +114,7 @@
id_ = new_id;
cid_ = buffer_desc.buffer_cid();
- buffer_state_bit_ = buffer_desc.buffer_state_bit();
+ client_state_mask_ = buffer_desc.client_state_mask();
// Note that here the buffer_state, fence_state and active_clients_bit_mask
// are mapped from shared memory as an atomic object. The std::atomic's
@@ -123,17 +123,17 @@
buffer_state_ = &metadata_header_->buffer_state;
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
- id(), buffer_state_->load());
+ id(), buffer_state_->load(std::memory_order_acquire));
fence_state_ = &metadata_header_->fence_state;
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
- fence_state_->load());
+ fence_state_->load(std::memory_order_acquire));
active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
ALOGD_IF(
TRACE,
"BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx64
".",
- id(), active_clients_bit_mask_->load());
+ id(), active_clients_bit_mask_->load(std::memory_order_acquire));
return 0;
}
@@ -169,7 +169,7 @@
// If ready fence is valid, we put that into the epoll set.
epoll_event event;
event.events = EPOLLIN;
- event.data.u64 = buffer_state_bit();
+ event.data.u64 = client_state_mask();
pending_fence_fd_ = new_fence.Duplicate();
if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
&event) < 0) {
@@ -182,12 +182,12 @@
}
// Set bit in fence state to indicate that there is a fence from this
// producer or consumer.
- fence_state_->fetch_or(buffer_state_bit());
+ fence_state_->fetch_or(client_state_mask());
} else {
// Unset bit in fence state to indicate that there is no fence, so that
// when consumer to acquire or producer to acquire, it knows no need to
// check fence for this buffer.
- fence_state_->fetch_and(~buffer_state_bit());
+ fence_state_->fetch_and(~client_state_mask());
}
}
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index c9d8554..8e630ec 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -38,11 +38,11 @@
// Only check producer bit and this consumer buffer's particular consumer bit.
// The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
// is not set.
- uint64_t buffer_state = buffer_state_->load();
- if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
+ if (!BufferHubDefs::IsBufferPosted(buffer_state, client_state_mask())) {
ALOGE("ConsumerBuffer::LocalAcquire: not posted, id=%d state=%" PRIx64
- " buffer_state_bit=%" PRIx64 ".",
- id(), buffer_state, buffer_state_bit());
+ " client_state_mask=%" PRIx64 ".",
+ id(), buffer_state, client_state_mask());
return -EBUSY;
}
@@ -57,14 +57,15 @@
out_meta->user_metadata_ptr = 0;
}
- uint64_t fence_state = fence_state_->load();
+ uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
// If there is an acquire fence from producer, we need to return it.
- if (fence_state & BufferHubDefs::kProducerStateBit) {
+ // The producer state bit mask is kFirstClientBitMask for now.
+ if (fence_state & BufferHubDefs::kFirstClientBitMask) {
*out_fence = shared_acquire_fence_.Duplicate();
}
// Set the consumer bit unique to this consumer.
- BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
+ BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, client_state_mask());
return 0;
}
@@ -118,7 +119,7 @@
return error;
// Check invalid state transition.
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
ALOGE("ConsumerBuffer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
id(), buffer_state);
diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
index 03f2d95..31bf79d 100644
--- a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
+++ b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
@@ -14,6 +14,10 @@
// Checks if the buffer node is valid.
virtual bool isValid() = 0;
+
+ // Duplicates the client. Token_out will be set to a new token when succeed,
+ // and not changed when failed.
+ virtual status_t duplicate(uint64_t* outToken) = 0;
};
// BnInterface for IBufferClient. Should only be created in bufferhub service.
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 282be46..09feb73 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -90,11 +90,13 @@
int cid() const { return cid_; }
// Returns the buffer buffer state.
- uint64_t buffer_state() { return buffer_state_->load(); };
+ uint64_t buffer_state() {
+ return buffer_state_->load(std::memory_order_acquire);
+ };
// A state mask which is unique to a buffer hub client among all its siblings
// sharing the same concrete graphic buffer.
- uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+ uint64_t client_state_mask() const { return client_state_mask_; }
// The following methods return settings of the first buffer. Currently,
// it is only possible to create multi-buffer BufferHubBases with the same
@@ -157,7 +159,7 @@
// Client bit mask which indicates the locations of this client object in the
// buffer_state_.
- uint64_t buffer_state_bit_{0ULL};
+ uint64_t client_state_mask_{0ULL};
IonBuffer buffer_;
IonBuffer metadata_buffer_;
};
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 49f9c3e..650da97 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -26,20 +26,21 @@
// MSB LSB
// | |
// v v
-// [P|C62|...|C1|C0]
-// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
-// Post'ed state: [1|..|0|0]
-// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
-// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
-static constexpr uint64_t kProducerStateBit = 1ULL << 63;
-static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+// [C62|...|C1|C0|P]
+// Gain'ed state: [..|0|0|0] -> Exclusively Writable.
+// Post'ed state: [..|0|0|1]
+// Acquired'ed state: [..|X|X|1] -> At least one bit is set in higher 63 bits
+// Released'ed state: [..|X|X|0] -> At least one bit is set in higher 63 bits
+static constexpr int kMaxNumberOfClients = 64;
+static constexpr uint64_t kFirstClientBitMask = 1ULL;
+static constexpr uint64_t kConsumerStateMask = ~kFirstClientBitMask;
static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
uint64_t clear_mask, uint64_t set_mask) {
uint64_t old_state;
uint64_t new_state;
do {
- old_state = buffer_state->load();
+ old_state = buffer_state->load(std::memory_order_acquire);
new_state = (old_state & ~clear_mask) | set_mask;
} while (!buffer_state->compare_exchange_weak(old_state, new_state));
}
@@ -48,23 +49,23 @@
static inline bool IsBufferPosted(uint64_t state,
uint64_t consumer_bit = kConsumerStateMask) {
- return (state & kProducerStateBit) && !(state & consumer_bit);
+ return (state & kFirstClientBitMask) && !(state & consumer_bit);
}
static inline bool IsBufferAcquired(uint64_t state) {
- return (state & kProducerStateBit) && (state & kConsumerStateMask);
+ return (state & kFirstClientBitMask) && (state & kConsumerStateMask);
}
static inline bool IsBufferReleased(uint64_t state) {
- return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+ return !(state & kFirstClientBitMask) && (state & kConsumerStateMask);
}
-static inline uint64_t FindNextClearedBit(uint64_t bits) {
+static inline uint64_t FindNextAvailableClientStateMask(uint64_t bits) {
return ~bits - (~bits & (~bits - 1));
}
static inline uint64_t FindFirstClearedBit() {
- return FindNextClearedBit(kProducerStateBit);
+ return FindNextAvailableClientStateMask(kFirstClientBitMask);
}
struct __attribute__((packed, aligned(8))) MetadataHeader {
@@ -94,13 +95,13 @@
BufferTraits() = default;
BufferTraits(const native_handle_t* buffer_handle,
const FileHandleType& metadata_handle, int id,
- uint64_t buffer_state_bit, uint64_t metadata_size,
+ uint64_t client_state_mask, uint64_t metadata_size,
uint32_t width, uint32_t height, uint32_t layer_count,
uint32_t format, uint64_t usage, uint32_t stride,
const FileHandleType& acquire_fence_fd,
const FileHandleType& release_fence_fd)
: id_(id),
- buffer_state_bit_(buffer_state_bit),
+ client_state_mask_(client_state_mask),
metadata_size_(metadata_size),
width_(width),
height_(height),
@@ -122,9 +123,9 @@
// State mask of the buffer client. Each BufferHubBuffer client backed by the
// same buffer channel has uniqued state bit among its siblings. For a
- // producer buffer the bit must be kProducerStateBit; for a consumer the bit
+ // producer buffer the bit must be kFirstClientBitMask; for a consumer the bit
// must be one of the kConsumerStateMask.
- uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+ uint64_t client_state_mask() const { return client_state_mask_; }
uint64_t metadata_size() const { return metadata_size_; }
uint32_t width() { return width_; }
@@ -148,7 +149,7 @@
private:
// BufferHub specific traits.
int id_ = -1;
- uint64_t buffer_state_bit_;
+ uint64_t client_state_mask_;
uint64_t metadata_size_;
// Traits for a GraphicBuffer.
@@ -169,10 +170,10 @@
FileHandleType acquire_fence_fd_;
FileHandleType release_fence_fd_;
- PDX_SERIALIZABLE_MEMBERS(BufferTraits<FileHandleType>, id_, buffer_state_bit_,
- metadata_size_, stride_, width_, height_,
- layer_count_, format_, usage_, buffer_handle_,
- metadata_handle_, acquire_fence_fd_,
+ PDX_SERIALIZABLE_MEMBERS(BufferTraits<FileHandleType>, id_,
+ client_state_mask_, metadata_size_, stride_, width_,
+ height_, layer_count_, format_, usage_,
+ buffer_handle_, metadata_handle_, acquire_fence_fd_,
release_fence_fd_);
BufferTraits(const BufferTraits&) = delete;
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index 7330aa1..5ff4e00 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -99,12 +99,12 @@
public:
BufferDescription() = default;
BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id,
- int buffer_cid, uint64_t buffer_state_bit,
+ int buffer_cid, uint64_t client_state_mask,
const FileHandleType& acquire_fence_fd,
const FileHandleType& release_fence_fd)
: id_(id),
buffer_cid_(buffer_cid),
- buffer_state_bit_(buffer_state_bit),
+ client_state_mask_(client_state_mask),
buffer_(buffer, id),
metadata_(metadata, id),
acquire_fence_fd_(acquire_fence_fd.Borrow()),
@@ -122,10 +122,8 @@
int buffer_cid() const { return buffer_cid_; }
// State mask of the buffer client. Each BufferHub client backed by the
- // same buffer channel has uniqued state bit among its siblings. For a
- // producer buffer the bit must be kProducerStateBit; for a consumer the bit
- // must be one of the kConsumerStateMask.
- uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+ // same buffer channel has uniqued state bit among its siblings.
+ uint64_t client_state_mask() const { return client_state_mask_; }
FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
FileHandleType take_release_fence() { return std::move(release_fence_fd_); }
@@ -135,7 +133,7 @@
private:
int id_{-1};
int buffer_cid_{-1};
- uint64_t buffer_state_bit_{0};
+ uint64_t client_state_mask_{0};
// Two IonBuffers: one for the graphic buffer and one for metadata.
NativeBufferHandle<FileHandleType> buffer_;
NativeBufferHandle<FileHandleType> metadata_;
@@ -145,7 +143,7 @@
FileHandleType release_fence_fd_;
PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_, buffer_cid_,
- buffer_state_bit_, buffer_, metadata_,
+ client_state_mask_, buffer_, metadata_,
acquire_fence_fd_, release_fence_fd_);
BufferDescription(const BufferDescription&) = delete;
@@ -314,7 +312,6 @@
kOpProducerGain,
kOpConsumerAcquire,
kOpConsumerRelease,
- kOpProducerBufferDetach,
kOpConsumerBufferDetach,
kOpCreateProducerQueue,
kOpCreateConsumerQueue,
@@ -344,8 +341,6 @@
PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, LocalFence(Void));
PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
void(LocalFence release_fence));
- PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
- LocalChannelHandle(Void));
// Detaches a ConsumerBuffer from an existing producer/consumer set. Can only
// be called when the consumer is the only consumer and it has exclusive
diff --git a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
index 2044c53..7349779 100644
--- a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
@@ -45,15 +45,6 @@
// Returns zero on success, or a negative errno code otherwise.
int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
- // Attempt to retrieve a post event from buffer hub. If successful,
- // |ready_fence| is set to a fence to wait on until the buffer is ready. This
- // call will only succeed after the fd is signaled. This returns zero or a
- // negative unix error code.
- template <typename Meta>
- int Acquire(LocalHandle* ready_fence, Meta* meta) {
- return Acquire(ready_fence, meta, sizeof(*meta));
- }
-
// Asynchronously acquires a bufer.
int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
diff --git a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
index d2d4d1e..2761416 100644
--- a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
@@ -52,11 +52,14 @@
// Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
// must be waited on before using the buffer. If it is not valid then the
- // buffer is free for immediate use. This call will only succeed if the buffer
- // is in the released state.
- // This returns zero or a negative unix error code.
- int Gain(LocalHandle* release_fence);
- int GainAsync();
+ // buffer is free for immediate use. This call will succeed if the buffer
+ // is in the released state, or in posted state and gain_posted_buffer is
+ // true.
+ //
+ // @param release_fence output fence.
+ // @param gain_posted_buffer whether to gain posted buffer or not.
+ // @return This returns zero or a negative unix error code.
+ int Gain(LocalHandle* release_fence, bool gain_posted_buffer = false);
// Asynchronously marks a released buffer as gained. This method is similar to
// the synchronous version above, except that it does not wait for BufferHub
@@ -64,7 +67,13 @@
// the underlying message, no error is returned if this method is called when
// the buffer is in an incorrect state. Returns zero if sending the message
// succeeded, or a negative errno code if local error check fails.
- int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ // TODO(b/112007999): gain_posted_buffer true is only used to prevent
+ // libdvrtracking from starving when there are non-responding clients. This
+ // gain_posted_buffer param can be removed once libdvrtracking start to use
+ // the new AHardwareBuffer API.
+ int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence,
+ bool gain_posted_buffer = false);
+ int GainAsync();
// Detaches a ProducerBuffer from an existing producer/consumer set. Can only
// be called when a producer buffer has exclusive access to the buffer (i.e.
@@ -92,7 +101,8 @@
explicit ProducerBuffer(LocalChannelHandle channel);
// Local state transition helpers.
- int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence,
+ bool gain_posted_buffer = false);
int LocalPost(const DvrNativeBufferMetadata* meta,
const LocalHandle& ready_fence);
};
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 7b6f77a..f36e169 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -80,7 +80,7 @@
return error;
// Check invalid state transition.
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
ALOGE("ProducerBuffer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
id(), buffer_state);
@@ -102,8 +102,9 @@
return error;
// Set the producer bit atomically to transit into posted state.
+ // The producer state bit mask is kFirstClientBitMask for now.
BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
- BufferHubDefs::kProducerStateBit);
+ BufferHubDefs::kFirstClientBitMask);
return 0;
}
@@ -134,21 +135,22 @@
}
int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
- LocalHandle* out_fence) {
- uint64_t buffer_state = buffer_state_->load();
+ LocalHandle* out_fence, bool gain_posted_buffer) {
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
id(), buffer_state);
if (!out_meta)
return -EINVAL;
- if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
- if (BufferHubDefs::IsBufferGained(buffer_state)) {
- // We don't want to log error when gaining a newly allocated
- // buffer.
- ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
- return -EALREADY;
- }
+ if (BufferHubDefs::IsBufferGained(buffer_state)) {
+ // We don't want to log error when gaining a newly allocated
+ // buffer.
+ ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
+ return -EALREADY;
+ }
+ if (BufferHubDefs::IsBufferAcquired(buffer_state) ||
+ (BufferHubDefs::IsBufferPosted(buffer_state) && !gain_posted_buffer)) {
ALOGE("ProducerBuffer::LocalGain: not released id=%d state=%" PRIx64 ".",
id(), buffer_state);
return -EBUSY;
@@ -167,7 +169,7 @@
out_meta->user_metadata_ptr = 0;
}
- uint64_t fence_state = fence_state_->load();
+ uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
// If there is an release fence from consumer, we need to return it.
if (fence_state & BufferHubDefs::kConsumerStateMask) {
*out_fence = shared_release_fence_.Duplicate();
@@ -180,11 +182,11 @@
return 0;
}
-int ProducerBuffer::Gain(LocalHandle* release_fence) {
+int ProducerBuffer::Gain(LocalHandle* release_fence, bool gain_posted_buffer) {
ATRACE_NAME("ProducerBuffer::Gain");
DvrNativeBufferMetadata meta;
- if (const int error = LocalGain(&meta, release_fence))
+ if (const int error = LocalGain(&meta, release_fence, gain_posted_buffer))
return error;
auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
@@ -194,10 +196,11 @@
}
int ProducerBuffer::GainAsync(DvrNativeBufferMetadata* out_meta,
- LocalHandle* release_fence) {
+ LocalHandle* release_fence,
+ bool gain_posted_buffer) {
ATRACE_NAME("ProducerBuffer::GainAsync");
- if (const int error = LocalGain(out_meta, release_fence))
+ if (const int error = LocalGain(out_meta, release_fence, gain_posted_buffer))
return error;
return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
@@ -226,7 +229,9 @@
ALOGW("ProducerBuffer::Detach: not supported operation during migration");
return {};
- uint64_t buffer_state = buffer_state_->load();
+ // TODO(b/112338294) Keep here for reference. Remove it after new logic is
+ // written.
+ /* uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
// Can only detach a ProducerBuffer when it's in gained state.
ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx64
@@ -240,7 +245,7 @@
ALOGE_IF(!status,
"ProducerBuffer::Detach: Failed to detach buffer (id=%d): %s.", id(),
status.GetErrorMessage().c_str());
- return status;
+ return status; */
}
} // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index e1c1aa9..f7942d0 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -69,7 +69,7 @@
.data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}};
ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
if (ret < 0) {
- ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
+ ALOGE("%s: Failed to add event fd to epoll set: %s", __FUNCTION__,
strerror(-ret));
}
}
@@ -77,7 +77,7 @@
Status<void> BufferHubQueue::ImportQueue() {
auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
if (!status) {
- ALOGE("BufferHubQueue::ImportQueue: Failed to import queue: %s",
+ ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return ErrorStatus(status.error());
} else {
@@ -136,9 +136,7 @@
consumer_queue->GetChannel()->TakeChannelParcelable());
if (!queue_parcelable.IsValid()) {
- ALOGE(
- "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create "
- "consumer queue parcelable.");
+ ALOGE("%s: Failed to create consumer queue parcelable.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
@@ -169,8 +167,7 @@
}
if (ret < 0 && ret != -EINTR) {
- ALOGE("BufferHubQueue::WaitForBuffers: Failed to wait for buffers: %s",
- strerror(-ret));
+ ALOGE("%s: Failed to wait for buffers: %s", __FUNCTION__, strerror(-ret));
return false;
}
@@ -264,14 +261,14 @@
// wait will be tried again to acquire the newly imported buffer.
auto buffer_status = OnBufferAllocated();
if (!buffer_status) {
- ALOGE("BufferHubQueue::HandleQueueEvent: Failed to import buffer: %s",
+ ALOGE("%s: Failed to import buffer: %s", __FUNCTION__,
buffer_status.GetErrorMessage().c_str());
}
} else if (events & EPOLLHUP) {
- ALOGD_IF(TRACE, "BufferHubQueue::HandleQueueEvent: hang up event!");
+ ALOGD_IF(TRACE, "%s: hang up event!", __FUNCTION__);
hung_up_ = true;
} else {
- ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%x", events);
+ ALOGW("%s: Unknown epoll events=%x", __FUNCTION__, events);
}
return {};
@@ -279,12 +276,11 @@
Status<void> BufferHubQueue::AddBuffer(
const std::shared_ptr<BufferHubBase>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu",
- buffer->id(), slot);
+ ALOGD_IF(TRACE, "%s: buffer_id=%d slot=%zu", __FUNCTION__, buffer->id(),
+ slot);
if (is_full()) {
- ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu",
- capacity_);
+ ALOGE("%s: queue is at maximum capacity: %zu", __FUNCTION__, capacity_);
return ErrorStatus(E2BIG);
}
@@ -303,7 +299,7 @@
const int ret =
epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
if (ret < 0) {
- ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
+ ALOGE("%s: Failed to add buffer to epoll set: %s", __FUNCTION__,
strerror(-ret));
return ErrorStatus(-ret);
}
@@ -315,17 +311,15 @@
}
Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
+ ALOGD_IF(TRACE, "%s: slot=%zu", __FUNCTION__, slot);
if (buffers_[slot]) {
for (const auto& event_source : buffers_[slot]->GetEventSources()) {
const int ret =
epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
if (ret < 0) {
- ALOGE(
- "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
- "set: %s",
- strerror(-ret));
+ ALOGE("%s: Failed to remove buffer from epoll set: %s", __FUNCTION__,
+ strerror(-ret));
return ErrorStatus(-ret);
}
}
@@ -343,6 +337,15 @@
Status<void> BufferHubQueue::Enqueue(Entry entry) {
if (!is_full()) {
+ // Find and remove the enqueued buffer from unavailable_buffers_slot if
+ // exist.
+ auto enqueued_buffer_iter = std::find_if(
+ unavailable_buffers_slot_.begin(), unavailable_buffers_slot_.end(),
+ [&entry](size_t slot) -> bool { return slot == entry.slot; });
+ if (enqueued_buffer_iter != unavailable_buffers_slot_.end()) {
+ unavailable_buffers_slot_.erase(enqueued_buffer_iter);
+ }
+
available_buffers_.push(std::move(entry));
// Trigger OnBufferAvailable callback if registered.
@@ -351,17 +354,16 @@
return {};
} else {
- ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
+ ALOGE("%s: Buffer queue is full!", __FUNCTION__);
return ErrorStatus(E2BIG);
}
}
Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout,
size_t* slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
- timeout);
+ ALOGD_IF(TRACE, "%s: count=%zu, timeout=%d", __FUNCTION__, count(), timeout);
- PDX_TRACE_FORMAT("BufferHubQueue::Dequeue|count=%zu|", count());
+ PDX_TRACE_FORMAT("%s|count=%zu|", __FUNCTION__, count());
if (count() == 0) {
if (!WaitForBuffers(timeout))
@@ -376,6 +378,7 @@
*slot = entry.slot;
available_buffers_.pop();
+ unavailable_buffers_slot_.push_back(*slot);
return {std::move(buffer)};
}
@@ -564,7 +567,7 @@
auto status =
InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
if (!status) {
- ALOGE("ProducerQueue::RemoveBuffer: Failed to remove producer buffer: %s",
+ ALOGE("%s: Failed to remove producer buffer: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return status.error_status();
}
@@ -580,31 +583,81 @@
pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* release_fence) {
+ pdx::LocalHandle* release_fence, bool gain_posted_buffer) {
ATRACE_NAME("ProducerQueue::Dequeue");
if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
- ALOGE("ProducerQueue::Dequeue: Invalid parameter.");
+ ALOGE("%s: Invalid parameter.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
- auto status = BufferHubQueue::Dequeue(timeout, slot);
- if (!status)
- return status.error_status();
-
- auto buffer = std::static_pointer_cast<BufferProducer>(status.take());
- const int ret = buffer->GainAsync(out_meta, release_fence);
+ std::shared_ptr<BufferProducer> buffer;
+ Status<std::shared_ptr<BufferHubBase>> dequeue_status =
+ BufferHubQueue::Dequeue(timeout, slot);
+ if (dequeue_status.ok()) {
+ buffer = std::static_pointer_cast<BufferProducer>(dequeue_status.take());
+ } else {
+ if (gain_posted_buffer) {
+ Status<std::shared_ptr<BufferProducer>> dequeue_unacquired_status =
+ ProducerQueue::DequeueUnacquiredBuffer(slot);
+ if (!dequeue_unacquired_status.ok()) {
+ ALOGE("%s: DequeueUnacquiredBuffer returned error: %d", __FUNCTION__,
+ dequeue_unacquired_status.error());
+ return dequeue_unacquired_status.error_status();
+ }
+ buffer = dequeue_unacquired_status.take();
+ } else {
+ return dequeue_status.error_status();
+ }
+ }
+ const int ret =
+ buffer->GainAsync(out_meta, release_fence, gain_posted_buffer);
if (ret < 0 && ret != -EALREADY)
return ErrorStatus(-ret);
return {std::move(buffer)};
}
+Status<std::shared_ptr<BufferProducer>> ProducerQueue::DequeueUnacquiredBuffer(
+ size_t* slot) {
+ if (unavailable_buffers_slot_.size() < 1) {
+ ALOGE(
+ "%s: Failed to dequeue un-acquired buffer. All buffer(s) are in "
+ "acquired state if exist.",
+ __FUNCTION__);
+ return ErrorStatus(ENOMEM);
+ }
+
+ // Find the first buffer that is not in acquired state from
+ // unavailable_buffers_slot_.
+ for (auto iter = unavailable_buffers_slot_.begin();
+ iter != unavailable_buffers_slot_.end(); iter++) {
+ std::shared_ptr<BufferProducer> buffer = ProducerQueue::GetBuffer(*iter);
+ if (buffer == nullptr) {
+ ALOGE("%s failed. Buffer slot %d is null.", __FUNCTION__,
+ static_cast<int>(*slot));
+ return ErrorStatus(EIO);
+ }
+ if (!BufferHubDefs::IsBufferAcquired(buffer->buffer_state())) {
+ *slot = *iter;
+ unavailable_buffers_slot_.erase(iter);
+ unavailable_buffers_slot_.push_back(*slot);
+ ALOGD("%s: Producer queue dequeue unacquired buffer in slot %d",
+ __FUNCTION__, static_cast<int>(*slot));
+ return {std::move(buffer)};
+ }
+ }
+ ALOGE(
+ "%s: Failed to dequeue un-acquired buffer. No un-acquired buffer exist.",
+ __FUNCTION__);
+ return ErrorStatus(EBUSY);
+}
+
pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
if (capacity() != 0) {
ALOGE(
- "ProducerQueue::TakeAsParcelable: producer queue can only be taken out"
- " as a parcelable when empty. Current queue capacity: %zu",
- capacity());
+ "%s: producer queue can only be taken out as a parcelable when empty. "
+ "Current queue capacity: %zu",
+ __FUNCTION__, capacity());
return ErrorStatus(EINVAL);
}
@@ -628,17 +681,16 @@
: BufferHubQueue(std::move(handle)) {
auto status = ImportQueue();
if (!status) {
- ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
+ ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
Close(-status.error());
}
auto import_status = ImportBuffers();
if (import_status) {
- ALOGI("ConsumerQueue::ConsumerQueue: Imported %zu buffers.",
- import_status.get());
+ ALOGI("%s: Imported %zu buffers.", __FUNCTION__, import_status.get());
} else {
- ALOGE("ConsumerQueue::ConsumerQueue: Failed to import buffers: %s",
+ ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
import_status.GetErrorMessage().c_str());
}
}
@@ -647,14 +699,11 @@
auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
if (!status) {
if (status.error() == EBADR) {
- ALOGI(
- "ConsumerQueue::ImportBuffers: Queue is silent, no buffers "
- "imported.");
+ ALOGI("%s: Queue is silent, no buffers imported.", __FUNCTION__);
return {0};
} else {
- ALOGE(
- "ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
- status.GetErrorMessage().c_str());
+ ALOGE("%s: Failed to import consumer buffer: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
return status.error_status();
}
}
@@ -665,13 +714,13 @@
auto buffer_handle_slots = status.take();
for (auto& buffer_handle_slot : buffer_handle_slots) {
- ALOGD_IF(TRACE, "ConsumerQueue::ImportBuffers: buffer_handle=%d",
+ ALOGD_IF(TRACE, ": buffer_handle=%d", __FUNCTION__,
buffer_handle_slot.first.value());
std::unique_ptr<BufferConsumer> buffer_consumer =
BufferConsumer::Import(std::move(buffer_handle_slot.first));
if (!buffer_consumer) {
- ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
+ ALOGE("%s: Failed to import buffer: slot=%zu", __FUNCTION__,
buffer_handle_slot.second);
last_error = ErrorStatus(EPIPE);
continue;
@@ -680,7 +729,7 @@
auto add_status =
AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
if (!add_status) {
- ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s",
+ ALOGE("%s: Failed to add buffer: %s", __FUNCTION__,
add_status.GetErrorMessage().c_str());
last_error = add_status;
} else {
@@ -696,8 +745,8 @@
Status<void> ConsumerQueue::AddBuffer(
const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
- id(), buffer->id(), slot);
+ ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu", __FUNCTION__, id(),
+ buffer->id(), slot);
return BufferHubQueue::AddBuffer(buffer, slot);
}
@@ -706,9 +755,9 @@
LocalHandle* acquire_fence) {
if (user_metadata_size != user_metadata_size_) {
ALOGE(
- "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
- "does not match metadata size (%zu) for the queue.",
- user_metadata_size, user_metadata_size_);
+ "%s: Metadata size (%zu) for the dequeuing buffer does not match "
+ "metadata size (%zu) for the queue.",
+ __FUNCTION__, user_metadata_size, user_metadata_size_);
return ErrorStatus(EINVAL);
}
@@ -723,7 +772,7 @@
if (metadata_src) {
memcpy(meta, metadata_src, user_metadata_size);
} else {
- ALOGW("ConsumerQueue::Dequeue: no user-defined metadata.");
+ ALOGW("%s: no user-defined metadata.", __FUNCTION__);
}
}
@@ -735,7 +784,7 @@
pdx::LocalHandle* acquire_fence) {
ATRACE_NAME("ConsumerQueue::Dequeue");
if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
- ALOGE("ConsumerQueue::Dequeue: Invalid parameter.");
+ ALOGE("%s: Invalid parameter.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
@@ -752,19 +801,18 @@
}
Status<void> ConsumerQueue::OnBufferAllocated() {
- ALOGD_IF(TRACE, "ConsumerQueue::OnBufferAllocated: queue_id=%d", id());
+ ALOGD_IF(TRACE, "%s: queue_id=%d", __FUNCTION__, id());
auto status = ImportBuffers();
if (!status) {
- ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
+ ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return ErrorStatus(status.error());
} else if (status.get() == 0) {
- ALOGW("ConsumerQueue::OnBufferAllocated: No new buffers allocated!");
+ ALOGW("%s: No new buffers allocated!", __FUNCTION__);
return ErrorStatus(ENOBUFS);
} else {
- ALOGD_IF(TRACE,
- "ConsumerQueue::OnBufferAllocated: Imported %zu consumer buffers.",
+ ALOGD_IF(TRACE, "%s: Imported %zu consumer buffers.", __FUNCTION__,
status.get());
return {};
}
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index c69002d..def7c6b 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -57,10 +57,10 @@
uint32_t default_width() const { return default_width_; }
// Returns the default buffer height of this buffer queue.
- uint32_t default_height() const { return static_cast<uint32_t>(default_height_); }
+ uint32_t default_height() const { return default_height_; }
// Returns the default buffer format of this buffer queue.
- uint32_t default_format() const { return static_cast<uint32_t>(default_format_); }
+ uint32_t default_format() const { return default_format_; }
// Creates a new consumer in handle form for immediate transport over RPC.
pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
@@ -208,6 +208,14 @@
// Size of the metadata that buffers in this queue cary.
size_t user_metadata_size_{0};
+ // Buffers and related data that are available for dequeue.
+ std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
+ available_buffers_;
+
+ // Slot of the buffers that are not available for normal dequeue. For example,
+ // the slot of posted or acquired buffers in the perspective of a producer.
+ std::vector<size_t> unavailable_buffers_slot_;
+
private:
void Initialize();
@@ -252,10 +260,6 @@
// queue regardless of its queue position or presence in the ring buffer.
std::array<std::shared_ptr<BufferHubBase>, kMaxQueueCapacity> buffers_;
- // Buffers and related data that are available for dequeue.
- std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
- available_buffers_;
-
// Keeps track with how many buffers have been added into the queue.
size_t capacity_{0};
@@ -349,11 +353,30 @@
// Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
// and caller should call Post() once it's done writing to release the buffer
// to the consumer side.
+ // @return a buffer in gained state, which was originally in released state.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
int timeout, size_t* slot, pdx::LocalHandle* release_fence);
+
+ // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
+ // and caller should call Post() once it's done writing to release the buffer
+ // to the consumer side.
+ //
+ // @param timeout to dequeue a buffer.
+ // @param slot is the slot of the output BufferProducer.
+ // @param release_fence for gaining a buffer.
+ // @param out_meta metadata of the output buffer.
+ // @param gain_posted_buffer whether to gain posted buffer if no released
+ // buffer is available to gain.
+ // @return a buffer in gained state, which was originally in released state if
+ // gain_posted_buffer is false, or in posted/released state if
+ // gain_posted_buffer is true.
+ // TODO(b/112007999): gain_posted_buffer true is only used to prevent
+ // libdvrtracking from starving when there are non-responding clients. This
+ // gain_posted_buffer param can be removed once libdvrtracking start to use
+ // the new AHardwareBuffer API.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* release_fence);
+ pdx::LocalHandle* release_fence, bool gain_posted_buffer = false);
// Enqueues a producer buffer in the queue.
pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer,
@@ -374,6 +397,16 @@
// arguments as the constructors.
explicit ProducerQueue(pdx::LocalChannelHandle handle);
ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
+
+ // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
+ // and caller should call Post() once it's done writing to release the buffer
+ // to the consumer side.
+ //
+ // @param slot the slot of the returned buffer.
+ // @return a buffer in gained state, which was originally in posted state or
+ // released state.
+ pdx::Status<std::shared_ptr<BufferProducer>> DequeueUnacquiredBuffer(
+ size_t* slot);
};
class ConsumerQueue : public BufferHubQueue {
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 046df54..c58f55f 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -1,5 +1,6 @@
#include <base/logging.h>
#include <binder/Parcel.h>
+#include <dvr/dvr_api.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
@@ -122,6 +123,147 @@
}
}
+TEST_F(BufferHubQueueTest,
+ TestDequeuePostedBufferIfNoAvailableReleasedBuffer_withBufferConsumer) {
+ ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+ // Allocate 3 buffers to use.
+ const size_t test_queue_capacity = 3;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ AllocateBuffer();
+ }
+ EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
+
+ size_t producer_slot, consumer_slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer posts 2 buffers and remember their posted sequence.
+ std::deque<size_t> posted_slots;
+ for (int64_t i = 0; i < 2; i++) {
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // Producer should not be gaining posted buffer when there are still
+ // available buffers to gain.
+ auto found_iter =
+ std::find(posted_slots.begin(), posted_slots.end(), producer_slot);
+ EXPECT_EQ(found_iter, posted_slots.end());
+ posted_slots.push_back(producer_slot);
+
+ // Producer posts the buffer.
+ mi.index = i;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+ }
+
+ // Consumer acquires one buffer.
+ auto c1_status =
+ consumer_queue_->Dequeue(kTimeoutMs, &consumer_slot, &mo, &fence);
+ EXPECT_TRUE(c1_status.ok());
+ auto c1 = c1_status.take();
+ ASSERT_NE(c1, nullptr);
+ // Consumer should get the oldest posted buffer. No checks here.
+ // posted_slots[0] should be in acquired state now.
+ EXPECT_EQ(mo.index, 0);
+ // Consumer releases the buffer.
+ EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
+ // posted_slots[0] should be in released state now.
+
+ // Producer gain and post 2 buffers.
+ for (int64_t i = 0; i < 2; i++) {
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the one in released state or the one haven't
+ // been use.
+ EXPECT_NE(posted_slots[1], producer_slot);
+
+ mi.index = i + 2;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+ }
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the oldest posted buffer.
+ EXPECT_EQ(posted_slots[1], producer_slot);
+
+ // Producer posts the buffer.
+ mi.index = 4;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+}
+
+TEST_F(BufferHubQueueTest,
+ TestDequeuePostedBufferIfNoAvailableReleasedBuffer_noBufferConsumer) {
+ ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+ // Allocate 4 buffers to use.
+ const size_t test_queue_capacity = 4;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ AllocateBuffer();
+ }
+ EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
+
+ // Post all allowed buffers and remember their posted sequence.
+ std::deque<size_t> posted_slots;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ size_t slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // Producer should not be gaining posted buffer when there are still
+ // available buffers to gain.
+ auto found_iter = std::find(posted_slots.begin(), posted_slots.end(), slot);
+ EXPECT_EQ(found_iter, posted_slots.end());
+ posted_slots.push_back(slot);
+
+ // Producer posts the buffer.
+ mi.index = i;
+ EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+ }
+
+ // Gain posted buffers in sequence.
+ const int64_t nb_dequeue_all_times = 2;
+ for (int j = 0; j < nb_dequeue_all_times; ++j) {
+ for (int i = 0; i < test_queue_capacity; ++i) {
+ size_t slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the oldest posted buffer.
+ EXPECT_EQ(posted_slots[i], slot);
+
+ // Producer posts the buffer.
+ mi.index = i + test_queue_capacity * (j + 1);
+ EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+ }
+ }
+}
+
TEST_F(BufferHubQueueTest, TestProducerConsumer) {
const size_t kBufferCount = 16;
size_t slot;
@@ -245,8 +387,8 @@
for (size_t i = 0; i < kBufferCount; i++) {
Entry* entry = &buffers[i];
- auto producer_status = producer_queue_->Dequeue(
- kTimeoutMs, &entry->slot, &mo, &entry->fence);
+ auto producer_status =
+ producer_queue_->Dequeue(kTimeoutMs, &entry->slot, &mo, &entry->fence);
ASSERT_TRUE(producer_status.ok());
entry->buffer = producer_status.take();
ASSERT_NE(nullptr, entry->buffer);
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index 68b8dd7..3769162 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -318,13 +318,7 @@
PDX_TRACE_NAME("Message::ReplyFileHandle");
auto svc = service_.lock();
if (!replied_ && svc) {
- Status<void> ret;
-
- if (handle)
- ret = svc->endpoint()->MessageReply(this, handle.Get());
- else
- ret = svc->endpoint()->MessageReply(this, handle.Get());
-
+ Status<void> ret = svc->endpoint()->MessageReply(this, handle.Get());
replied_ = ret.ok();
return ret;
} else {
diff --git a/libs/vr/libpdx/status_tests.cpp b/libs/vr/libpdx/status_tests.cpp
index d4e697c..772c529 100644
--- a/libs/vr/libpdx/status_tests.cpp
+++ b/libs/vr/libpdx/status_tests.cpp
@@ -2,6 +2,8 @@
#include <gtest/gtest.h>
+#include <memory>
+
using android::pdx::ErrorStatus;
using android::pdx::Status;
@@ -84,8 +86,8 @@
Status<std::unique_ptr<int>> status1;
Status<std::unique_ptr<int>> status2;
- status1 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{11}}};
- status2 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{12}}};
+ status1 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{11})};
+ status2 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{12})};
EXPECT_FALSE(status1.empty());
EXPECT_FALSE(status2.empty());
EXPECT_TRUE(status1.ok());
@@ -114,7 +116,7 @@
}
TEST(Status, Take) {
- Status<std::unique_ptr<int>> status{std::unique_ptr<int>{new int{123}}};
+ Status<std::unique_ptr<int>> status{std::make_unique<int>(int{123})};
EXPECT_FALSE(status.empty());
EXPECT_NE(nullptr, status.get());
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index d500278..9a1d2e5 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -34,4 +34,7 @@
],
cppflags: ["-std=c++1z"],
name: "vrflinger_test",
+
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 6f792ec..e27f233 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -36,23 +36,12 @@
#include "egl_platform_entries.h"
#include "egl_trace.h"
#include "egldefs.h"
+#include <EGL/eglext_angle.h>
extern "C" {
android_namespace_t* android_get_exported_namespace(const char*);
// TODO(ianelliott@): Get this from an ANGLE header:
- typedef enum ANGLEPreference {
- ANGLE_NO_PREFERENCE = 0,
- ANGLE_PREFER_NATIVE = 1,
- ANGLE_PREFER_ANGLE = 2,
- } ANGLEPreference;
-
- // TODO(ianelliott@): Get this from an ANGLE header:
- typedef bool (*fpANGLEUseForApplication)(const char* appName, const char* deviceMfr,
- const char* deviceModel, ANGLEPreference developerOption,
- ANGLEPreference appPreference);
-
- // TODO(ianelliott@): Get this from an ANGLE header:
typedef bool (*fpANGLEGetUtilityAPI)(unsigned int* versionToUse);
// TODO(ianelliott@): Get this from an ANGLE header:
@@ -274,10 +263,24 @@
return (void*)hnd;
}
-void Loader::close(void* driver)
+void Loader::close(egl_connection_t* cnx)
{
- driver_t* hnd = (driver_t*)driver;
+ driver_t* hnd = (driver_t*) cnx->dso;
delete hnd;
+ cnx->dso = nullptr;
+
+ if (cnx->featureSo) {
+ dlclose(cnx->featureSo);
+ cnx->featureSo = nullptr;
+ }
+
+ cnx->angleDecided = false;
+ cnx->useAngle = false;
+
+ if (cnx->vendorEGL) {
+ dlclose(cnx->vendorEGL);
+ cnx->vendorEGL = nullptr;
+ }
}
void Loader::init_api(void* dso,
@@ -507,16 +510,56 @@
return nullptr;
}
-static ANGLEPreference getAnglePref(const char* app_pref) {
- if (app_pref == nullptr)
- return ANGLE_NO_PREFERENCE;
- if (strcmp(app_pref, "angle") == 0) {
- return ANGLE_PREFER_ANGLE;
- } else if (strcmp(app_pref, "native") == 0) {
- return ANGLE_PREFER_NATIVE;
+static bool check_angle_rules(void* so, const char* app_name) {
+ bool use_angle = false;
+ const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
+ const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
+ const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
+
+ std::string app_name_str = app_name ? app_name : "";
+ char manufacturer[PROPERTY_VALUE_MAX];
+ char model[PROPERTY_VALUE_MAX];
+ property_get("ro.product.manufacturer", manufacturer, "UNSET");
+ property_get("ro.product.model", model, "UNSET");
+
+ fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
+ (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
+
+ if (ANGLEGetUtilityAPI) {
+
+ // Negotiate the interface version by requesting most recent known to the platform
+ unsigned int versionToUse = 1;
+ if ((ANGLEGetUtilityAPI)(&versionToUse)) {
+
+ // Add and remove versions below as needed
+ switch(versionToUse) {
+ case 1: {
+ ALOGV("Using version 1 of ANGLE opt-in/out logic interface");
+ fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
+ (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
+
+ if (AndroidUseANGLEForApplication) {
+ use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
+ rules_length, app_name_str.c_str(),
+ manufacturer, model);
+ } else {
+ ALOGW("Cannot find AndroidUseANGLEForApplication in ANGLE feature-support library");
+ }
+ }
+ break;
+ default:
+ ALOGW("Cannot find supported version of ANGLE feature-support library, found version %u", versionToUse);
+ }
+ } else {
+ ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, requested version %u", versionToUse);
+ }
+ } else {
+ ALOGW("Cannot find ANGLEGetUtilityAPI function");
}
- return ANGLE_NO_PREFERENCE;
+
+ ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
+ return use_angle;
}
static void* load_angle(const char* kind, android_namespace_t* ns, egl_connection_t* cnx) {
@@ -524,86 +567,42 @@
if (strcmp(kind, "EGL") != 0 && strcmp(kind, "GLESv2") != 0 && strcmp(kind, "GLESv1_CM") != 0)
return nullptr;
- void* so = nullptr;
std::string name;
char prop[PROPERTY_VALUE_MAX];
- const char* app_name = android_getAngleAppName();
- const char* app_pref = android_getAngleAppPref();
- bool developer_opt_in = android_getAngleDeveloperOptIn();
- const int rules_fd = android_getAngleRulesFd();
- const long rules_offset = android_getAngleRulesOffset();
- const long rules_length = android_getAngleRulesLength();
+ const char* app_name = android::GraphicsEnv::getInstance().getAngleAppName();
+ bool developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
// Determine whether or not to use ANGLE:
- ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
- bool use_angle = (developer_option == ANGLE_PREFER_ANGLE);
+ bool use_angle = developer_opt_in;
if (use_angle) {
ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+ } else if (cnx->angleDecided) {
+ use_angle = cnx->useAngle;
} else {
// The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily
// load ANGLE and call the updatable opt-in/out logic:
- std::string app_name_str = app_name ? app_name : "";
- char manufacturer[PROPERTY_VALUE_MAX];
- char model[PROPERTY_VALUE_MAX];
- property_get("ro.product.manufacturer", manufacturer, "UNSET");
- property_get("ro.product.model", model, "UNSET");
- so = load_angle_from_namespace("feature_support", ns);
- if (so) {
- ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
- bool use_version0_API = false;
- bool use_version1_API = false;
- fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
- (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
- if (ANGLEGetUtilityAPI) {
- unsigned int versionToUse = 1;
- if ((ANGLEGetUtilityAPI)(&versionToUse)) {
- if (versionToUse == 1) {
- use_version1_API = true;
- } else {
- use_version0_API = true;
- }
- }
- } else {
- use_version0_API = true;
- }
- if (use_version1_API) {
- // Use the new version 1 API to determine if the
- // application should use the ANGLE or the native driver.
- fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
- (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
- if (AndroidUseANGLEForApplication) {
- use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
- rules_length, app_name_str.c_str(),
- manufacturer, model);
- } else {
- ALOGW("Cannot find AndroidUseANGLEForApplication in library");
- }
- } else if (use_version0_API) {
- // Use the old version 0 API to determine if the
- // application should use the ANGLE or the native driver.
- fpANGLEUseForApplication ANGLEUseForApplication =
- (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
- if (ANGLEUseForApplication) {
- ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
- use_angle = (ANGLEUseForApplication)(app_name_str.c_str(), manufacturer, model,
- developer_option, app_preference);
- ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
- } else {
- ALOGW("Cannot find ANGLEUseForApplication in library");
- }
- }
- ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
- dlclose(so);
- so = nullptr;
+
+ // Check if ANGLE is enabled. Workaround for several bugs:
+ // b/119305693 b/119322355 b/119305887
+ // Something is not working correctly in the feature library
+ property_get("debug.angle.enable", prop, "0");
+ if (atoi(prop)) {
+ cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+ }
+ if (cnx->featureSo) {
+ ALOGV("loaded ANGLE's opt-in/out logic from namespace");
+ use_angle = check_angle_rules(cnx->featureSo, app_name);
} else {
// We weren't able to load and call the updateable opt-in/out logic.
// If we can't load the library, there is no ANGLE available.
use_angle = false;
- ALOGV("Could not temporarily-load the ANGLE opt-in/out logic, cannot use ANGLE.");
+ ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE.");
}
+ cnx->angleDecided = true;
}
+ void* so = nullptr;
if (use_angle) {
so = load_angle_from_namespace(kind, ns);
}
@@ -611,13 +610,30 @@
if (so) {
ALOGV("Loaded ANGLE %s library for %s (instead of native)",
kind, app_name ? app_name : "nullptr");
- property_get("debug.angle.backend", prop, "UNSET");
- ALOGV("ANGLE's backend set to %s", prop);
property_get("debug.hwui.renderer", prop, "UNSET");
ALOGV("Skia's renderer set to %s", prop);
cnx->useAngle = true;
- // Find and load vendor libEGL for ANGLE
- if (!cnx->vendorEGL) {
+
+ EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+
+ char prop[PROPERTY_VALUE_MAX];
+ property_get("debug.angle.backend", prop, "0");
+ switch (atoi(prop)) {
+ case 1:
+ ALOGV("%s: Requesting OpenGLES back-end", __FUNCTION__);
+ angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
+ break;
+ case 2:
+ ALOGV("%s: Requesting Vulkan back-end", __FUNCTION__);
+ angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+ break;
+ default:
+ break;
+ }
+
+ cnx->angleBackend = angleBackendDefault;
+ if (!cnx->vendorEGL && (cnx->angleBackend == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) {
+ // Find and load vendor libEGL for ANGLE's GL back-end to use.
cnx->vendorEGL = load_system_driver("EGL");
}
return so;
@@ -660,13 +676,13 @@
ATRACE_CALL();
void* dso = nullptr;
- android_namespace_t* ns = android_getAngleNamespace();
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
if (ns) {
dso = load_angle(kind, ns, cnx);
}
#ifndef __ANDROID_VNDK__
if (!dso) {
- android_namespace_t* ns = android_getDriverNamespace();
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (ns) {
dso = load_updated_driver(kind, ns);
}
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 9cc73f3..392887d 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -51,7 +51,7 @@
~Loader();
void* open(egl_connection_t* cnx);
- void close(void* driver);
+ void close(egl_connection_t* cnx);
private:
Loader();
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 476b304..a065973 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -128,56 +128,10 @@
return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
}
-static bool addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
+static bool addAnglePlatformAttributes(egl_connection_t* const cnx,
std::vector<EGLAttrib>& attrs) {
intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
- EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
- if (attrib_list) {
- while (*attrib_list != EGL_NONE) {
- EGLAttrib attr = *attrib_list++;
- EGLAttrib value = *attrib_list++;
- if (attr == EGL_PLATFORM_ANGLE_TYPE_ANGLE) {
- switch (value) {
- case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
- angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
- break;
- case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
- case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
- angleBackendDefault = value;
- break;
- default:
- ALOGW("Invalid EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute: 0x%" PRIxPTR,
- value);
- break;
- }
- }
- }
- }
-
- // Allow debug property to override application's
- char prop[PROPERTY_VALUE_MAX];
- property_get("debug.angle.backend", prop, "0");
- switch (atoi(prop)) {
- case 1:
- ALOGV("addAnglePlatformAttributes: Requesting OpenGLES back-end");
- angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
- break;
- case 2:
- ALOGV("addAnglePlatformAttributes: Requesting Vulkan back-end");
- angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
- break;
- default:
- break;
- }
-
- if (cnx->angleBackend == 0) {
- // Haven't been initialized yet, so set it.
- cnx->angleBackend = angleBackendDefault;
- } else if (cnx->angleBackend != angleBackendDefault) {
- return false;
- }
-
attrs.reserve(4 * 2);
attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
@@ -186,6 +140,7 @@
switch (cnx->angleBackend) {
case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
ALOGV("%s: Requesting Vulkan ANGLE back-end", __FUNCTION__);
+ char prop[PROPERTY_VALUE_MAX];
property_get("debug.angle.validation", prop, "0");
attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
attrs.push_back(atoi(prop));
@@ -212,7 +167,7 @@
// Initialize function ptrs for ANGLE PlatformMethods struct, used for systrace
bool initializeAnglePlatform(EGLDisplay dpy) {
// Since we're inside libEGL, use dlsym to lookup fptr for ANGLEGetDisplayPlatform
- android_namespace_t* ns = android_getAngleNamespace();
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = ns,
@@ -260,7 +215,7 @@
}
}
- if (!addAnglePlatformAttributes(cnx, attrib_list, attrs)) {
+ if (!addAnglePlatformAttributes(cnx, attrs)) {
ALOGE("eglGetDisplay(%p) failed: Mismatch display request", display);
*error = EGL_BAD_PARAMETER;
return EGL_NO_DISPLAY;
@@ -310,7 +265,12 @@
if (cnx->egl.eglGetPlatformDisplay) {
dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANDROID_KHR, display,
attrib_list);
- } else {
+ }
+
+ // It is possible that eglGetPlatformDisplay does not have a
+ // working implementation for Android platform; in that case,
+ // one last fallback to eglGetDisplay
+ if(dpy == EGL_NO_DISPLAY) {
if (attrib_list) {
ALOGW("getPlatformDisplay: unexpected attribute list, attributes ignored");
}
@@ -320,8 +280,7 @@
disp.dpy = dpy;
if (dpy == EGL_NO_DISPLAY) {
- loader.close(cnx->dso);
- cnx->dso = nullptr;
+ loader.close(cnx);
}
}
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index 6900b8b..dd8fbfc 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -144,8 +144,8 @@
std::string LayerLoader::GetDebugLayers() {
// Layers can be specified at the Java level in GraphicsEnvironemnt
- // gpu_debug_layers = layer1:layer2:layerN
- std::string debug_layers = android_getDebugLayers();
+ // gpu_debug_layers_gles = layer1:layer2:layerN
+ std::string debug_layers = android::GraphicsEnv::getInstance().getDebugLayersGLES();
if (debug_layers.empty()) {
// Only check system properties if Java settings are empty
@@ -339,7 +339,9 @@
// Load the layers in reverse order so we start with the driver's entrypoint and work our way up
for (int32_t i = layers.size() - 1; i >= 0; i--) {
// Check each layer path for the layer
- std::vector<std::string> paths = android::base::Split(android_getLayerPaths(), ":");
+ std::vector<std::string> paths =
+ android::base::Split(android::GraphicsEnv::getInstance().getLayerPaths().c_str(),
+ ":");
if (!system_path.empty()) {
// Prepend the system paths so they override other layers
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 1daa4d2..547a669 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -485,58 +485,29 @@
}
// Returns a list of color spaces understood by the vendor EGL driver.
-static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp,
- android_pixel_format format) {
+static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp) {
std::vector<EGLint> colorSpaces;
- if (!dp->hasColorSpaceSupport) return colorSpaces;
- // OpenGL drivers only support sRGB encoding with 8-bit formats.
- // RGB_888 is never returned by getNativePixelFormat, but is included for completeness.
- const bool formatSupportsSRGBEncoding =
- format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 ||
- format == HAL_PIXEL_FORMAT_RGB_888;
- const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16;
+ // sRGB and linear are always supported when color space support is present.
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+ colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
- if (formatSupportsSRGBEncoding) {
- // sRGB and linear are always supported when color space support is present.
- colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
- colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
- // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_display_p3")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
- }
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
}
-
- // According to the spec, scRGB is only supported for floating point formats.
- // For non-linear scRGB, the application is responsible for applying the
- // transfer function.
- if (formatIsFloatingPoint) {
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_scrgb")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
- }
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_scrgb_linear")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
- }
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
}
-
- // BT2020 can be used with any pixel format. PQ encoding must be applied by the
- // application and does not affect the behavior of OpenGL.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_bt2020_linear")) {
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb_linear")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
+ }
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_linear")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
}
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_bt2020_pq")) {
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_pq")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
}
-
- // Linear DCI-P3 simply uses different primaries than standard RGB and thus
- // can be used with any pixel format.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_display_p3_linear")) {
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3_linear")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
}
return colorSpaces;
@@ -547,18 +518,32 @@
// unmodified.
template <typename AttrType>
static EGLBoolean processAttributes(egl_display_ptr dp, ANativeWindow* window,
- android_pixel_format format, const AttrType* attrib_list,
- EGLint* colorSpace, std::vector<AttrType>* strippedAttribList) {
+ const AttrType* attrib_list, EGLint* colorSpace,
+ std::vector<AttrType>* strippedAttribList) {
for (const AttrType* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
bool copyAttribute = true;
if (attr[0] == EGL_GL_COLORSPACE_KHR) {
- // Fail immediately if the driver doesn't have color space support at all.
- if (!dp->hasColorSpaceSupport) return false;
+ switch (attr[1]) {
+ case EGL_GL_COLORSPACE_LINEAR_KHR:
+ case EGL_GL_COLORSPACE_SRGB_KHR:
+ case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
+ case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
+ case EGL_GL_COLORSPACE_SCRGB_EXT:
+ case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT:
+ case EGL_GL_COLORSPACE_BT2020_PQ_EXT:
+ case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
+ // Fail immediately if the driver doesn't have color space support at all.
+ if (!dp->hasColorSpaceSupport) return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ break;
+ default:
+ // BAD_ATTRIBUTE if attr is not any of the EGL_GL_COLORSPACE_*
+ return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
*colorSpace = static_cast<EGLint>(attr[1]);
// Strip the attribute if the driver doesn't understand it.
copyAttribute = false;
- std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format);
+ std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp);
for (auto driverColorSpace : driverColorSpaces) {
if (static_cast<EGLint>(attr[1]) == driverColorSpace) {
copyAttribute = true;
@@ -585,10 +570,8 @@
// If the passed color space has wide color gamut, check whether the target native window
// supports wide color.
- const bool colorSpaceIsNarrow =
- *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
- *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR ||
- *colorSpace == EGL_UNKNOWN;
+ const bool colorSpaceIsNarrow = *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
+ *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR || *colorSpace == EGL_UNKNOWN;
if (window && !colorSpaceIsNarrow) {
bool windowSupportsWideColor = true;
// Ordinarily we'd put a call to native_window_get_wide_color_support
@@ -606,12 +589,12 @@
ALOGE("processAttributes: invalid window (win=%p) "
"failed (%#x) (already connected to another API?)",
window, err);
- return false;
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_FALSE);
}
if (!windowSupportsWideColor) {
// Application has asked for a wide-color colorspace but
// wide-color support isn't available on the display the window is on.
- return false;
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
}
}
return true;
@@ -695,8 +678,7 @@
native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata);
s->resetSmpte2086Metadata();
if (err != 0) {
- ALOGE("error setting native window smpte2086 metadata: %s (%d)",
- strerror(-err), err);
+ ALOGE("error setting native window smpte2086 metadata: %s (%d)", strerror(-err), err);
return EGL_FALSE;
}
}
@@ -706,8 +688,7 @@
native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata);
s->resetCta8613Metadata();
if (err != 0) {
- ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
- strerror(-err), err);
+ ALOGE("error setting native window CTS 861.3 metadata: %s (%d)", strerror(-err), err);
return EGL_FALSE;
}
}
@@ -749,10 +730,12 @@
// now select correct colorspace and dataspace based on user's attribute list
EGLint colorSpace = EGL_UNKNOWN;
std::vector<AttrType> strippedAttribList;
- if (!processAttributes<AttrType>(dp, window, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
+ if (!processAttributes<AttrType>(dp, window, attrib_list, &colorSpace, &strippedAttribList)) {
ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ }
+ return EGL_NO_SURFACE;
}
attrib_list = strippedAttribList.data();
@@ -765,13 +748,14 @@
}
android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
- if (dataSpace != HAL_DATASPACE_UNKNOWN) {
- err = native_window_set_buffers_data_space(window, dataSpace);
- if (err != 0) {
- ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
+ // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN.
+ // HAL_DATASPACE_UNKNOWN is the default value, but it may have changed
+ // at this point.
+ err = native_window_set_buffers_data_space(window, dataSpace);
+ if (err != 0) {
+ ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
}
@@ -873,9 +857,8 @@
return EGL_NO_SURFACE;
}
-EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list)
-{
+EGLSurface eglCreatePbufferSurfaceImpl(EGLDisplay dpy, EGLConfig config,
+ const EGLint* attrib_list) {
egl_connection_t* cnx = nullptr;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
@@ -886,35 +869,30 @@
// Select correct colorspace based on user's attribute list
EGLint colorSpace = EGL_UNKNOWN;
std::vector<EGLint> strippedAttribList;
- if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
+ if (!processAttributes(dp, nullptr, attrib_list, &colorSpace, &strippedAttribList)) {
ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ return EGL_NO_SURFACE;
}
attrib_list = strippedAttribList.data();
- EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
- dp->disp.dpy, config, attrib_list);
+ EGLSurface surface = cnx->egl.eglCreatePbufferSurface(dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s =
- new egl_surface_t(dp.get(), config, nullptr, surface,
- getReportedColorSpace(colorSpace), cnx);
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface,
+ getReportedColorSpace(colorSpace), cnx);
return s;
}
}
return EGL_NO_SURFACE;
}
-EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface)
-{
+EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- egl_surface_t * const s = get_surface(surface);
+ egl_surface_t* const s = get_surface(surface);
EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
if (result == EGL_TRUE) {
_s.terminate();
@@ -922,17 +900,15 @@
return result;
}
-EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint *value)
-{
+EGLBoolean eglQuerySurfaceImpl(EGLDisplay dpy, EGLSurface surface, EGLint attribute,
+ EGLint* value) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- egl_surface_t const * const s = get_surface(surface);
+ egl_surface_t const* const s = get_surface(surface);
if (s->getColorSpaceAttribute(attribute, value)) {
return EGL_TRUE;
} else if (s->getSmpte2086Attribute(attribute, value)) {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 7c710d5..cca0053 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -76,9 +76,11 @@
void* libGles1;
void* libGles2;
+ bool angleDecided;
bool useAngle;
EGLint angleBackend;
void* vendorEGL;
+ void* featureSo;
};
// clang-format on
diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt
index fa26e33..b2d7957 100644
--- a/opengl/libs/libEGL.map.txt
+++ b/opengl/libs/libEGL.map.txt
@@ -3,23 +3,30 @@
eglBindAPI;
eglBindTexImage;
eglChooseConfig;
+ eglClientWaitSync; # introduced=29
eglClientWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
eglCopyBuffers;
eglCreateContext;
+ eglCreateImage; # introduced=29
eglCreateImageKHR;
eglCreateNativeClientBufferANDROID; # introduced=24
eglCreatePbufferFromClientBuffer;
eglCreatePbufferSurface;
eglCreatePixmapSurface;
+ eglCreatePlatformPixmapSurface; # introduced=29
+ eglCreatePlatformWindowSurface; # introduced=29
eglCreateStreamFromFileDescriptorKHR; # introduced=23
eglCreateStreamKHR; # introduced=23
eglCreateStreamProducerSurfaceKHR; # introduced=23
+ eglCreateSync; # introduced=29
eglCreateSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
eglCreateWindowSurface;
eglDestroyContext;
+ eglDestroyImage; # introduced=29
eglDestroyImageKHR;
eglDestroyStreamKHR; # introduced=23
eglDestroySurface;
+ eglDestroySync; # introduced=29
eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
eglDupNativeFenceFDANDROID; # vndk
eglGetConfigAttrib;
@@ -30,8 +37,10 @@
eglGetDisplay;
eglGetError;
eglGetNativeClientBufferANDROID; # introduced=26
+ eglGetPlatformDisplay; # introduced=29
eglGetProcAddress;
eglGetStreamFileDescriptorKHR; # introduced=23
+ eglGetSyncAttrib; # introduced=29
eglGetSyncAttribKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
eglGetSystemTimeFrequencyNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
eglGetSystemTimeNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
@@ -64,6 +73,7 @@
eglWaitClient;
eglWaitGL;
eglWaitNative;
+ eglWaitSync; # introduced=29
eglWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
local:
*;
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index f246077..a9e873a 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -25,6 +25,7 @@
"libhidltransport",
"liblog",
"libutils",
+ "libnativewindow",
],
include_dirs: [
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 5927dc1..459b135 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -775,4 +775,169 @@
EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
}
+
+TEST_F(EGLTest, EGLInvalidColorspaceAttribute) {
+ EGLConfig config;
+
+ ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER,
+ EGL_NONE,
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError());
+ ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+}
+
+TEST_F(EGLTest, EGLUnsupportedColorspaceFormatCombo) {
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLBoolean success;
+
+ const EGLint attrs[] = {
+ // clang-format off
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 16,
+ EGL_GREEN_SIZE, 16,
+ EGL_BLUE_SIZE, 16,
+ EGL_ALPHA_SIZE, 16,
+ EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+ EGL_NONE,
+ // clang-format on
+ };
+ success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(1, numConfigs);
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ const EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+ EGL_NONE,
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_BAD_MATCH, eglGetError());
+ ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+}
+
+TEST_F(EGLTest, EGLCreateWindowFailAndSucceed) {
+ EGLConfig config;
+
+ ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER,
+ EGL_NONE,
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError());
+ ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+
+ // Now recreate surface with a valid colorspace. Ensure proper cleanup is done
+ // in the first failed attempt (e.g. native_window_api_disconnect).
+ winAttrs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+ eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGLCreateWindowTwoColorspaces) {
+ EGLConfig config;
+
+ ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ const EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+ EGL_NONE,
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ android_dataspace dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get()));
+ ASSERT_EQ(dataspace, HAL_DATASPACE_DISPLAY_P3);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+
+ // Now create with default attribute (EGL_GL_COLORSPACE_LINEAR_KHR)
+ eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get()));
+ // Make sure the dataspace has been reset to UNKNOWN
+ ASSERT_NE(dataspace, HAL_DATASPACE_DISPLAY_P3);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
}
diff --git a/opengl/tools/glgen/stubs/egl/EGL15Header.java-if b/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
index 7409d93..859380f 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
@@ -20,7 +20,9 @@
* EGL 1.5
*
*/
-public class EGL15 {
+public final class EGL15 {
+
+ private EGL15() {};
public static final int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x00000001;
public static final int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x00000002;
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
new file mode 100644
index 0000000..ca65e02
--- /dev/null
+++ b/services/bufferhub/Android.bp
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_shared {
+ name: "libbufferhubservice",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ srcs: [
+ "BufferClient.cpp",
+ "BufferHubService.cpp",
+ "BufferNode.cpp",
+ ],
+ header_libs: [
+ "libbufferhub_headers",
+ "libdvr_headers",
+ "libnativewindow_headers",
+ "libpdx_headers",
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+ export_include_dirs: [
+ "include"
+ ],
+}
+
+cc_binary {
+ name: "android.frameworks.bufferhub@1.0-service",
+ relative_install_path: "hw",
+ srcs: [
+ "main_bufferhub.cpp"
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libbufferhubservice",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ init_rc: ["android.frameworks.bufferhub@1.0-service.rc"],
+ vintf_fragments: ["android.frameworks.bufferhub@1.0-service.xml"],
+}
diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp
new file mode 100644
index 0000000..b3662b2
--- /dev/null
+++ b/services/bufferhub/BufferClient.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferClient.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::hidl_handle;
+using hardware::Void;
+
+Return<void> BufferClient::duplicate(duplicate_cb _hidl_cb) {
+ // TODO(b/118614157): implement token generation and registration
+ _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
\ No newline at end of file
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
new file mode 100644
index 0000000..86598e0
--- /dev/null
+++ b/services/bufferhub/BufferHubService.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferHubService.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::Void;
+
+Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& /*description*/,
+ const uint32_t /*userMetadataSize*/,
+ allocateBuffer_cb _hidl_cb) {
+ // TODO(b/118614333): implement buffer allocation
+ _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
+}
+
+Return<void> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/,
+ importBuffer_cb _hidl_cb) {
+ // TODO(b/118614157): implement buffer import
+ _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
new file mode 100644
index 0000000..53dd702
--- /dev/null
+++ b/services/bufferhub/BufferNode.cpp
@@ -0,0 +1,99 @@
+#include <errno.h>
+
+#include <bufferhub/BufferNode.h>
+#include <private/dvr/buffer_hub_defs.h>
+#include <ui/GraphicBufferAllocator.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+void BufferNode::InitializeMetadata() {
+ // Using placement new here to reuse shared memory instead of new allocation
+ // Initialize the atomic variables to zero.
+ dvr::BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
+ buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint64_t>(0);
+ fence_state_ = new (&metadata_header->fence_state) std::atomic<uint64_t>(0);
+ active_clients_bit_mask_ =
+ new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
+}
+
+// Allocates a new BufferNode.
+BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t user_metadata_size) {
+ uint32_t out_stride = 0;
+ // graphicBufferId is not used in GraphicBufferAllocator::allocate
+ // TODO(b/112338294) After move to the service folder, stop using the
+ // hardcoded service name "bufferhub".
+ int ret = GraphicBufferAllocator::get().allocate(width, height, format, layer_count, usage,
+ const_cast<const native_handle_t**>(
+ &buffer_handle_),
+ &out_stride,
+ /*graphicBufferId=*/0,
+ /*requestor=*/"bufferhub");
+
+ if (ret != OK || buffer_handle_ == nullptr) {
+ ALOGE("%s: Failed to allocate buffer: %s", __FUNCTION__, strerror(-ret));
+ return;
+ }
+
+ buffer_desc_.width = width;
+ buffer_desc_.height = height;
+ buffer_desc_.layers = layer_count;
+ buffer_desc_.format = format;
+ buffer_desc_.usage = usage;
+ buffer_desc_.stride = out_stride;
+
+ metadata_ = BufferHubMetadata::Create(user_metadata_size);
+ if (!metadata_.IsValid()) {
+ ALOGE("%s: Failed to allocate metadata.", __FUNCTION__);
+ return;
+ }
+ InitializeMetadata();
+}
+
+// Free the handle
+BufferNode::~BufferNode() {
+ if (buffer_handle_ != nullptr) {
+ status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
+ if (ret != OK) {
+ ALOGE("%s: Failed to free handle; Got error: %d", __FUNCTION__, ret);
+ }
+ }
+}
+
+uint64_t BufferNode::GetActiveClientsBitMask() const {
+ return active_clients_bit_mask_->load(std::memory_order_acquire);
+}
+
+uint64_t BufferNode::AddNewActiveClientsBitToMask() {
+ uint64_t current_active_clients_bit_mask = GetActiveClientsBitMask();
+ uint64_t client_state_mask = 0ULL;
+ uint64_t updated_active_clients_bit_mask = 0ULL;
+ do {
+ client_state_mask = dvr::BufferHubDefs::FindNextAvailableClientStateMask(
+ current_active_clients_bit_mask);
+ if (client_state_mask == 0ULL) {
+ ALOGE("%s: reached the maximum number of channels per buffer node: 32.", __FUNCTION__);
+ errno = E2BIG;
+ return 0ULL;
+ }
+ updated_active_clients_bit_mask = current_active_clients_bit_mask | client_state_mask;
+ } while (!(active_clients_bit_mask_->compare_exchange_weak(current_active_clients_bit_mask,
+ updated_active_clients_bit_mask,
+ std::memory_order_acq_rel,
+ std::memory_order_acquire)));
+ return client_state_mask;
+}
+
+void BufferNode::RemoveClientsBitFromMask(const uint64_t& value) {
+ active_clients_bit_mask_->fetch_and(~value);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc
new file mode 100644
index 0000000..36fbede
--- /dev/null
+++ b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc
@@ -0,0 +1,6 @@
+service system_bufferhub /system/bin/hw/android.frameworks.bufferhub@1.0-service
+ class hal animation
+ user system
+ group system graphics
+ onrestart restart surfaceflinger
+ writepid /dev/cpuset/system-background/tasks
diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml
new file mode 100644
index 0000000..bd958d3
--- /dev/null
+++ b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.frameworks.bufferhub</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IBufferHub</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
new file mode 100644
index 0000000..14ea95c
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::Return;
+
+class BufferClient : public IBufferClient {
+public:
+ Return<void> duplicate(duplicate_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
new file mode 100644
index 0000000..5e0cff0
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
+
+class BufferHubService : public IBufferHub {
+public:
+ Return<void> allocateBuffer(const HardwareBufferDescription& description,
+ const uint32_t userMetadataSize,
+ allocateBuffer_cb _hidl_cb) override;
+ Return<void> importBuffer(const hidl_handle& nativeHandle, importBuffer_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
new file mode 100644
index 0000000..ffeacac
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -0,0 +1,84 @@
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
+
+#include <android/hardware_buffer.h>
+#include <ui/BufferHubMetadata.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+class BufferNode {
+public:
+ // Allocates a new BufferNode.
+ BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t user_metadata_size);
+
+ ~BufferNode();
+
+ // Returns whether the object holds a valid metadata.
+ bool IsValid() const { return metadata_.IsValid(); }
+
+ size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
+
+ // Accessors of the buffer description and handle
+ const native_handle_t* buffer_handle() const { return buffer_handle_; }
+ const AHardwareBuffer_Desc& buffer_desc() const { return buffer_desc_; }
+
+ // Accessors of metadata.
+ const BufferHubMetadata& metadata() const { return metadata_; }
+
+ // Gets the current value of active_clients_bit_mask in metadata_ with
+ // std::memory_order_acquire, so that all previous releases of
+ // active_clients_bit_mask from all threads will be returned here.
+ uint64_t GetActiveClientsBitMask() const;
+
+ // Find and add a new client_state_mask to active_clients_bit_mask in
+ // metadata_.
+ // Return the new client_state_mask that is added to active_clients_bit_mask.
+ // Return 0ULL if there are already 32 bp clients of the buffer.
+ uint64_t AddNewActiveClientsBitToMask();
+
+ // Removes the value from active_clients_bit_mask in metadata_ with
+ // std::memory_order_release, so that the change will be visible to any
+ // acquire of active_clients_bit_mask_ in any threads after the succeed of
+ // this operation.
+ void RemoveClientsBitFromMask(const uint64_t& value);
+
+private:
+ // Helper method for constructors to initialize atomic metadata header
+ // variables in shared memory.
+ void InitializeMetadata();
+
+ // Gralloc buffer handles.
+ native_handle_t* buffer_handle_;
+ AHardwareBuffer_Desc buffer_desc_;
+
+ // Metadata in shared memory.
+ BufferHubMetadata metadata_;
+
+ // The following variables are atomic variables in metadata_ that are visible
+ // to Bn object and Bp objects. Please find more info in
+ // BufferHubDefs::MetadataHeader.
+
+ // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
+ // four states: gained, posted, acquired, released.
+ std::atomic<uint64_t>* buffer_state_ = nullptr;
+
+ // TODO(b/112012161): add comments to fence_state_.
+ std::atomic<uint64_t>* fence_state_ = nullptr;
+
+ // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
+ // union of all client_state_mask of all bp clients.
+ std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
diff --git a/services/bufferhub/main_bufferhub.cpp b/services/bufferhub/main_bufferhub.cpp
new file mode 100644
index 0000000..084460d
--- /dev/null
+++ b/services/bufferhub/main_bufferhub.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferHubService.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+#include <log/log.h>
+
+using android::sp;
+using android::frameworks::bufferhub::V1_0::IBufferHub;
+using android::frameworks::bufferhub::V1_0::implementation::BufferHubService;
+
+int main(int /*argc*/, char** /*argv*/) {
+ ALOGI("Bootstrap bufferhub HIDL service.");
+
+ android::hardware::configureRpcThreadpool(/*numThreads=*/1, /*willJoin=*/true);
+
+ sp<IBufferHub> service = new BufferHubService();
+ LOG_ALWAYS_FATAL_IF(service->registerAsService() != android::OK, "Failed to register service");
+
+ android::hardware::joinRpcThreadpool();
+
+ return 0;
+}
diff --git a/services/bufferhub/tests/Android.bp b/services/bufferhub/tests/Android.bp
new file mode 100644
index 0000000..cef31f6
--- /dev/null
+++ b/services/bufferhub/tests/Android.bp
@@ -0,0 +1,24 @@
+cc_test {
+ name: "BufferNode_test",
+ srcs: ["BufferNode_test.cpp"],
+ cflags: [
+ "-DLOG_TAG=\"BufferNode_test\"",
+ "-DTRACE=0",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+ ],
+ header_libs: [
+ "libbufferhub_headers",
+ "libdvr_headers",
+ "libnativewindow_headers",
+ "libpdx_headers",
+ ],
+ shared_libs: [
+ "libbufferhubservice",
+ "libui",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
+}
\ No newline at end of file
diff --git a/services/bufferhub/tests/BufferNode_test.cpp b/services/bufferhub/tests/BufferNode_test.cpp
new file mode 100644
index 0000000..df31d78
--- /dev/null
+++ b/services/bufferhub/tests/BufferNode_test.cpp
@@ -0,0 +1,110 @@
+#include <bufferhub/BufferNode.h>
+#include <errno.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <ui/GraphicBufferMapper.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+namespace {
+
+using testing::NotNull;
+
+const uint32_t kWidth = 640;
+const uint32_t kHeight = 480;
+const uint32_t kLayerCount = 1;
+const uint32_t kFormat = 1;
+const uint64_t kUsage = 0;
+const size_t kUserMetadataSize = 0;
+const size_t kMaxClientsCount = dvr::BufferHubDefs::kMaxNumberOfClients;
+
+class BufferNodeTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ buffer_node =
+ new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ ASSERT_TRUE(buffer_node->IsValid());
+ }
+
+ void TearDown() override {
+ if (buffer_node != nullptr) {
+ delete buffer_node;
+ }
+ }
+
+ BufferNode* buffer_node = nullptr;
+};
+
+TEST_F(BufferNodeTest, TestCreateBufferNode) {
+ EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
+ // Test the handle just allocated is good (i.e. able to be imported)
+ GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+ const native_handle_t* outHandle;
+ status_t ret =
+ mapper.importBuffer(buffer_node->buffer_handle(), buffer_node->buffer_desc().width,
+ buffer_node->buffer_desc().height,
+ buffer_node->buffer_desc().layers,
+ buffer_node->buffer_desc().format, buffer_node->buffer_desc().usage,
+ buffer_node->buffer_desc().stride, &outHandle);
+ EXPECT_EQ(ret, OK);
+ EXPECT_THAT(outHandle, NotNull());
+}
+
+TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
+ uint64_t new_client_state_mask_1 = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_client_state_mask_1);
+
+ // Request and add a new client_state_mask again.
+ // Active clients bit mask should be the union of the two new
+ // client_state_masks.
+ uint64_t new_client_state_mask_2 = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
+ new_client_state_mask_1 | new_client_state_mask_2);
+}
+
+TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
+ uint64_t new_client_state_mask = 0ULL;
+ uint64_t current_mask = 0ULL;
+ uint64_t expected_mask = 0ULL;
+
+ for (int i = 0; i < kMaxClientsCount; ++i) {
+ new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_NE(new_client_state_mask, 0);
+ EXPECT_FALSE(new_client_state_mask & current_mask);
+ expected_mask = current_mask | new_client_state_mask;
+ current_mask = buffer_node->GetActiveClientsBitMask();
+ EXPECT_EQ(current_mask, expected_mask);
+ }
+
+ // Method should fail upon requesting for more than maximum allowable clients.
+ new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(new_client_state_mask, 0ULL);
+ EXPECT_EQ(errno, E2BIG);
+}
+
+TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
+ buffer_node->AddNewActiveClientsBitToMask();
+ uint64_t current_mask = buffer_node->GetActiveClientsBitMask();
+ uint64_t new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);
+
+ buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+
+ // Remove the test_mask again to the active client bit mask should not modify
+ // the value of active clients bit mask.
+ buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+}
+
+} // namespace
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
new file mode 100644
index 0000000..250bbee
--- /dev/null
+++ b/services/gpuservice/Android.bp
@@ -0,0 +1,74 @@
+filegroup {
+ name: "gpuservice_sources",
+ srcs: [
+ "GpuService.cpp",
+ ],
+}
+
+filegroup {
+ name: "gpuservice_binary_sources",
+ srcs: ["main_gpuservice.cpp"],
+}
+
+cc_defaults {
+ name: "gpuservice_defaults",
+ cflags: [
+ "-DLOG_TAG=\"GpuService\"",
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ cppflags: ["-std=c++1z"],
+ srcs: [
+ ":gpuservice_sources",
+ ],
+ include_dirs: [
+ "frameworks/native/vulkan/vkjson",
+ "frameworks/native/vulkan/include",
+ ],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ "libvulkan",
+ ],
+ static_libs: [
+ "libvkjson",
+ ],
+}
+
+cc_defaults {
+ name: "gpuservice_production_defaults",
+ defaults: ["gpuservice_defaults"],
+ cflags: [
+ "-fvisibility=hidden",
+ "-fwhole-program-vtables", // requires ThinLTO
+ ],
+ lto: {
+ thin: true,
+ },
+}
+
+cc_defaults {
+ name: "gpuservice_binary",
+ defaults: ["gpuservice_defaults"],
+ whole_static_libs: [
+ "libsigchain",
+ ],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ ldflags: ["-Wl,--export-dynamic"],
+}
+
+cc_binary {
+ name: "gpuservice",
+ defaults: ["gpuservice_binary"],
+ init_rc: ["gpuservice.rc"],
+ srcs: [":gpuservice_binary_sources"],
+}
diff --git a/services/surfaceflinger/GpuService.cpp b/services/gpuservice/GpuService.cpp
similarity index 83%
rename from services/surfaceflinger/GpuService.cpp
rename to services/gpuservice/GpuService.cpp
index 71052fb..e4ca6bc 100644
--- a/services/surfaceflinger/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -23,10 +23,7 @@
namespace android {
-// ----------------------------------------------------------------------------
-
-class BpGpuService : public BpInterface<IGpuService>
-{
+class BpGpuService : public BpInterface<IGpuService> {
public:
explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
};
@@ -34,19 +31,15 @@
IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService");
status_t BnGpuService::onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags)
-{
+ Parcel* reply, uint32_t flags) {
status_t status;
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
int err = data.readFileDescriptor();
- int argc = data.readInt32();
- Vector<String16> args;
- for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
- args.add(data.readString16());
- }
+ std::vector<String16> args;
+ data.readString16Vector(&args);
sp<IBinder> unusedCallback;
sp<IResultReceiver> resultReceiver;
if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK)
@@ -64,20 +57,17 @@
}
}
-// ----------------------------------------------------------------------------
-
namespace {
status_t cmd_help(int out);
status_t cmd_vkjson(int out, int err);
}
-const char* const GpuService::SERVICE_NAME = "gpu";
+const char* const GpuService::SERVICE_NAME = "gpuservice";
-GpuService::GpuService() {}
+GpuService::GpuService() = default;
status_t GpuService::shellCommand(int /*in*/, int out, int err,
- Vector<String16>& args)
-{
+ std::vector<String16>& args) {
ALOGV("GpuService::shellCommand");
for (size_t i = 0, n = args.size(); i < n; i++)
ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string());
@@ -93,8 +83,6 @@
return BAD_VALUE;
}
-// ----------------------------------------------------------------------------
-
namespace {
status_t cmd_help(int out) {
diff --git a/services/surfaceflinger/GpuService.h b/services/gpuservice/GpuService.h
similarity index 80%
rename from services/surfaceflinger/GpuService.h
rename to services/gpuservice/GpuService.h
index b8c28d2..e2b396e 100644
--- a/services/surfaceflinger/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GPUSERVICE_H
#define ANDROID_GPUSERVICE_H
+#include <vector>
+
#include <binder/IInterface.h>
#include <cutils/compiler.h>
@@ -34,22 +36,21 @@
class BnGpuService: public BnInterface<IGpuService> {
protected:
virtual status_t shellCommand(int in, int out, int err,
- Vector<String16>& args) = 0;
+ std::vector<String16>& args) = 0;
- virtual status_t onTransact(uint32_t code, const Parcel& data,
+ status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0) override;
};
-class GpuService : public BnGpuService
-{
+class GpuService : public BnGpuService {
public:
static const char* const SERVICE_NAME ANDROID_API;
GpuService() ANDROID_API;
protected:
- virtual status_t shellCommand(int in, int out, int err,
- Vector<String16>& args) override;
+ status_t shellCommand(int in, int out, int err,
+ std::vector<String16>& args) override;
};
} // namespace android
diff --git a/services/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc
new file mode 100644
index 0000000..d23cf46
--- /dev/null
+++ b/services/gpuservice/gpuservice.rc
@@ -0,0 +1,4 @@
+service gpuservice /system/bin/gpuservice
+ class core
+ user gpu_service
+ group graphics
diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp
new file mode 100644
index 0000000..64aafca
--- /dev/null
+++ b/services/gpuservice/main_gpuservice.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <sys/resource.h>
+#include "GpuService.h"
+
+using namespace android;
+
+int main(int /* argc */, char** /* argv */) {
+ signal(SIGPIPE, SIG_IGN);
+
+ // publish GpuService
+ sp<GpuService> gpuservice = new GpuService();
+ sp<IServiceManager> sm(defaultServiceManager());
+ sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
+
+ // limit the number of binder threads to 4.
+ ProcessState::self()->setThreadPoolMaxThreadCount(4);
+
+ // start the thread pool
+ sp<ProcessState> ps(ProcessState::self());
+ ps->startThreadPool();
+ ps->giveThreadPoolName();
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 622a623..9a65452 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -41,8 +41,6 @@
"-Wall",
"-Wextra",
"-Werror",
- // Allow implicit fallthroughs in InputReader.cpp until they are fixed.
- "-Wno-error=implicit-fallthrough",
"-Wno-unused-parameter",
// TODO: Move inputflinger to its own process and mark it hidden
//-fvisibility=hidden
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index a964d29..1a1dabb 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -147,8 +147,7 @@
fd(fd), id(id), path(path), identifier(identifier),
classes(0), configuration(nullptr), virtualKeyMap(nullptr),
ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
- timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
- isVirtual(fd < 0) {
+ enabled(true), isVirtual(fd < 0) {
memset(keyBitmask, 0, sizeof(keyBitmask));
memset(absBitmask, 0, sizeof(absBitmask));
memset(relBitmask, 0, sizeof(relBitmask));
@@ -871,31 +870,6 @@
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
- // Some input devices may have a better concept of the time
- // when an input event was actually generated than the kernel
- // which simply timestamps all events on entry to evdev.
- // This is a custom Android extension of the input protocol
- // mainly intended for use with uinput based device drivers.
- if (iev.type == EV_MSC) {
- if (iev.code == MSC_ANDROID_TIME_SEC) {
- device->timestampOverrideSec = iev.value;
- continue;
- } else if (iev.code == MSC_ANDROID_TIME_USEC) {
- device->timestampOverrideUsec = iev.value;
- continue;
- }
- }
- if (device->timestampOverrideSec || device->timestampOverrideUsec) {
- iev.time.tv_sec = device->timestampOverrideSec;
- iev.time.tv_usec = device->timestampOverrideUsec;
- if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
- device->timestampOverrideSec = 0;
- device->timestampOverrideUsec = 0;
- }
- ALOGV("applied override time %d.%06d",
- int(iev.time.tv_sec), int(iev.time.tv_usec));
- }
-
// Use the time specified in the event instead of the current time
// so that downstream code can get more accurate estimates of
// event dispatch latency from the time the event is enqueued onto
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index ea663b7..62ce47c 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -42,20 +42,6 @@
#define BTN_FIRST 0x100 // first button code
#define BTN_LAST 0x15f // last button code
-/*
- * These constants are used privately in Android to pass raw timestamps
- * through evdev from uinput device drivers because there is currently no
- * other way to transfer this information. The evdev driver automatically
- * timestamps all input events with the time they were posted and clobbers
- * whatever information was passed in.
- *
- * For the purposes of this hack, the timestamp is specified in the
- * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying
- * seconds and microseconds.
- */
-#define MSC_ANDROID_TIME_SEC 0x6
-#define MSC_ANDROID_TIME_USEC 0x7
-
namespace android {
enum {
@@ -371,9 +357,6 @@
int32_t controllerNumber;
- int32_t timestampOverrideSec;
- int32_t timestampOverrideUsec;
-
Device(int fd, int32_t id, const std::string& path,
const InputDeviceIdentifier& identifier);
~Device();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2cad986..2e984d9 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2545,6 +2545,9 @@
uint32_t policyFlags = args->policyFlags;
int32_t flags = args->flags;
int32_t metaState = args->metaState;
+ // InputDispatcher tracks and generates key repeats on behalf of
+ // whatever notifies it, so repeatCount should always be set to 0
+ constexpr int32_t repeatCount = 0;
if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
policyFlags |= POLICY_FLAG_VIRTUAL;
flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
@@ -2560,7 +2563,7 @@
KeyEvent event;
event.initialize(args->deviceId, args->source, args->displayId, args->action,
- flags, keyCode, args->scanCode, metaState, 0,
+ flags, keyCode, args->scanCode, metaState, repeatCount,
args->downTime, args->eventTime);
android::base::Timer t;
@@ -2585,7 +2588,6 @@
mLock.lock();
}
- int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, args->displayId, policyFlags,
args->action, flags, keyCode, args->scanCode,
@@ -2756,7 +2758,7 @@
accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
/*byref*/ keyCode, /*byref*/ metaState);
keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
- action, flags, keyCode, keyEvent.getScanCode(), metaState, 0,
+ action, flags, keyCode, keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(),
keyEvent.getDownTime(), keyEvent.getEventTime());
if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 0b73be0..869bd71 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -1041,7 +1041,7 @@
void InputDevice::dump(std::string& dump) {
InputDeviceInfo deviceInfo;
- getDeviceInfo(& deviceInfo);
+ getDeviceInfo(&deviceInfo);
dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
deviceInfo.getDisplayName().c_str());
@@ -2612,7 +2612,7 @@
// Should not happen during first time configuration.
ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
mParameters.mode = Parameters::MODE_POINTER;
- // fall through.
+ [[fallthrough]];
case Parameters::MODE_POINTER:
mSource = AINPUT_SOURCE_MOUSE;
mXPrecision = 1.0f;
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
index f1d3726..2da2a70 100644
--- a/services/inputflinger/host/InputFlinger.cpp
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -53,7 +53,7 @@
if ((uid != AID_SHELL)
&& !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
result.appendFormat("Permission Denial: "
- "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+ "can't dump InputFlinger from pid=%d, uid=%d\n", pid, uid);
} else {
dumpInternal(result);
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 707f3c5..6114f51 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1082,7 +1082,7 @@
// --- InputReaderPolicyTest ---
class InputReaderPolicyTest : public testing::Test {
- protected:
+protected:
sp<FakeInputReaderPolicy> mFakePolicy;
virtual void SetUp() {
@@ -1101,7 +1101,7 @@
* Such configuration is not currently allowed.
*/
TEST_F(InputReaderPolicyTest, Viewports_GetCleared) {
- const std::string uniqueId = "local:0";
+ static const std::string uniqueId = "local:0";
// We didn't add any viewports yet, so there shouldn't be any.
std::optional<DisplayViewport> internalViewport =
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 16003a2..9abb040 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -19,10 +19,6 @@
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
],
- include_dirs: [
- "frameworks/native/vulkan/vkjson",
- "frameworks/native/vulkan/include",
- ],
shared_libs: [
"android.frameworks.vr.composer@1.0",
"android.hardware.configstore-utils",
@@ -59,13 +55,11 @@
"libtimestats_proto",
"libui",
"libutils",
- "libvulkan",
],
static_libs: [
"librenderengine",
"libserviceutils",
"libtrace_proto",
- "libvkjson",
"libvr_manager",
"libvrflinger",
],
@@ -132,7 +126,6 @@
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
"FrameTracker.cpp",
- "GpuService.cpp",
"Layer.cpp",
"LayerBE.cpp",
"LayerProtoHelper.cpp",
@@ -153,6 +146,7 @@
"SurfaceInterceptor.cpp",
"SurfaceTracing.cpp",
"TimeStats/TimeStats.cpp",
+ "TransactionCompletedThread.cpp",
],
}
@@ -190,6 +184,7 @@
"libhidltransport",
"liblayers_proto",
"liblog",
+ "libsync",
"libtimestats_proto",
"libutils",
],
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 52fbd44..d05ee04 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -229,15 +229,14 @@
getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
+void BufferLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t supportedPerFrameMetadata) {
// Apply this display's projection's viewport to the visible region
// before giving it to the HWC HAL.
- const ui::Transform& tr = display->getTransform();
- const auto& viewport = display->getViewport();
- Region visible = tr.transform(visibleRegion.intersect(viewport));
- const auto displayId = display->getId();
+ Region visible = transform.transform(visibleRegion.intersect(viewport));
+
if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+ ALOGE("[%s] failed to setPerFrameData: no HWC layer found for display %" PRIu64,
mName.string(), displayId);
return;
}
@@ -290,7 +289,7 @@
}
const HdrMetadata& metadata = getDrawingHdrMetadata();
- error = hwcLayer->setPerFrameMetadata(display->getSupportedPerFrameMetadata(), metadata);
+ error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata);
if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
to_string(error).c_str(), static_cast<int32_t>(error));
@@ -303,10 +302,10 @@
}
getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
- getBE().compositionInfo.hwc.supportedPerFrameMetadata = display->getSupportedPerFrameMetadata();
+ getBE().compositionInfo.hwc.supportedPerFrameMetadata = supportedPerFrameMetadata;
getBE().compositionInfo.hwc.colorTransform = getColorTransform();
- setHwcLayerBuffer(display);
+ setHwcLayerBuffer(displayId);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -318,10 +317,10 @@
return hasReadyFrame();
}
-bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+bool BufferLayer::onPostComposition(const std::optional<DisplayId>& displayId,
+ const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) {
-
// mFrameLatencyNeeded is true when a new frame was latched for the
// composition.
if (!mFrameLatencyNeeded) return false;
@@ -352,11 +351,10 @@
if (presentFence->isValid()) {
mTimeStats.setPresentFence(layerID, mCurrentFrameNumber, presentFence);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
- } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
+ } else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- const nsecs_t actualPresentTime =
- mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
mTimeStats.setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
@@ -522,7 +520,7 @@
}
bool BufferLayer::hasReadyFrame() const {
- return hasDrawingBuffer() || getSidebandStreamChanged() || getAutoRefresh();
+ return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
}
uint32_t BufferLayer::getEffectiveScalingMode() const {
@@ -660,7 +658,7 @@
}
uint64_t BufferLayer::getHeadFrameNumber() const {
- if (hasDrawingBuffer()) {
+ if (hasFrameUpdate()) {
return getFrameNumber();
} else {
return mCurrentFrameNumber;
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 1d33a1f..690a4e5 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -80,10 +80,12 @@
bool isHdrY410() const override;
- void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
bool onPreComposition(nsecs_t refreshStartTime) override;
- bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+ bool onPostComposition(const std::optional<DisplayId>& displayId,
+ const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) override;
@@ -134,7 +136,7 @@
virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
- virtual bool hasDrawingBuffer() const = 0;
+ virtual bool hasFrameUpdate() const = 0;
virtual void setFilteringEnabled(bool enabled) = 0;
@@ -145,7 +147,7 @@
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& display) = 0;
+ virtual void setHwcLayerBuffer(DisplayId displayId) = 0;
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e592a8b..78ab23a 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -23,7 +23,9 @@
BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
-BufferQueueLayer::~BufferQueueLayer() = default;
+BufferQueueLayer::~BufferQueueLayer() {
+ mConsumer->abandon();
+}
// -----------------------------------------------------------------------
// Interface implementation for Layer
@@ -33,10 +35,6 @@
mConsumer->setReleaseFence(releaseFence);
}
-void BufferQueueLayer::abandon() {
- mConsumer->abandon();
-}
-
void BufferQueueLayer::setTransformHint(uint32_t orientation) const {
mConsumer->setTransformHint(orientation);
}
@@ -84,7 +82,7 @@
return true;
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
return false;
}
@@ -112,7 +110,7 @@
return true;
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
return true;
}
@@ -208,7 +206,7 @@
return {};
}
-bool BufferQueueLayer::hasDrawingBuffer() const {
+bool BufferQueueLayer::hasFrameUpdate() const {
return mQueuedFrames > 0;
}
@@ -327,8 +325,7 @@
return NO_ERROR;
}
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto displayId = display->getId();
+void BufferQueueLayer::setHwcLayerBuffer(DisplayId displayId) {
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
@@ -355,6 +352,11 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
+ // Report the timestamp to the Scheduler.
+ if (mFlinger->mUseScheduler) {
+ mFlinger->mScheduler->addNewFrameTimestamp(item.mTimestamp, item.mIsAutoTimestamp);
+ }
+
Mutex::Autolock lock(mQueueItemLock);
// Reset the frame number tracker when we receive the first buffer after
// a frame number reset
@@ -380,7 +382,17 @@
mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(), item.mFrameNumber);
- mFlinger->signalLayerUpdate();
+
+ // If this layer is orphaned, then we run a fake vsync pulse so that
+ // dequeueBuffer doesn't block indefinitely.
+ if (isRemovedFromCurrentState()) {
+ bool ignored = false;
+ latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+ usleep(16000);
+ releasePendingBuffer(systemTime());
+ } else {
+ mFlinger->signalLayerUpdate();
+ }
}
void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
@@ -395,7 +407,7 @@
}
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
ALOGE("Can't replace a frame on an empty queue");
return;
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index abe0bc7..ae0b705 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -40,8 +40,6 @@
public:
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
- void abandon() override;
-
void setTransformHint(uint32_t orientation) const override;
std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
@@ -85,7 +83,7 @@
std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
- bool hasDrawingBuffer() const override;
+ bool hasFrameUpdate() const override;
void setFilteringEnabled(bool enabled) override;
@@ -96,8 +94,7 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
- // -----------------------------------------------------------------------
+ void setHwcLayerBuffer(DisplayId displayId) override;
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index ac9e783..425f5c7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -43,9 +43,11 @@
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {
- // TODO(marissaw): send the release fence back to buffer owner
- return;
+void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ // The transaction completed callback can only be sent if the release fence from the PREVIOUS
+ // frame has fired. In practice, we should never actually wait on the previous release fence
+ // but we should store it just in case.
+ mPreviousReleaseFence = releaseFence;
}
void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -54,7 +56,6 @@
}
void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
- // TODO(marissaw): use this to signal the buffer owner
return;
}
@@ -63,7 +64,13 @@
return true;
}
- return hasDrawingBuffer();
+ return hasFrameUpdate();
+}
+
+bool BufferStateLayer::willPresentCurrentTransaction() const {
+ // Returns true if the most recent Transaction applied to CurrentState will be presented.
+ return getSidebandStreamChanged() || getAutoRefresh() ||
+ (mCurrentState.modified && mCurrentState.buffer != nullptr);
}
bool BufferStateLayer::getTransformToDisplayInverse() const {
@@ -83,6 +90,7 @@
while (!mPendingStates.empty()) {
popPendingState(stateToCommit);
}
+ mCurrentStateModified = stateUpdateAvailable && mCurrentState.modified;
mCurrentState.modified = false;
return stateUpdateAvailable;
}
@@ -120,7 +128,11 @@
return true;
}
-bool BufferStateLayer::setBuffer(sp<GraphicBuffer> buffer) {
+bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) {
+ if (mCurrentState.buffer) {
+ mReleasePreviousBuffer = true;
+ }
+
mCurrentState.sequence++;
mCurrentState.buffer = buffer;
mCurrentState.modified = true;
@@ -129,6 +141,9 @@
}
bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
+ // The acquire fences of BufferStateLayers have already signaled before they are set
+ mCallbackHandleAcquireTime = fence->getSignalTime();
+
mCurrentState.acquireFence = fence;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -184,6 +199,44 @@
return true;
}
+bool BufferStateLayer::setTransactionCompletedListeners(
+ const std::vector<sp<CallbackHandle>>& handles) {
+ // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return
+ if (handles.empty()) {
+ mReleasePreviousBuffer = false;
+ return false;
+ }
+
+ const bool willPresent = willPresentCurrentTransaction();
+
+ for (const auto& handle : handles) {
+ // If this transaction set a buffer on this layer, release its previous buffer
+ handle->releasePreviousBuffer = mReleasePreviousBuffer;
+
+ // If this layer will be presented in this frame
+ if (willPresent) {
+ // If this transaction set an acquire fence on this layer, set its acquire time
+ handle->acquireTime = mCallbackHandleAcquireTime;
+
+ // Notify the transaction completed thread that there is a pending latched callback
+ // handle
+ mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+
+ // Store so latched time and release fence can be set
+ mCurrentState.callbackHandles.push_back(handle);
+
+ } else { // If this layer will NOT need to be relatched and presented this frame
+ // Notify the transaction completed thread this handle is done
+ mFlinger->getTransactionCompletedThread().addUnlatchedCallbackHandle(handle);
+ }
+ }
+
+ mReleasePreviousBuffer = false;
+ mCallbackHandleAcquireTime = -1;
+
+ return willPresent;
+}
+
bool BufferStateLayer::setSize(uint32_t w, uint32_t h) {
if (mCurrentState.active.w == w && mCurrentState.active.h == h) return false;
mCurrentState.active.w = w;
@@ -267,7 +320,7 @@
}
uint32_t BufferStateLayer::getDrawingScalingMode() const {
- return NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
}
Region BufferStateLayer::getDrawingSurfaceDamage() const {
@@ -316,8 +369,8 @@
return {};
}
-bool BufferStateLayer::hasDrawingBuffer() const {
- return getDrawingState().buffer != nullptr;
+bool BufferStateLayer::hasFrameUpdate() const {
+ return mCurrentStateModified && getCurrentState().buffer != nullptr;
}
void BufferStateLayer::setFilteringEnabled(bool enabled) {
@@ -405,6 +458,10 @@
return BAD_VALUE;
}
+ mFlinger->getTransactionCompletedThread()
+ .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
+ mPreviousReleaseFence);
+
// Handle sync fences
if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
// TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
@@ -472,8 +529,7 @@
}
// TODO(marissaw): properly support mTimeStats
- mTimeStats.setLayerName(layerID, getName().c_str());
- mTimeStats.setPostTime(layerID, getFrameNumber(), latchTime);
+ mTimeStats.setPostTime(layerID, getFrameNumber(), getName().c_str(), latchTime);
mTimeStats.setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
mTimeStats.setLatchTime(layerID, getFrameNumber(), latchTime);
@@ -500,8 +556,7 @@
return NO_ERROR;
}
-void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto displayId = display->getId();
+void BufferStateLayer::setHwcLayerBuffer(DisplayId displayId) {
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
@@ -516,6 +571,7 @@
s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
}
+ mCurrentStateModified = false;
mFrameNumber++;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 0c6eaf5..315d5af 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -62,13 +62,14 @@
bool setTransform(uint32_t transform) override;
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) override;
- bool setBuffer(sp<GraphicBuffer> buffer) override;
+ bool setBuffer(const sp<GraphicBuffer>& buffer) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
bool setApi(int32_t api) override;
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
+ bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
bool setSize(uint32_t w, uint32_t h) override;
bool setPosition(float x, float y, bool immediate) override;
@@ -110,7 +111,7 @@
std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
- bool hasDrawingBuffer() const override;
+ bool hasFrameUpdate() const override;
void setFilteringEnabled(bool enabled) override;
@@ -121,10 +122,11 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
- // -----------------------------------------------------------------------
+ void setHwcLayerBuffer(DisplayId displayId) override;
+
private:
void onFirstRef() override;
+ bool willPresentCurrentTransaction() const;
static const std::array<float, 16> IDENTITY_MATRIX;
@@ -136,6 +138,12 @@
uint32_t mFrameNumber{0};
+ sp<Fence> mPreviousReleaseFence;
+
+ bool mCurrentStateModified = false;
+ bool mReleasePreviousBuffer = false;
+ nsecs_t mCallbackHandleAcquireTime = -1;
+
// TODO(marissaw): support sticky transform for LEGACY camera mode
};
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 263f872..ad716ef 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -57,13 +57,12 @@
return !isHiddenByPolicy() && getAlpha() > 0.0f;
}
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
- const ui::Transform& tr = display->getTransform();
- const auto& viewport = display->getViewport();
- Region visible = tr.transform(visibleRegion.intersect(viewport));
- const auto displayId = display->getId();
+void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
+ Region visible = transform.transform(visibleRegion.intersect(viewport));
+
if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+ ALOGE("[%s] failed to setPerFrameData: no HWC layer found for display %" PRIu64,
mName.string(), displayId);
return;
}
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 2c10357..d1b1697 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -33,7 +33,10 @@
bool useIdentityTransform);
bool isVisible() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
+
+ bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
protected:
FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 44e843e..ca49f6c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -32,6 +32,6 @@
return !isHiddenByPolicy();
}
-void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&) {}
+void ContainerLayer::setPerFrameData(DisplayId, const ui::Transform&, const Rect&, int32_t) {}
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 8eddc7f..413844b 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -33,9 +33,12 @@
bool useIdentityTransform) override;
bool isVisible() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
bool isCreatedFromMainThread() const override { return true; }
+
+ bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6f645df..f51daf3 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -28,12 +28,15 @@
#include <string.h>
#include <math.h>
+#include <android-base/stringprintf.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <gui/Surface.h>
#include <hardware/gralloc.h>
#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <system/window.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
@@ -211,22 +214,20 @@
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
- DisplayDevice::DisplayType type, int32_t id)
- : flinger(flinger), displayToken(displayToken), type(type), id(id) {}
+ const std::optional<DisplayId>& displayId)
+ : flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
: lastCompositionHadVisibleLayers(false),
mFlinger(args.flinger),
- mType(args.type),
- mId(args.id),
mDisplayToken(args.displayToken),
+ mId(args.displayId),
mNativeWindow(args.nativeWindow),
+ mGraphicBuffer(nullptr),
mDisplaySurface(args.displaySurface),
- mSurface{std::move(args.renderSurface)},
- mDisplayWidth(args.displayWidth),
- mDisplayHeight(args.displayHeight),
mDisplayInstallOrientation(args.displayInstallOrientation),
mPageFlipCount(0),
+ mIsVirtual(args.isVirtual),
mIsSecure(args.isSecure),
mLayerStack(NO_LAYER_STACK),
mOrientation(),
@@ -239,14 +240,12 @@
mHasHdr10(false),
mHasHLG(false),
mHasDolbyVision(false),
- mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
+ mSupportedPerFrameMetadata(args.supportedPerFrameMetadata),
+ mIsPrimary(args.isPrimary) {
populateColorModes(args.hwcColorModes);
ALOGE_IF(!mNativeWindow, "No native window was set for display");
ALOGE_IF(!mDisplaySurface, "No display surface was set for display");
- ALOGE_IF(!mSurface, "No render surface was set for display");
- ALOGE_IF(mDisplayWidth <= 0 || mDisplayHeight <= 0,
- "Invalid dimensions of %d x %d were set for display", mDisplayWidth, mDisplayHeight);
std::vector<Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
for (Hdr hdrType : types) {
@@ -285,6 +284,14 @@
}
mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
+ ANativeWindow* const window = mNativeWindow.get();
+
+ int status = native_window_api_connect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
+ ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
+
+ mDisplayWidth = ANativeWindow_getWidth(window);
+ mDisplayHeight = ANativeWindow_getHeight(window);
+
// initialize the display orientation transform.
setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
}
@@ -292,16 +299,12 @@
DisplayDevice::~DisplayDevice() = default;
void DisplayDevice::disconnect(HWComposer& hwc) {
- if (mId >= 0) {
- hwc.disconnectDisplay(mId);
- mId = -1;
+ if (mId) {
+ hwc.disconnectDisplay(*mId);
+ mId.reset();
}
}
-bool DisplayDevice::isValid() const {
- return mFlinger != nullptr;
-}
-
int DisplayDevice::getWidth() const {
return mDisplayWidth;
}
@@ -323,7 +326,6 @@
void DisplayDevice::flip() const
{
- mFlinger->getRenderEngine().checkErrors();
mPageFlipCount++;
}
@@ -333,9 +335,11 @@
status_t DisplayDevice::prepareFrame(HWComposer& hwc,
std::vector<CompositionInfo>& compositionData) {
- status_t error = hwc.prepare(*this, compositionData);
- if (error != NO_ERROR) {
- return error;
+ if (mId) {
+ status_t error = hwc.prepare(*mId, compositionData);
+ if (error != NO_ERROR) {
+ return error;
+ }
}
DisplaySurface::CompositionType compositionType;
@@ -356,9 +360,71 @@
return mDisplaySurface->prepareFrame(compositionType);
}
-void DisplayDevice::swapBuffers(HWComposer& hwc) const {
+sp<GraphicBuffer> DisplayDevice::dequeueBuffer() {
+ int fd;
+ ANativeWindowBuffer* buffer;
+
+ status_t res = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
+
+ if (res != NO_ERROR) {
+ ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
+ getDisplayName().c_str(), res);
+ // Return fast here as we can't do much more - any rendering we do
+ // now will just be wrong.
+ return mGraphicBuffer;
+ }
+
+ ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
+ mGraphicBuffer->getNativeBuffer()->handle);
+ mGraphicBuffer = GraphicBuffer::from(buffer);
+
+ // Block until the buffer is ready
+ // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
+ // that the gl driver can block instead.
+ if (fd >= 0) {
+ sync_wait(fd, -1);
+ close(fd);
+ }
+
+ return mGraphicBuffer;
+}
+
+void DisplayDevice::queueBuffer(HWComposer& hwc) {
if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) {
- mSurface->swapBuffers();
+ // hasFlipClientTargetRequest could return true even if we haven't
+ // dequeued a buffer before. Try dequeueing one if we don't have a
+ // buffer ready.
+ if (mGraphicBuffer == nullptr) {
+ ALOGI("Attempting to queue a client composited buffer without one "
+ "previously dequeued for display [%s]. Attempting to dequeue "
+ "a scratch buffer now",
+ mDisplayName.c_str());
+ // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
+ // after a successful call to queueBuffer, or if dequeueBuffer has
+ // never been called.
+ dequeueBuffer();
+ }
+
+ if (mGraphicBuffer == nullptr) {
+ ALOGE("No buffer is ready for display [%s]", mDisplayName.c_str());
+ } else {
+ int fd = mBufferReady.release();
+
+ status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(), fd);
+ if (res != NO_ERROR) {
+ ALOGE("Error when queueing buffer for display [%s]: %d", mDisplayName.c_str(), res);
+ // We risk blocking on dequeueBuffer if the primary display failed
+ // to queue up its buffer, so crash here.
+ if (isPrimary()) {
+ LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", res);
+ } else {
+ mNativeWindow->cancelBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(), fd);
+ }
+ }
+ mGraphicBuffer = nullptr;
+ }
}
status_t result = mDisplaySurface->advanceFrame();
@@ -367,16 +433,10 @@
}
}
-void DisplayDevice::onSwapBuffersCompleted() const {
+void DisplayDevice::onPresentDisplayCompleted() {
mDisplaySurface->onFrameCommitted();
}
-bool DisplayDevice::makeCurrent() const {
- bool success = mFlinger->getRenderEngine().setCurrentSurface(*mSurface);
- setViewportAndProjection();
- return success;
-}
-
void DisplayDevice::setViewportAndProjection() const {
size_t w = mDisplayWidth;
size_t h = mDisplayHeight;
@@ -384,6 +444,13 @@
mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0);
}
+void DisplayDevice::finishBuffer() {
+ mBufferReady = mFlinger->getRenderEngine().flush();
+ if (mBufferReady.get() < 0) {
+ mFlinger->getRenderEngine().finish();
+ }
+}
+
const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
return mDisplaySurface->getClientTargetAcquireFence();
}
@@ -532,19 +599,10 @@
void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
dirtyRegion.set(getBounds());
- mSurface->setNativeWindow(nullptr);
-
mDisplaySurface->resizeBuffers(newWidth, newHeight);
- ANativeWindow* const window = mNativeWindow.get();
- mSurface->setNativeWindow(window);
- mDisplayWidth = mSurface->getWidth();
- mDisplayHeight = mSurface->getHeight();
-
- LOG_FATAL_IF(mDisplayWidth != newWidth,
- "Unable to set new width to %d", newWidth);
- LOG_FATAL_IF(mDisplayHeight != newHeight,
- "Unable to set new height to %d", newHeight);
+ mDisplayWidth = newWidth;
+ mDisplayHeight = newHeight;
}
void DisplayDevice::setProjection(int orientation,
@@ -599,7 +657,7 @@
// need to take care of primary display rotation for mGlobalTransform
// for case if the panel is not installed aligned with device orientation
- if (mType == DisplayType::DISPLAY_PRIMARY) {
+ if (isPrimary()) {
DisplayDevice::orientationToTransfrom(
(orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1),
w, h, &R);
@@ -646,17 +704,23 @@
return sPrimaryDisplayOrientation;
}
+std::string DisplayDevice::getDebugName() const {
+ const auto id = mId ? base::StringPrintf("%" PRIu64 ", ", *mId) : std::string();
+ return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
+ isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
+ mDisplayName.c_str());
+}
+
void DisplayDevice::dump(String8& result) const {
const ui::Transform& tr(mGlobalTransform);
ANativeWindow* const window = mNativeWindow.get();
- result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.c_str());
- result.appendFormat(" type=%x, ID=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
- "(%d:%d:%d:%d), orient=%2d (type=%08x), "
- "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
- mType, mId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
- mSurface->queryRedSize(), mSurface->queryGreenSize(),
- mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation,
- tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
+ result.appendFormat("+ %s\n", getDebugName().c_str());
+ result.appendFormat(" layerStack=%u, (%4dx%4d), ANativeWindow=%p "
+ "format=%d, orient=%2d (type=%08x), flips=%u, isSecure=%d, "
+ "powerMode=%d, activeConfig=%d, numLayers=%zu\n",
+ mLayerStack, mDisplayWidth, mDisplayHeight, window,
+ ANativeWindow_getFormat(window), mOrientation, tr.getType(),
+ getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
mVisibleLayersSortedByZ.size());
result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
"transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
@@ -667,9 +731,9 @@
auto const surface = static_cast<Surface*>(window);
ui::Dataspace dataspace = surface->getBuffersDataSpace();
result.appendFormat(" wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
- mHasWideColorGamut, mHasHdr10,
- decodeColorMode(mActiveColorMode).c_str(),
- dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
+ mHasWideColorGamut, mHasHdr10, decodeColorMode(mActiveColorMode).c_str(),
+ dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(),
+ dataspace);
String8 surfaceDump;
mDisplaySurface->dumpAsString(surfaceDump);
@@ -693,7 +757,7 @@
const Dataspace dataspace = colorModeToDataspace(mode);
const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
- ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mId,
+ ALOGV("%s: map (%s, %s) to (%s, %s, %s)", getDebugName().c_str(),
dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
decodeRenderIntent(intent).c_str(),
dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 38482c9..eb2c5c3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -20,27 +20,29 @@
#include <stdlib.h>
#include <memory>
+#include <optional>
#include <string>
#include <unordered_map>
+#include <android/native_window.h>
#include <binder/IBinder.h>
#include <gui/LayerState.h>
#include <hardware/hwcomposer_defs.h>
#include <math/mat4.h>
-#include <renderengine/Surface.h>
+#include <renderengine/RenderEngine.h>
+#include <system/window.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
#include <ui/Transform.h>
-#include <utils/RefBase.h>
#include <utils/Mutex.h>
+#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Timers.h>
+#include "DisplayHardware/DisplayIdentification.h"
#include "RenderArea.h"
-struct ANativeWindow;
-
namespace android {
class DisplaySurface;
@@ -66,25 +68,15 @@
Region undefinedRegion;
bool lastCompositionHadVisibleLayers;
- enum DisplayType {
- DISPLAY_ID_INVALID = -1,
- DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY,
- DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL,
- DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL,
- NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
- };
-
enum {
NO_LAYER_STACK = 0xFFFFFFFF,
};
explicit DisplayDevice(DisplayDeviceCreationArgs&& args);
-
~DisplayDevice();
- // whether this is a valid object. An invalid DisplayDevice is returned
- // when an non existing id is requested
- bool isValid() const;
+ bool isVirtual() const { return mIsVirtual; }
+ bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
@@ -118,11 +110,9 @@
bool needsFiltering() const { return mNeedsFiltering; }
uint32_t getLayerStack() const { return mLayerStack; }
- int32_t getDisplayType() const { return mType; }
- bool isPrimary() const { return mType == DISPLAY_PRIMARY; }
- bool isVirtual() const { return mType == DISPLAY_VIRTUAL; }
- int32_t getId() const { return mId; }
- const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
+
+ const std::optional<DisplayId>& getId() const { return mId; }
+ const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
@@ -156,10 +146,13 @@
ui::Dataspace* outDataspace, ui::ColorMode* outMode,
ui::RenderIntent* outIntent) const;
- void swapBuffers(HWComposer& hwc) const;
+ // Queues the drawn buffer for consumption by HWC.
+ void queueBuffer(HWComposer& hwc);
+ // Allocates a buffer as scratch space for GPU composition
+ sp<GraphicBuffer> dequeueBuffer();
// called after h/w composer has completed its set() call
- void onSwapBuffersCompleted() const;
+ void onPresentDisplayCompleted();
Rect getBounds() const {
return Rect(mDisplayWidth, mDisplayHeight);
@@ -169,7 +162,11 @@
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
- bool makeCurrent() const;
+ // Acquires a new buffer for GPU composition.
+ void readyNewBuffer();
+ // Marks the current buffer has finished, so that it can be presented and
+ // swapped out.
+ void finishBuffer();
void setViewportAndProjection() const;
const sp<Fence>& getClientTargetAcquireFence() const;
@@ -203,28 +200,32 @@
* Debugging
*/
uint32_t getPageFlipCount() const;
+ std::string getDebugName() const;
void dump(String8& result) const;
private:
- /*
- * Constants, set during initialization
- */
- sp<SurfaceFlinger> mFlinger;
- DisplayType mType;
- int32_t mId;
- wp<IBinder> mDisplayToken;
+ const sp<SurfaceFlinger> mFlinger;
+ const wp<IBinder> mDisplayToken;
+
+ std::optional<DisplayId> mId;
// ANativeWindow this display is rendering into
sp<ANativeWindow> mNativeWindow;
+ // Current buffer that this display can render to.
+ sp<GraphicBuffer> mGraphicBuffer;
sp<DisplaySurface> mDisplaySurface;
+ // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
+ // that drawing to the buffer is now complete.
+ base::unique_fd mBufferReady;
- std::unique_ptr<renderengine::Surface> mSurface;
int mDisplayWidth;
int mDisplayHeight;
const int mDisplayInstallOrientation;
mutable uint32_t mPageFlipCount;
std::string mDisplayName;
- bool mIsSecure;
+
+ const bool mIsVirtual;
+ const bool mIsSecure;
/*
* Can only accessed from the main thread, these members
@@ -298,13 +299,16 @@
const ui::ColorMode mode, const ui::RenderIntent intent);
std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
+
+ // TODO(b/74619554): Remove special cases for primary display.
+ const bool mIsPrimary;
};
struct DisplayDeviceState {
- bool isVirtual() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
+ bool isVirtual() const { return !displayId.has_value(); }
int32_t sequenceId = sNextSequenceId++;
- DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_ID_INVALID;
+ std::optional<DisplayId> displayId;
sp<IGraphicBufferProducer> surface;
uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
Rect viewport;
@@ -323,25 +327,23 @@
// We use a constructor to ensure some of the values are set, without
// assuming a default value.
DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
- DisplayDevice::DisplayType type, int32_t id);
+ const std::optional<DisplayId>& displayId);
const sp<SurfaceFlinger> flinger;
const wp<IBinder> displayToken;
- const DisplayDevice::DisplayType type;
- const int32_t id;
+ const std::optional<DisplayId> displayId;
+ bool isVirtual{false};
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<DisplaySurface> displaySurface;
- std::unique_ptr<renderengine::Surface> renderSurface;
- int displayWidth{0};
- int displayHeight{0};
int displayInstallOrientation{DisplayState::eOrientationDefault};
bool hasWideColorGamut{false};
HdrCapabilities hdrCapabilities;
int32_t supportedPerFrameMetadata{0};
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
int initialPowerMode{HWC_POWER_MODE_NORMAL};
+ bool isPrimary{false};
};
class DisplayRenderArea : public RenderArea {
@@ -349,10 +351,11 @@
DisplayRenderArea(const sp<const DisplayDevice> device,
ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
: DisplayRenderArea(device, device->getBounds(), device->getWidth(), device->getHeight(),
- rotation) {}
+ device->getCompositionDataSpace(), rotation) {}
DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
- uint32_t reqHeight, ui::Transform::orientation_flags rotation)
- : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE,
+ uint32_t reqHeight, ui::Dataspace reqDataSpace,
+ ui::Transform::orientation_flags rotation)
+ : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
getDisplayRotation(rotation, device->getInstallOrientation())),
mDevice(device),
mSourceCrop(sourceCrop) {}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index dcc4138..ec240f3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -33,6 +33,9 @@
constexpr size_t kEdidHeaderLength = 5;
+constexpr uint16_t kFallbackEdidManufacturerId = 0;
+constexpr uint16_t kVirtualEdidManufacturerId = 0xffffu;
+
std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) {
if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) {
return {};
@@ -165,7 +168,8 @@
return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt;
}
-std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData& data) {
+std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
+ uint8_t port, const DisplayIdentificationData& data) {
if (!isEdid(data)) {
ALOGE("Display identification data has unknown format.");
return {};
@@ -179,7 +183,16 @@
// Hash display name instead of using product code or serial number, since the latter have been
// observed to change on some displays with multiple inputs.
const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
- return getEdidDisplayId(port, edid->manufacturerId, hash);
+ return DisplayIdentificationInfo{getEdidDisplayId(port, edid->manufacturerId, hash),
+ std::string(edid->displayName)};
+}
+
+DisplayId getFallbackDisplayId(uint8_t port) {
+ return getEdidDisplayId(port, kFallbackEdidManufacturerId, 0);
+}
+
+DisplayId getVirtualDisplayId(uint32_t id) {
+ return getEdidDisplayId(0, kVirtualEdidManufacturerId, id);
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 379f2d3..1f2e789 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -19,6 +19,7 @@
#include <array>
#include <cstdint>
#include <optional>
+#include <string>
#include <string_view>
#include <vector>
@@ -27,6 +28,11 @@
using DisplayId = uint64_t;
using DisplayIdentificationData = std::vector<uint8_t>;
+struct DisplayIdentificationInfo {
+ DisplayId id;
+ std::string name;
+};
+
// NUL-terminated plug and play ID.
using PnpId = std::array<char, 4>;
@@ -40,6 +46,10 @@
std::optional<Edid> parseEdid(const DisplayIdentificationData&);
std::optional<PnpId> getPnpId(uint16_t manufacturerId);
-std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData&);
+std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
+ uint8_t port, const DisplayIdentificationData&);
+
+DisplayId getFallbackDisplayId(uint8_t port);
+DisplayId getVirtualDisplayId(uint32_t id);
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index e6d7834..f3f8d9d 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -52,26 +52,25 @@
*
*/
-FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
- const sp<IGraphicBufferConsumer>& consumer) :
- ConsumerBase(consumer),
- mDisplayType(disp),
- mCurrentBufferSlot(-1),
- mCurrentBuffer(),
- mCurrentFence(Fence::NO_FENCE),
- mHwc(hwc),
- mHasPendingRelease(false),
- mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mPreviousBuffer()
-{
- ALOGV("Creating for display %d", disp);
+FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId,
+ const sp<IGraphicBufferConsumer>& consumer)
+ : ConsumerBase(consumer),
+ mDisplayId(displayId),
+ mCurrentBufferSlot(-1),
+ mCurrentBuffer(),
+ mCurrentFence(Fence::NO_FENCE),
+ mHwc(hwc),
+ mHasPendingRelease(false),
+ mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mPreviousBuffer() {
+ ALOGV("Creating for display %" PRIu64, displayId);
mName = "FramebufferSurface";
mConsumer->setConsumerName(mName);
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
- const auto& activeConfig = mHwc.getActiveConfig(disp);
+ const auto& activeConfig = mHwc.getActiveConfig(displayId);
mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
activeConfig->getHeight());
mConsumer->setMaxAcquiredBufferCount(
@@ -142,8 +141,7 @@
mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
&outSlot, &outBuffer);
outDataspace = static_cast<Dataspace>(item.mDataSpace);
- status_t result =
- mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
+ status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
if (result != NO_ERROR) {
ALOGE("error posting framebuffer: %d", result);
return result;
@@ -161,7 +159,7 @@
void FramebufferSurface::onFrameCommitted() {
if (mHasPendingRelease) {
- sp<Fence> fence = mHwc.getPresentFence(mDisplayType);
+ sp<Fence> fence = mHwc.getPresentFence(mDisplayId);
if (fence->isValid()) {
status_t result = addReleaseFence(mPreviousBufferSlot,
mPreviousBuffer, fence);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 0fd8e9e..2431dfd 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
+#include "DisplayIdentification.h"
#include "DisplaySurface.h"
#include "HWComposerBufferCache.h"
@@ -38,7 +39,8 @@
class FramebufferSurface : public ConsumerBase,
public DisplaySurface {
public:
- FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
+ FramebufferSurface(HWComposer& hwc, DisplayId displayId,
+ const sp<IGraphicBufferConsumer>& consumer);
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
@@ -63,8 +65,7 @@
status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer,
sp<Fence>& outFence, ui::Dataspace& outDataspace);
- // mDisplayType must match one of the HWC display types
- int mDisplayType;
+ const DisplayId mDisplayId;
// mCurrentBufferIndex is the slot index of the current buffer or
// INVALID_BUFFER_SLOT to indicate that either there is no current buffer
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 3a40648..393041d 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -184,7 +184,6 @@
auto newDisplay = std::make_unique<Display>(
*mComposer.get(), mPowerAdvisor, mCapabilities, displayId, displayType);
- newDisplay->setFrequencyScaleParameters(mFrequencyScaler);
newDisplay->setConnected(true);
mDisplays.emplace(displayId, std::move(newDisplay));
} else if (connection == Connection::Disconnected) {
@@ -224,14 +223,6 @@
return static_cast<Error>(mComposer->executeCommands());
}
-void Device::setDisplayFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler) {
- mFrequencyScaler = frequencyScaler;
-}
-
-Device::FrequencyScaler Device::getDisplayFrequencyScaleParameters() {
- return mFrequencyScaler;
-}
-
// Display methods
Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
@@ -271,7 +262,6 @@
mWidth(-1),
mHeight(-1),
mVsyncPeriod(-1),
- mFrequencyScaler(display.mFrequencyScaler),
mDpiX(-1),
mDpiY(-1) {}
@@ -711,10 +701,6 @@
mIsConnected = connected;
}
-void Display::setFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler) {
- mFrequencyScaler = frequencyScaler;
-}
-
int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
{
int32_t value = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 363adb5..d274631 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,7 +23,6 @@
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11
-#include <cutils/properties.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/GraphicTypes.h>
@@ -85,11 +84,6 @@
public:
explicit Device(std::unique_ptr<android::Hwc2::Composer> composer);
- struct FrequencyScaler {
- int32_t multiplier = 1;
- int32_t divisor = 1;
- };
-
void registerCallback(ComposerCallback* callback, int32_t sequenceId);
// Required by HWC2
@@ -121,9 +115,6 @@
// This method provides an explicit way to flush state changes to HWC.
Error flushCommands();
- void setDisplayFrequencyScaleParameters(FrequencyScaler frequecyScaler);
- FrequencyScaler getDisplayFrequencyScaleParameters();
-
private:
// Initialization methods
@@ -134,7 +125,6 @@
std::unordered_set<Capability> mCapabilities;
std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
- FrequencyScaler mFrequencyScaler;
bool mRegisteredCallback = false;
};
@@ -199,8 +189,7 @@
int32_t getWidth() const { return mWidth; }
int32_t getHeight() const { return mHeight; }
- nsecs_t getVsyncPeriod() const {
- return mVsyncPeriod * mFrequencyScaler.multiplier / mFrequencyScaler.divisor; }
+ nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
float getDpiX() const { return mDpiX; }
float getDpiY() const { return mDpiY; }
@@ -213,7 +202,6 @@
int32_t mWidth;
int32_t mHeight;
nsecs_t mVsyncPeriod;
- Device::FrequencyScaler mFrequencyScaler;
float mDpiX;
float mDpiY;
};
@@ -281,7 +269,6 @@
hwc2_display_t getId() const { return mId; }
bool isConnected() const { return mIsConnected; }
void setConnected(bool connected); // For use by Device only
- void setFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler);
private:
int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
@@ -306,7 +293,6 @@
hwc2_display_t mId;
bool mIsConnected;
DisplayType mType;
- Device::FrequencyScaler mFrequencyScaler;
std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6b56ca4..4c472b8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -58,15 +58,15 @@
ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
#define LOG_DISPLAY_ERROR(displayId, msg) \
- ALOGE("%s failed for display %d: %s", __FUNCTION__, displayId, msg)
+ ALOGE("%s failed for display %" PRIu64 ": %s", __FUNCTION__, displayId, msg)
-#define LOG_HWC_ERROR(what, error, displayId) \
- ALOGE("%s: %s failed for display %d: %s (%d)", __FUNCTION__, what, displayId, \
+#define LOG_HWC_ERROR(what, error, displayId) \
+ ALOGE("%s: %s failed for display %" PRIu64 ": %s (%d)", __FUNCTION__, what, displayId, \
to_string(error).c_str(), static_cast<int32_t>(error))
#define RETURN_IF_INVALID_DISPLAY(displayId, ...) \
do { \
- if (!isValidDisplay(displayId)) { \
+ if (mDisplayData.count(displayId) == 0) { \
LOG_DISPLAY_ERROR(displayId, "Invalid display"); \
return __VA_ARGS__; \
} \
@@ -92,7 +92,9 @@
HWComposer::HWComposer(std::unique_ptr<android::Hwc2::Composer> composer)
: mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}
-HWComposer::~HWComposer() = default;
+HWComposer::~HWComposer() {
+ mDisplayData.clear();
+}
void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
int32_t sequenceId) {
@@ -116,11 +118,6 @@
return mHwcDevice->getCapabilities().count(capability) > 0;
}
-bool HWComposer::isValidDisplay(int32_t displayId) const {
- return static_cast<size_t>(displayId) < mDisplayData.size() &&
- mDisplayData[displayId].hwcDisplay;
-}
-
void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
bool valid = true;
switch (from) {
@@ -146,52 +143,50 @@
}
}
-std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
- HWC2::Connection connection) {
- if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
- ALOGE("Invalid display type of %d", displayType);
- return {};
- }
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
+ HWC2::Connection connection) {
+ std::optional<DisplayIdentificationInfo> info;
- ALOGV("hotplug: %" PRIu64 ", %s %s", hwcDisplayId,
- displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
- to_string(connection).c_str());
- mHwcDevice->onHotplug(hwcDisplayId, connection);
-
- std::optional<DisplayId> displayId;
-
- if (connection == HWC2::Connection::Connected) {
- uint8_t port;
- DisplayIdentificationData data;
- if (getDisplayIdentificationData(hwcDisplayId, &port, &data)) {
- displayId = generateDisplayId(port, data);
- ALOGE_IF(!displayId, "Failed to generate stable ID for display %" PRIu64, hwcDisplayId);
+ if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
+ info = DisplayIdentificationInfo{*displayId, std::string()};
+ } else {
+ if (connection == HWC2::Connection::Disconnected) {
+ ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
+ return {};
}
+
+ info = onHotplugConnect(hwcDisplayId);
+ if (!info) return {};
}
+ ALOGV("%s: %s %s display %" PRIu64 " with HWC ID %" PRIu64, __FUNCTION__,
+ to_string(connection).c_str(),
+ hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external", info->id, hwcDisplayId);
+
+ mHwcDevice->onHotplug(hwcDisplayId, connection);
+
// Disconnect is handled through HWComposer::disconnectDisplay via
// SurfaceFlinger's onHotplugReceived callback handling
if (connection == HWC2::Connection::Connected) {
- mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
- mHwcDisplaySlots[hwcDisplayId] = displayType;
+ mDisplayData[info->id].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
+ mPhysicalDisplayIdMap[hwcDisplayId] = info->id;
}
- return displayId;
+ return info;
}
-bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplayId) {
- const auto it = mHwcDisplaySlots.find(hwcDisplayId);
- if (it == mHwcDisplaySlots.end()) {
- LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid display");
+bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) {
+ const auto displayId = toPhysicalDisplayId(hwcDisplayId);
+ if (!displayId) {
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
return false;
}
- const int32_t displayId = it->second;
- RETURN_IF_INVALID_DISPLAY(displayId, false);
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
- const auto& displayData = mDisplayData[displayId];
+ const auto& displayData = mDisplayData[*displayId];
if (displayData.isVirtual) {
- LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
+ LOG_DISPLAY_ERROR(*displayId, "Invalid operation on virtual display");
return false;
}
@@ -202,31 +197,26 @@
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
- if (timestamp == mLastHwVSync[displayId]) {
- ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
- timestamp);
+ if (timestamp == mLastHwVSync[*displayId]) {
+ ALOGW("Ignoring duplicate VSYNC event from HWC for display %" PRIu64 " (t=%" PRId64 ")",
+ *displayId, timestamp);
return false;
}
- mLastHwVSync[displayId] = timestamp;
+ mLastHwVSync[*displayId] = timestamp;
}
- if (outDisplayId) {
- *outDisplayId = displayId;
- }
-
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", displayId);
- ATRACE_INT(tag, ++mVSyncCounts[displayId] & 1);
+ const auto tag = "HW_VSYNC_" + std::to_string(*displayId);
+ ATRACE_INT(tag.c_str(), ++mVSyncCounts[*displayId] & 1);
return true;
}
-status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
- ui::PixelFormat* format, int32_t *outId) {
+std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
+ ui::PixelFormat* format) {
if (mRemainingHwcVirtualDisplays == 0) {
ALOGE("%s: No remaining virtual displays", __FUNCTION__);
- return NO_MEMORY;
+ return {};
}
if (SurfaceFlinger::maxVirtualDisplaySize != 0 &&
@@ -234,41 +224,33 @@
height > SurfaceFlinger::maxVirtualDisplaySize)) {
ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width,
height, SurfaceFlinger::maxVirtualDisplaySize);
- return INVALID_OPERATION;
+ return {};
}
-
HWC2::Display* display;
auto error = mHwcDevice->createVirtualDisplay(width, height, format,
&display);
if (error != HWC2::Error::None) {
ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
- return NO_MEMORY;
+ return {};
}
- size_t displaySlot = 0;
- if (!mFreeDisplaySlots.empty()) {
- displaySlot = *mFreeDisplaySlots.begin();
- mFreeDisplaySlots.erase(displaySlot);
- } else if (mDisplayData.size() < INT32_MAX) {
- // Don't bother allocating a slot larger than we can return
- displaySlot = mDisplayData.size();
- mDisplayData.resize(displaySlot + 1);
+ DisplayId displayId;
+ if (mFreeVirtualDisplayIds.empty()) {
+ displayId = getVirtualDisplayId(mNextVirtualDisplayId++);
} else {
- ALOGE("%s: Unable to allocate a display slot", __FUNCTION__);
- return NO_MEMORY;
+ displayId = *mFreeVirtualDisplayIds.begin();
+ mFreeVirtualDisplayIds.erase(displayId);
}
- auto& displayData = mDisplayData[displaySlot];
+ auto& displayData = mDisplayData[displayId];
displayData.hwcDisplay = display;
displayData.isVirtual = true;
--mRemainingHwcVirtualDisplays;
- *outId = static_cast<int32_t>(displaySlot);
-
- return NO_ERROR;
+ return displayId;
}
-HWC2::Layer* HWComposer::createLayer(int32_t displayId) {
+HWC2::Layer* HWComposer::createLayer(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
auto display = mDisplayData[displayId].hwcDisplay;
@@ -278,7 +260,7 @@
return layer;
}
-void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) {
+void HWComposer::destroyLayer(DisplayId displayId, HWC2::Layer* layer) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto display = mDisplayData[displayId].hwcDisplay;
@@ -286,7 +268,8 @@
RETURN_IF_HWC_ERROR(error, displayId);
}
-nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const {
+nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, 0);
// this returns the last refresh timestamp.
// if the last one is not available, we estimate it based on
// the refresh period and whatever closest timestamp we have.
@@ -296,17 +279,17 @@
return now - ((now - mLastHwVSync[displayId]) % vsyncPeriod);
}
-bool HWComposer::isConnected(int32_t displayId) const {
+bool HWComposer::isConnected(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, false);
- return mDisplayData[displayId].hwcDisplay->isConnected();
+ return mDisplayData.at(displayId).hwcDisplay->isConnected();
}
-std::vector<std::shared_ptr<const HWC2::Display::Config>>
- HWComposer::getConfigs(int32_t displayId) const {
+std::vector<std::shared_ptr<const HWC2::Display::Config>> HWComposer::getConfigs(
+ DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
- auto& displayData = mDisplayData[displayId];
- auto configs = mDisplayData[displayId].hwcDisplay->getConfigs();
+ const auto& displayData = mDisplayData.at(displayId);
+ auto configs = displayData.hwcDisplay->getConfigs();
if (displayData.configMap.empty()) {
for (size_t i = 0; i < configs.size(); ++i) {
displayData.configMap[i] = configs[i];
@@ -315,12 +298,12 @@
return configs;
}
-std::shared_ptr<const HWC2::Display::Config>
- HWComposer::getActiveConfig(int32_t displayId) const {
+std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
+ DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
std::shared_ptr<const HWC2::Display::Config> config;
- auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfig(&config);
if (error == HWC2::Error::BadConfig) {
LOG_DISPLAY_ERROR(displayId, "No active config");
return nullptr;
@@ -336,11 +319,11 @@
return config;
}
-int HWComposer::getActiveConfigIndex(int32_t displayId) const {
+int HWComposer::getActiveConfigIndex(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, -1);
int index;
- auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfigIndex(&index);
if (error == HWC2::Error::BadConfig) {
LOG_DISPLAY_ERROR(displayId, "No active config");
return -1;
@@ -356,17 +339,17 @@
return index;
}
-std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const {
+std::vector<ui::ColorMode> HWComposer::getColorModes(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
std::vector<ui::ColorMode> modes;
- auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getColorModes(&modes);
RETURN_IF_HWC_ERROR(error, displayId, {});
return modes;
}
-status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode,
- ui::RenderIntent renderIntent) {
+status_t HWComposer::setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+ ui::RenderIntent renderIntent) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -379,8 +362,7 @@
return NO_ERROR;
}
-
-void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
+void HWComposer::setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
@@ -401,37 +383,30 @@
displayData.vsyncEnabled = enabled;
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", displayId);
- ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
+ const auto tag = "HW_VSYNC_ON_" + std::to_string(displayId);
+ ATRACE_INT(tag.c_str(), enabled == HWC2::Vsync::Enable ? 1 : 0);
}
}
-status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
- ui::Dataspace dataspace) {
+status_t HWComposer::setClientTarget(DisplayId displayId, uint32_t slot,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
+ ui::Dataspace dataspace) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- ALOGV("setClientTarget for display %d", displayId);
+ ALOGV("setClientTarget for display %" PRIu64, displayId);
auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace);
RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
return NO_ERROR;
}
-status_t HWComposer::prepare(DisplayDevice& display,
- std::vector<CompositionInfo>& compositionData) {
+status_t HWComposer::prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) {
ATRACE_CALL();
- Mutex::Autolock _l(mDisplayLock);
- const auto displayId = display.getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
- ALOGV("Skipping HWComposer prepare for non-HWC display");
- return NO_ERROR;
- }
-
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ Mutex::Autolock _l(mDisplayLock);
+
auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
if (!hwcDisplay->isConnected()) {
@@ -501,7 +476,8 @@
changedTypes[&*hwcLayer]);
compositionInfo.compositionType = changedTypes[&*hwcLayer];
compositionInfo.layer->mLayer->setCompositionType(displayId,
- compositionInfo.compositionType, false);
+ compositionInfo.compositionType,
+ false);
}
switch (compositionInfo.compositionType) {
@@ -540,49 +516,48 @@
return NO_ERROR;
}
-bool HWComposer::hasDeviceComposition(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasDeviceComposition(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are never composed by
// the device
return false;
}
- RETURN_IF_INVALID_DISPLAY(displayId, false);
- return mDisplayData[displayId].hasDeviceComposition;
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
+ return mDisplayData.at(*displayId).hasDeviceComposition;
}
-bool HWComposer::hasFlipClientTargetRequest(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are never composed by
// the device
return false;
}
- RETURN_IF_INVALID_DISPLAY(displayId, false);
- return ((static_cast<uint32_t>(mDisplayData[displayId].displayRequests) &
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
+ return ((static_cast<uint32_t>(mDisplayData.at(*displayId).displayRequests) &
static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
}
-bool HWComposer::hasClientComposition(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasClientComposition(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are always composed by
// the client
return true;
}
- RETURN_IF_INVALID_DISPLAY(displayId, true);
- return mDisplayData[displayId].hasClientComposition;
+ RETURN_IF_INVALID_DISPLAY(*displayId, true);
+ return mDisplayData.at(*displayId).hasClientComposition;
}
-sp<Fence> HWComposer::getPresentFence(int32_t displayId) const {
+sp<Fence> HWComposer::getPresentFence(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
- return mDisplayData[displayId].lastPresentFence;
+ return mDisplayData.at(displayId).lastPresentFence;
}
-sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
- HWC2::Layer* layer) const {
+sp<Fence> HWComposer::getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
- auto displayFences = mDisplayData[displayId].releaseFences;
+ auto displayFences = mDisplayData.at(displayId).releaseFences;
if (displayFences.count(layer) == 0) {
ALOGV("getLayerReleaseFence: Release fence not found");
return Fence::NO_FENCE;
@@ -590,7 +565,7 @@
return displayFences[layer];
}
-status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) {
+status_t HWComposer::presentAndGetReleaseFences(DisplayId displayId) {
ATRACE_CALL();
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -618,8 +593,7 @@
return NO_ERROR;
}
-status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) {
- ALOGV("setPowerMode(%d, %d)", displayId, intMode);
+status_t HWComposer::setPowerMode(DisplayId displayId, int32_t intMode) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto& displayData = mDisplayData[displayId];
@@ -675,7 +649,7 @@
return NO_ERROR;
}
-status_t HWComposer::setActiveConfig(int32_t displayId, size_t configId) {
+status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -689,8 +663,7 @@
return NO_ERROR;
}
-status_t HWComposer::setColorTransform(int32_t displayId,
- const mat4& transform) {
+status_t HWComposer::setColorTransform(DisplayId displayId, const mat4& transform) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -702,26 +675,34 @@
return NO_ERROR;
}
-void HWComposer::disconnectDisplay(int32_t displayId) {
+void HWComposer::disconnectDisplay(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
// If this was a virtual display, add its slot back for reuse by future
// virtual displays
if (displayData.isVirtual) {
- mFreeDisplaySlots.insert(displayId);
+ mFreeVirtualDisplayIds.insert(displayId);
++mRemainingHwcVirtualDisplays;
}
const auto hwcDisplayId = displayData.hwcDisplay->getId();
- mHwcDisplaySlots.erase(hwcDisplayId);
- displayData = DisplayData();
+ mPhysicalDisplayIdMap.erase(hwcDisplayId);
+ mDisplayData.erase(displayId);
+ mVSyncCounts.erase(displayId);
+
+ // TODO(b/74619554): Select internal/external display from remaining displays.
+ if (hwcDisplayId == mInternalHwcDisplayId) {
+ mInternalHwcDisplayId.reset();
+ } else if (hwcDisplayId == mExternalHwcDisplayId) {
+ mExternalHwcDisplayId.reset();
+ }
mHwcDevice->destroyDisplay(hwcDisplayId);
}
-status_t HWComposer::setOutputBuffer(int32_t displayId,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
+status_t HWComposer::setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buffer) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto& displayData = mDisplayData[displayId];
@@ -735,13 +716,12 @@
return NO_ERROR;
}
-void HWComposer::clearReleaseFences(int32_t displayId) {
+void HWComposer::clearReleaseFences(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId);
mDisplayData[displayId].releaseFences.clear();
}
-status_t HWComposer::getHdrCapabilities(
- int32_t displayId, HdrCapabilities* outCapabilities) {
+status_t HWComposer::getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
@@ -750,22 +730,22 @@
return NO_ERROR;
}
-int32_t HWComposer::getSupportedPerFrameMetadata(int32_t displayId) const {
+int32_t HWComposer::getSupportedPerFrameMetadata(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, 0);
- return mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata();
+ return mDisplayData.at(displayId).hwcDisplay->getSupportedPerFrameMetadata();
}
-std::vector<ui::RenderIntent> HWComposer::getRenderIntents(int32_t displayId,
- ui::ColorMode colorMode) const {
+std::vector<ui::RenderIntent> HWComposer::getRenderIntents(DisplayId displayId,
+ ui::ColorMode colorMode) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
std::vector<ui::RenderIntent> renderIntents;
- auto error = mDisplayData[displayId].hwcDisplay->getRenderIntents(colorMode, &renderIntents);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getRenderIntents(colorMode, &renderIntents);
RETURN_IF_HWC_ERROR(error, displayId, {});
return renderIntents;
}
-mat4 HWComposer::getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace) {
+mat4 HWComposer::getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace) {
RETURN_IF_INVALID_DISPLAY(displayId, {});
mat4 matrix;
@@ -806,23 +786,67 @@
result.append(mHwcDevice->dump().c_str());
}
-std::optional<hwc2_display_t>
-HWComposer::getHwcDisplayId(int32_t displayId) const {
- if (!isValidDisplay(displayId)) {
+std::optional<DisplayId> HWComposer::toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const {
+ if (const auto it = mPhysicalDisplayIdMap.find(hwcDisplayId);
+ it != mPhysicalDisplayIdMap.end()) {
+ return it->second;
+ }
+ return {};
+}
+
+std::optional<hwc2_display_t> HWComposer::fromPhysicalDisplayId(DisplayId displayId) const {
+ if (const auto it = mDisplayData.find(displayId);
+ it != mDisplayData.end() && !it->second.isVirtual) {
+ return it->second.hwcDisplay->getId();
+ }
+ return {};
+}
+
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) {
+ if (isUsingVrComposer() && mInternalHwcDisplayId) {
+ ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId);
return {};
}
- return mDisplayData[displayId].hwcDisplay->getId();
-}
-void HWComposer::setDisplayFrequencyScaleParameters(
- HWC2::Device::FrequencyScaler frequencyScaler)
-{
- mHwcDevice->setDisplayFrequencyScaleParameters(frequencyScaler);
-}
+ uint8_t port;
+ DisplayIdentificationData data;
+ const bool hasMultiDisplaySupport = getDisplayIdentificationData(hwcDisplayId, &port, &data);
-HWC2::Device::FrequencyScaler HWComposer::getDisplayFrequencyScaleParameters()
-{
- return mHwcDevice->getDisplayFrequencyScaleParameters();
+ if (mPhysicalDisplayIdMap.empty()) {
+ mHasMultiDisplaySupport = hasMultiDisplaySupport;
+ ALOGI("Switching to %s multi-display mode",
+ hasMultiDisplaySupport ? "generalized" : "legacy");
+ } else if (mHasMultiDisplaySupport && !hasMultiDisplaySupport) {
+ ALOGE("Ignoring connection of display %" PRIu64 " without identification data",
+ hwcDisplayId);
+ return {};
+ }
+
+ std::optional<DisplayIdentificationInfo> info;
+
+ if (mHasMultiDisplaySupport) {
+ info = parseDisplayIdentificationData(port, data);
+ ALOGE_IF(!info, "Failed to parse identification data for display %" PRIu64, hwcDisplayId);
+ } else if (mInternalHwcDisplayId && mExternalHwcDisplayId) {
+ ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId);
+ return {};
+ } else {
+ ALOGW_IF(hasMultiDisplaySupport, "Ignoring identification data for display %" PRIu64,
+ hwcDisplayId);
+ port = mInternalHwcDisplayId ? HWC_DISPLAY_EXTERNAL : HWC_DISPLAY_PRIMARY;
+ }
+
+ if (!mInternalHwcDisplayId) {
+ mInternalHwcDisplayId = hwcDisplayId;
+ } else if (!mExternalHwcDisplayId) {
+ mExternalHwcDisplayId = hwcDisplayId;
+ }
+
+ if (info) return info;
+
+ return DisplayIdentificationInfo{getFallbackDisplayId(port),
+ hwcDisplayId == mInternalHwcDisplayId ? "Internal display"
+ : "External display"};
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index cca1f3b..5074c2c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -34,7 +34,8 @@
#include <memory>
#include <optional>
-#include <set>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include "DisplayIdentification.h"
@@ -82,101 +83,94 @@
bool hasCapability(HWC2::Capability capability) const;
- // Attempts to allocate a virtual display. If the virtual display is created
- // on the HWC device, outId will contain its HWC ID.
- status_t allocateVirtualDisplay(uint32_t width, uint32_t height,
- ui::PixelFormat* format, int32_t* outId);
+ // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
+ std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
+ ui::PixelFormat* format);
// Attempts to create a new layer on this display
- HWC2::Layer* createLayer(int32_t displayId);
+ HWC2::Layer* createLayer(DisplayId displayId);
// Destroy a previously created layer
- void destroyLayer(int32_t displayId, HWC2::Layer* layer);
+ void destroyLayer(DisplayId displayId, HWC2::Layer* layer);
// Asks the HAL what it can do
- status_t prepare(DisplayDevice& display,
- std::vector<CompositionInfo>& compositionData);
+ status_t prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData);
- status_t setClientTarget(int32_t displayId, uint32_t slot,
- const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
+ status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
// Present layers to the display and read releaseFences.
- status_t presentAndGetReleaseFences(int32_t displayId);
+ status_t presentAndGetReleaseFences(DisplayId displayId);
// set power mode
- status_t setPowerMode(int32_t displayId, int mode);
+ status_t setPowerMode(DisplayId displayId, int mode);
// set active config
- status_t setActiveConfig(int32_t displayId, size_t configId);
+ status_t setActiveConfig(DisplayId displayId, size_t configId);
// Sets a color transform to be applied to the result of composition
- status_t setColorTransform(int32_t displayId, const mat4& transform);
+ status_t setColorTransform(DisplayId displayId, const mat4& transform);
// reset state when an external, non-virtual display is disconnected
- void disconnectDisplay(int32_t displayId);
+ void disconnectDisplay(DisplayId displayId);
// does this display have layers handled by HWC
- bool hasDeviceComposition(int32_t displayId) const;
+ bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const;
// does this display have pending request to flip client target
- bool hasFlipClientTargetRequest(int32_t displayId) const;
+ bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const;
// does this display have layers handled by GLES
- bool hasClientComposition(int32_t displayId) const;
+ bool hasClientComposition(const std::optional<DisplayId>& displayId) const;
// get the present fence received from the last call to present.
- sp<Fence> getPresentFence(int32_t displayId) const;
+ sp<Fence> getPresentFence(DisplayId displayId) const;
// Get last release fence for the given layer
- sp<Fence> getLayerReleaseFence(int32_t displayId,
- HWC2::Layer* layer) const;
+ sp<Fence> getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const;
// Set the output buffer and acquire fence for a virtual display.
// Returns INVALID_OPERATION if displayId is not a virtual display.
- status_t setOutputBuffer(int32_t displayId, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& buf);
+ status_t setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buffer);
// After SurfaceFlinger has retrieved the release fences for all the frames,
// it can call this to clear the shared pointers in the release fence map
- void clearReleaseFences(int32_t displayId);
+ void clearReleaseFences(DisplayId displayId);
// Fetches the HDR capabilities of the given display
- status_t getHdrCapabilities(int32_t displayId, HdrCapabilities* outCapabilities);
+ status_t getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities);
- int32_t getSupportedPerFrameMetadata(int32_t displayId) const;
+ int32_t getSupportedPerFrameMetadata(DisplayId displayId) const;
// Returns the available RenderIntent of the given display.
- std::vector<ui::RenderIntent> getRenderIntents(int32_t displayId, ui::ColorMode colorMode) const;
+ std::vector<ui::RenderIntent> getRenderIntents(DisplayId displayId,
+ ui::ColorMode colorMode) const;
- mat4 getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace);
+ mat4 getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace);
// Events handling ---------------------------------------------------------
- // Returns true if successful, false otherwise. The
- // DisplayDevice::DisplayType of the display is returned as an output param.
- bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplay);
- std::optional<DisplayId> onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
- HWC2::Connection connection);
+ // Returns stable display ID (and display name on connection of new or previously disconnected
+ // display), or std::nullopt if hotplug event was ignored.
+ std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId,
+ HWC2::Connection connection);
- void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
+ bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp);
+ void setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled);
- // Query display parameters. Pass in a display index (e.g.
- // HWC_DISPLAY_PRIMARY).
- nsecs_t getRefreshTimestamp(int32_t displayId) const;
- bool isConnected(int32_t displayId) const;
+ nsecs_t getRefreshTimestamp(DisplayId displayId) const;
+ bool isConnected(DisplayId displayId) const;
// Non-const because it can update configMap inside of mDisplayData
- std::vector<std::shared_ptr<const HWC2::Display::Config>>
- getConfigs(int32_t displayId) const;
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(DisplayId displayId) const;
- std::shared_ptr<const HWC2::Display::Config>
- getActiveConfig(int32_t displayId) const;
- int getActiveConfigIndex(int32_t displayId) const;
+ std::shared_ptr<const HWC2::Display::Config> getActiveConfig(DisplayId displayId) const;
+ int getActiveConfigIndex(DisplayId displayId) const;
- std::vector<ui::ColorMode> getColorModes(int32_t displayId) const;
+ std::vector<ui::ColorMode> getColorModes(DisplayId displayId) const;
- status_t setActiveColorMode(int32_t displayId, ui::ColorMode mode,
- ui::RenderIntent renderIntent);
+ status_t setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+ ui::RenderIntent renderIntent);
bool isUsingVrComposer() const;
@@ -185,20 +179,19 @@
android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
- std::optional<hwc2_display_t> getHwcDisplayId(int32_t displayId) const;
+ // TODO(b/74619554): Remove special cases for internal/external display.
+ std::optional<hwc2_display_t> getInternalHwcDisplayId() const { return mInternalHwcDisplayId; }
+ std::optional<hwc2_display_t> getExternalHwcDisplayId() const { return mExternalHwcDisplayId; }
- // ------------------------------------------------------------------------
- // These functions set and get the frequencyScaler. The frequencyScaler holds
- // a multiplier and divisor for virtually scaling the panel frequency in
- // software. This is used to simulate different panel frequencies when
- // panel hardware is not available.
- void setDisplayFrequencyScaleParameters(HWC2::Device::FrequencyScaler frequencyScaler);
- HWC2::Device::FrequencyScaler getDisplayFrequencyScaleParameters();
+ std::optional<DisplayId> toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const;
+ std::optional<hwc2_display_t> fromPhysicalDisplayId(DisplayId displayId) const;
+
private:
// For unit tests
friend TestableSurfaceFlinger;
- bool isValidDisplay(int32_t displayId) const;
+ std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
+
static void validateChange(HWC2::Composition from, HWC2::Composition to);
struct cb_context;
@@ -223,21 +216,30 @@
HWC2::Error presentError;
};
- std::unique_ptr<HWC2::Device> mHwcDevice;
- std::vector<DisplayData> mDisplayData{HWC_NUM_PHYSICAL_DISPLAY_TYPES};
- std::set<size_t> mFreeDisplaySlots;
- std::unordered_map<hwc2_display_t, int32_t> mHwcDisplaySlots;
+ std::unordered_map<DisplayId, DisplayData> mDisplayData;
+
+ // This must be destroyed before mDisplayData, because destructor may call back into HWComposer
+ // and look up DisplayData.
+ std::unique_ptr<HWC2::Device> mHwcDevice;
+
+ std::unordered_map<hwc2_display_t, DisplayId> mPhysicalDisplayIdMap;
+ std::optional<hwc2_display_t> mInternalHwcDisplayId;
+ std::optional<hwc2_display_t> mExternalHwcDisplayId;
+ bool mHasMultiDisplaySupport = false;
+
// protect mDisplayData from races between prepare and dump
mutable Mutex mDisplayLock;
cb_context* mCBContext = nullptr;
- size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]{0, 0};
+ std::unordered_map<DisplayId, size_t> mVSyncCounts;
+
+ std::unordered_set<uint32_t> mFreeVirtualDisplayIds;
+ uint32_t mNextVirtualDisplayId = 0;
uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
// protected by mLock
mutable Mutex mLock;
- mutable std::unordered_map<int32_t, nsecs_t> mLastHwVSync{
- {{HWC_DISPLAY_PRIMARY, 0}, {HWC_DISPLAY_EXTERNAL, 0}}};
+ mutable std::unordered_map<DisplayId, nsecs_t> mLastHwVSync;
// thread-safe
mutable Mutex mVsyncLock;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index c111a27..5f3fcd6 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -48,34 +48,34 @@
}
}
-VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
- const sp<IGraphicBufferProducer>& sink,
- const sp<IGraphicBufferProducer>& bqProducer,
- const sp<IGraphicBufferConsumer>& bqConsumer,
- const std::string& name)
-: ConsumerBase(bqConsumer),
- mHwc(hwc),
- mDisplayId(dispId),
- mDisplayName(name),
- mSource{},
- mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
- mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
- mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
- mProducerSlotSource(0),
- mProducerBuffers(),
- mQueueBufferOutput(),
- mSinkBufferWidth(0),
- mSinkBufferHeight(0),
- mCompositionType(COMPOSITION_UNKNOWN),
- mFbFence(Fence::NO_FENCE),
- mOutputFence(Fence::NO_FENCE),
- mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mDbgState(DBG_STATE_IDLE),
- mDbgLastCompositionType(COMPOSITION_UNKNOWN),
- mMustRecompose(false),
- mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv)
-{
+VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc,
+ const std::optional<DisplayId>& displayId,
+ const sp<IGraphicBufferProducer>& sink,
+ const sp<IGraphicBufferProducer>& bqProducer,
+ const sp<IGraphicBufferConsumer>& bqConsumer,
+ const std::string& name)
+ : ConsumerBase(bqConsumer),
+ mHwc(hwc),
+ mDisplayId(displayId),
+ mDisplayName(name),
+ mSource{},
+ mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
+ mProducerSlotSource(0),
+ mProducerBuffers(),
+ mQueueBufferOutput(),
+ mSinkBufferWidth(0),
+ mSinkBufferHeight(0),
+ mCompositionType(COMPOSITION_UNKNOWN),
+ mFbFence(Fence::NO_FENCE),
+ mOutputFence(Fence::NO_FENCE),
+ mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mDbgState(DBG_STATE_IDLE),
+ mDbgLastCompositionType(COMPOSITION_UNKNOWN),
+ mMustRecompose(false),
+ mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) {
mSource[SOURCE_SINK] = sink;
mSource[SOURCE_SCRATCH] = bqProducer;
@@ -107,8 +107,6 @@
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
sink->setAsyncMode(true);
- IGraphicBufferProducer::QueueBufferOutput output;
- mSource[SOURCE_SCRATCH]->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &output);
}
VirtualDisplaySurface::~VirtualDisplaySurface() {
@@ -116,8 +114,9 @@
}
status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
mMustRecompose = mustRecompose;
@@ -129,8 +128,9 @@
}
status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN,
"Unexpected prepareFrame() in %s state", dbgStateStr());
@@ -177,8 +177,9 @@
}
status_t VirtualDisplaySurface::advanceFrame() {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
if (mCompositionType == COMPOSITION_HWC) {
VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
@@ -211,7 +212,7 @@
// At this point we know the output buffer acquire fence,
// so update HWC state with it.
- mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer);
+ mHwc.setOutputBuffer(*mDisplayId, mOutputFence, outBuffer);
status_t result = NO_ERROR;
if (fbBuffer != nullptr) {
@@ -221,22 +222,23 @@
&hwcSlot, &hwcBuffer);
// TODO: Correctly propagate the dataspace from GL composition
- result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence,
- hwcBuffer, ui::Dataspace::UNKNOWN);
+ result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
+ ui::Dataspace::UNKNOWN);
}
return result;
}
void VirtualDisplaySurface::onFrameCommitted() {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return;
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
"Unexpected onFrameCommitted() in %s state", dbgStateStr());
mDbgState = DBG_STATE_IDLE;
- sp<Fence> retireFence = mHwc.getPresentFence(mDisplayId);
+ sp<Fence> retireFence = mHwc.getPresentFence(*mDisplayId);
if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
// release the scratch buffer back to the pool
Mutex::Autolock lock(mMutex);
@@ -291,8 +293,9 @@
status_t VirtualDisplaySurface::requestBuffer(int pslot,
sp<GraphicBuffer>* outBuf) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected requestBuffer pslot=%d in %s state",
@@ -313,7 +316,7 @@
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
- LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
+ LOG_FATAL_IF(!mDisplayId);
status_t result =
mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
@@ -359,7 +362,7 @@
PixelFormat format, uint64_t usage,
uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
- if (mDisplayId < 0) {
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge,
outTimestamps);
}
@@ -446,8 +449,9 @@
status_t VirtualDisplaySurface::queueBuffer(int pslot,
const QueueBufferInput& input, QueueBufferOutput* output) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected queueBuffer(pslot=%d) in %s state", pslot,
@@ -504,8 +508,9 @@
status_t VirtualDisplaySurface::cancelBuffer(int pslot,
const sp<Fence>& fence) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
@@ -616,6 +621,8 @@
}
status_t VirtualDisplaySurface::refreshOutputBuffer() {
+ LOG_FATAL_IF(!mDisplayId);
+
if (mOutputProducerSlot >= 0) {
mSource[SOURCE_SINK]->cancelBuffer(
mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
@@ -633,8 +640,8 @@
// until after GLES calls queueBuffer(). So here we just set the buffer
// (for use in HWC prepare) but not the fence; we'll call this again with
// the proper fence once we have it.
- result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE,
- mProducerBuffers[mOutputProducerSlot]);
+ result = mHwc.setOutputBuffer(*mDisplayId, Fence::NO_FENCE,
+ mProducerBuffers[mOutputProducerSlot]);
return result;
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 4bd4d0f..33678df 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+#include <optional>
#include <string>
+#include "DisplayIdentification.h"
#include "DisplaySurface.h"
#include "HWComposerBufferCache.h"
@@ -75,11 +77,10 @@
public BnGraphicBufferProducer,
private ConsumerBase {
public:
- VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
- const sp<IGraphicBufferProducer>& sink,
- const sp<IGraphicBufferProducer>& bqProducer,
- const sp<IGraphicBufferConsumer>& bqConsumer,
- const std::string& name);
+ VirtualDisplaySurface(HWComposer& hwc, const std::optional<DisplayId>& displayId,
+ const sp<IGraphicBufferProducer>& sink,
+ const sp<IGraphicBufferProducer>& bqProducer,
+ const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name);
//
// DisplaySurface interface
@@ -154,7 +155,7 @@
// Immutable after construction
//
HWComposer& mHwc;
- const int32_t mDisplayId;
+ const std::optional<DisplayId> mDisplayId;
const std::string mDisplayName;
sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
uint32_t mDefaultOutputFormat;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index dba5f8f..8882667 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -111,6 +111,8 @@
args.flinger->getCompositorTiming(&compositorTiming);
mFrameEventHistory.initializeCompositorTiming(compositorTiming);
mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
+
+ mFlinger->onLayerCreated();
}
Layer::~Layer() {
@@ -119,13 +121,11 @@
c->detachLayer(this);
}
- for (auto& point : mRemoteSyncPoints) {
- point->setTransactionApplied();
- }
- for (auto& point : mLocalSyncPoints) {
- point->setFrameAvailable();
- }
mFrameTracker.logAndResetStats(mName);
+
+ destroyAllHwcLayers();
+
+ mFlinger->onLayerDestroyed();
}
// ---------------------------------------------------------------------------
@@ -140,10 +140,9 @@
void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
void Layer::onRemovedFromCurrentState() {
+ mRemovedFromCurrentState = true;
+
// the layer is removed from SF mCurrentState to mLayersPendingRemoval
-
- mPendingRemoval = true;
-
if (mCurrentState.zOrderRelativeOf != nullptr) {
sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
if (strongRelative != nullptr) {
@@ -153,22 +152,29 @@
mCurrentState.zOrderRelativeOf = nullptr;
}
+ // Since we are no longer reachable from CurrentState SurfaceFlinger
+ // will no longer invoke doTransaction for us, and so we will
+ // never finish applying transactions. We signal the sync point
+ // now so that another layer will not become indefinitely
+ // blocked.
+ for (auto& point: mRemoteSyncPoints) {
+ point->setTransactionApplied();
+ }
+ mRemoteSyncPoints.clear();
+
+ {
+ Mutex::Autolock syncLock(mLocalSyncPointMutex);
+ for (auto& point : mLocalSyncPoints) {
+ point->setFrameAvailable();
+ }
+ mLocalSyncPoints.clear();
+ }
+
for (const auto& child : mCurrentChildren) {
child->onRemovedFromCurrentState();
}
}
-void Layer::onRemoved() {
- // the layer is removed from SF mLayersPendingRemoval
- abandon();
-
- destroyAllHwcLayers();
-
- for (const auto& child : mCurrentChildren) {
- child->onRemoved();
- }
-}
-
// ---------------------------------------------------------------------------
// set-up
// ---------------------------------------------------------------------------
@@ -190,9 +196,9 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::createHwcLayer(HWComposer* hwc, int32_t displayId) {
+bool Layer::createHwcLayer(HWComposer* hwc, DisplayId displayId) {
LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(displayId) != 0,
- "Already have a layer for display %d", displayId);
+ "Already have a layer for display %" PRIu64, displayId);
auto layer = std::shared_ptr<HWC2::Layer>(
hwc->createLayer(displayId),
[hwc, displayId](HWC2::Layer* layer) {
@@ -208,7 +214,7 @@
return true;
}
-bool Layer::destroyHwcLayer(int32_t displayId) {
+bool Layer::destroyHwcLayer(DisplayId displayId) {
if (getBE().mHwcLayers.count(displayId) == 0) {
return false;
}
@@ -228,6 +234,10 @@
}
LOG_ALWAYS_FATAL_IF(!getBE().mHwcLayers.empty(),
"All hardware composer layers should have been destroyed");
+
+ for (const sp<Layer>& child : mDrawingChildren) {
+ child->destroyAllHwcLayers();
+ }
}
Rect Layer::getContentCrop() const {
@@ -464,12 +474,13 @@
void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
const auto displayId = display->getId();
- if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setGeometry: no HWC layer found (%d)",
- mName.string(), displayId);
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ if (!hasHwcLayer(*displayId)) {
+ ALOGE("[%s] failed to setGeometry: no HWC layer found for display %" PRIu64, mName.string(),
+ *displayId);
return;
}
- auto& hwcInfo = getBE().mHwcLayers[displayId];
+ auto& hwcInfo = getBE().mHwcLayers[*displayId];
// enable this layer
hwcInfo.forceClientComposition = false;
@@ -621,7 +632,7 @@
if (orientation & ui::Transform::ROT_INVALID) {
// we can only handle simple transformation
hwcInfo.forceClientComposition = true;
- getBE().mHwcLayers[displayId].compositionType = HWC2::Composition::Client;
+ getBE().mHwcLayers[*displayId].compositionType = HWC2::Composition::Client;
} else {
auto transform = static_cast<HWC2::Transform>(orientation);
hwcInfo.transform = transform;
@@ -635,18 +646,18 @@
}
}
-void Layer::forceClientComposition(int32_t displayId) {
+void Layer::forceClientComposition(DisplayId displayId) {
if (getBE().mHwcLayers.count(displayId) == 0) {
- ALOGE("forceClientComposition: no HWC layer found (%d)", displayId);
+ ALOGE("forceClientComposition: no HWC layer found (display %" PRIu64 ")", displayId);
return;
}
getBE().mHwcLayers[displayId].forceClientComposition = true;
}
-bool Layer::getForceClientComposition(int32_t displayId) {
+bool Layer::getForceClientComposition(DisplayId displayId) {
if (getBE().mHwcLayers.count(displayId) == 0) {
- ALOGE("getForceClientComposition: no HWC layer found (%d)", displayId);
+ ALOGE("getForceClientComposition: no HWC layer found (display %" PRIu64 ")", displayId);
return false;
}
@@ -655,7 +666,7 @@
void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
const auto displayId = display->getId();
- if (getBE().mHwcLayers.count(displayId) == 0 ||
+ if (getBE().mHwcLayers.count(*displayId) == 0 ||
getCompositionType(displayId) != HWC2::Composition::Cursor) {
return;
}
@@ -678,8 +689,8 @@
auto position = displayTransform.transform(frame);
auto error =
- (getBE().mHwcLayers[displayId].layer)->setCursorPosition(
- position.left, position.top);
+ getBE().mHwcLayers[*displayId].layer->setCursorPosition(position.left, position.top);
+
ALOGE_IF(error != HWC2::Error::None,
"[%s] Failed to set cursor position "
"to (%d, %d): %s (%d)",
@@ -711,7 +722,7 @@
clearWithOpenGL(renderArea, 0, 0, 0, 0);
}
-void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc) {
+void Layer::setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc) {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setCompositionType called without a valid HWC layer");
return;
@@ -734,16 +745,20 @@
}
}
-HWC2::Composition Layer::getCompositionType(int32_t displayId) const {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+HWC2::Composition Layer::getCompositionType(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// If we're querying the composition type for a display that does not
// have a HWC counterpart, then it will always be Client
return HWC2::Composition::Client;
}
- return getBE().mHwcLayers[displayId].compositionType;
+ if (getBE().mHwcLayers.count(*displayId) == 0) {
+ ALOGE("getCompositionType called with an invalid HWC layer");
+ return HWC2::Composition::Invalid;
+ }
+ return getBE().mHwcLayers.at(*displayId).compositionType;
}
-void Layer::setClearClientTarget(int32_t displayId, bool clear) {
+void Layer::setClearClientTarget(DisplayId displayId, bool clear) {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setClearClientTarget called without a valid HWC layer");
return;
@@ -751,7 +766,7 @@
getBE().mHwcLayers[displayId].clearClientTarget = clear;
}
-bool Layer::getClearClientTarget(int32_t displayId) const {
+bool Layer::getClearClientTarget(DisplayId displayId) const {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("getClearClientTarget called without a valid HWC layer");
return false;
@@ -765,6 +780,9 @@
// relevant frame
return false;
}
+ if (isRemovedFromCurrentState()) {
+ return false;
+ }
Mutex::Autolock lock(mLocalSyncPointMutex);
mLocalSyncPoints.push_back(point);
@@ -838,7 +856,9 @@
// If this transaction is waiting on the receipt of a frame, generate a sync
// point and send it to the remote layer.
- if (mCurrentState.barrierLayer_legacy != nullptr) {
+ // We don't allow installing sync points after we are removed from the current state
+ // as we won't be able to signal our end.
+ if (mCurrentState.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) {
sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
if (barrierLayer == nullptr) {
ALOGE("[%s] Unable to promote barrier Layer.", mName.string());
@@ -1047,6 +1067,7 @@
// Commit the transaction
commitTransaction(c);
+ mCurrentState.callbackHandles = {};
return flags;
}
@@ -1414,7 +1435,7 @@
result.append("-----------------------------\n");
}
-void Layer::miniDump(String8& result, int32_t displayId) const {
+void Layer::miniDump(String8& result, DisplayId displayId) const {
if (getBE().mHwcLayers.count(displayId) == 0) {
return;
}
@@ -1489,9 +1510,8 @@
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) {
if (newTimestamps) {
- const int32_t layerID = getSequence();
- mTimeStats.setLayerName(layerID, getName().c_str());
- mTimeStats.setPostTime(layerID, newTimestamps->frameNumber, newTimestamps->postedTime);
+ mTimeStats.setPostTime(getSequence(), newTimestamps->frameNumber, getName().c_str(),
+ newTimestamps->postedTime);
}
Mutex::Autolock lock(mFrameEventHistoryMutex);
@@ -1979,7 +1999,7 @@
}
}
-void Layer::writeToProto(LayerProto* layerInfo, int32_t displayId) {
+void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
if (!hasHwcLayer(displayId)) {
return;
}
@@ -2008,6 +2028,10 @@
}
}
+bool Layer::isRemovedFromCurrentState() const {
+ return mRemovedFromCurrentState;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 21729ad..9b9b91b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -38,6 +38,7 @@
#include <cstdint>
#include <list>
+#include <optional>
#include <vector>
#include "Client.h"
@@ -47,6 +48,7 @@
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
+#include "TransactionCompletedThread.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWComposerBufferCache.h"
@@ -183,6 +185,10 @@
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
bool hasColorTransform;
+
+ // The deque of callback handles for this frame. The back of the deque contains the most
+ // recent callback handle.
+ std::deque<sp<CallbackHandle>> callbackHandles;
};
explicit Layer(const LayerCreationArgs& args);
@@ -265,13 +271,17 @@
virtual bool setTransform(uint32_t /*transform*/) { return false; };
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
virtual bool setCrop(const Rect& /*crop*/) { return false; };
- virtual bool setBuffer(sp<GraphicBuffer> /*buffer*/) { return false; };
+ virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) { return false; };
virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
virtual bool setApi(int32_t /*api*/) { return false; };
virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
+ virtual bool setTransactionCompletedListeners(
+ const std::vector<sp<CallbackHandle>>& /*handles*/) {
+ return false;
+ };
ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
@@ -346,12 +356,12 @@
virtual bool isCreatedFromMainThread() const { return false; }
- bool isPendingRemoval() const { return mPendingRemoval; }
+ bool isRemovedFromCurrentState() const;
void writeToProto(LayerProto* layerInfo,
LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
- void writeToProto(LayerProto* layerInfo, int32_t displayId);
+ void writeToProto(LayerProto* layerInfo, DisplayId displayId);
virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -377,16 +387,17 @@
virtual bool isHdrY410() const { return false; }
void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
- void forceClientComposition(int32_t displayId);
- bool getForceClientComposition(int32_t displayId);
- virtual void setPerFrameData(const sp<const DisplayDevice>& display) = 0;
+ void forceClientComposition(DisplayId displayId);
+ bool getForceClientComposition(DisplayId displayId);
+ virtual void setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t supportedPerFrameMetadata) = 0;
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc = true);
- HWC2::Composition getCompositionType(int32_t displayId) const;
- void setClearClientTarget(int32_t displayId, bool clear);
- bool getClearClientTarget(int32_t displayId) const;
+ void setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc = true);
+ HWC2::Composition getCompositionType(const std::optional<DisplayId>& displayId) const;
+ void setClearClientTarget(DisplayId displayId, bool clear);
+ bool getClearClientTarget(DisplayId displayId) const;
void updateCursorPosition(const sp<const DisplayDevice>& display);
/*
@@ -394,8 +405,6 @@
*/
virtual void onLayerDisplayed(const sp<Fence>& releaseFence);
- virtual void abandon() {}
-
virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
virtual void setTransformHint(uint32_t /*orientation*/) const { }
@@ -403,13 +412,14 @@
* called before composition.
* returns true if the layer has pending updates.
*/
- virtual bool onPreComposition(nsecs_t /*refreshStartTime*/) { return true; }
+ virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- virtual bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+ virtual bool onPostComposition(const std::optional<DisplayId>& /*displayId*/,
+ const std::shared_ptr<FenceTime>& /*glDoneFence*/,
const std::shared_ptr<FenceTime>& /*presentFence*/,
const CompositorTiming& /*compositorTiming*/) {
return false;
@@ -475,12 +485,6 @@
*/
void onRemovedFromCurrentState();
- /*
- * called with the state lock from the main thread when the layer is
- * removed from the pending removal list
- */
- void onRemoved();
-
// Updates the transform hint in our SurfaceFlingerConsumer to match
// the current orientation of the display device.
void updateTransformHint(const sp<const DisplayDevice>& display) const;
@@ -500,24 +504,24 @@
// -----------------------------------------------------------------------
- bool createHwcLayer(HWComposer* hwc, int32_t displayId);
- bool destroyHwcLayer(int32_t displayId);
+ bool createHwcLayer(HWComposer* hwc, DisplayId displayId);
+ bool destroyHwcLayer(DisplayId displayId);
void destroyAllHwcLayers();
- bool hasHwcLayer(int32_t displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
+ bool hasHwcLayer(DisplayId displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
- HWC2::Layer* getHwcLayer(int32_t displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+ HWC2::Layer* getHwcLayer(DisplayId displayId) {
+ if (!hasHwcLayer(displayId)) {
return nullptr;
}
return getBE().mHwcLayers[displayId].layer.get();
}
- bool setHwcLayer(int32_t hwcId) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+ bool setHwcLayer(DisplayId displayId) {
+ if (!hasHwcLayer(displayId)) {
return false;
}
- getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[hwcId].layer;
+ getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[displayId].layer;
return true;
}
@@ -532,7 +536,7 @@
/* always call base class first */
static void miniDumpHeader(String8& result);
- void miniDump(String8& result, int32_t displayId) const;
+ void miniDump(String8& result, DisplayId displayId) const;
void dumpFrameStats(String8& result) const;
void dumpFrameEvents(String8& result);
void clearFrameStats();
@@ -595,12 +599,12 @@
*/
class LayerCleaner {
sp<SurfaceFlinger> mFlinger;
- wp<Layer> mLayer;
+ sp<Layer> mLayer;
protected:
~LayerCleaner() {
// destroy client resources
- mFlinger->onLayerDestroyed(mLayer);
+ mFlinger->onHandleDestroyed(mLayer);
}
public:
@@ -702,6 +706,8 @@
virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
bool getPremultipledAlpha() const;
+ bool mPendingHWCDestroy{false};
+
protected:
// -----------------------------------------------------------------------
bool usingRelativeZ(LayerVector::StateSet stateSet);
@@ -745,7 +751,7 @@
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering{false};
- bool mPendingRemoval{false};
+ std::atomic<bool> mRemovedFromCurrentState{false};
// page-flip thread (currently main thread)
bool mProtectedByApp{false}; // application requires protected path to external sink
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 463c46c..3f5134e 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -24,6 +24,7 @@
#include <renderengine/Texture.h>
#include <ui/Region.h>
+#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWComposerBufferCache.h"
#include "SurfaceFlinger.h"
@@ -41,7 +42,7 @@
std::shared_ptr<LayerBE> layer;
struct {
std::shared_ptr<HWC2::Layer> hwcLayer;
- int32_t displayId = -1;
+ DisplayId displayId;
sp<Fence> fence;
HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
Rect displayFrame;
@@ -123,12 +124,11 @@
HWC2::Transform transform;
};
-
// A layer can be attached to multiple displays when operating in mirror mode
// (a.k.a: when several displays are attached with equal layerStack). In this
// case we need to keep track. In non-mirror mode, a layer will have only one
- // HWCInfo. This map key is a display layerStack.
- std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+ // HWCInfo.
+ std::unordered_map<DisplayId, HWCInfo> mHwcLayers;
CompositionInfo compositionInfo;
};
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 3c11e73..9bad6de 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -1,5 +1,6 @@
#pragma once
+#include <ui/GraphicTypes.h>
#include <ui/Transform.h>
#include <functional>
@@ -19,9 +20,11 @@
static float getCaptureFillValue(CaptureFill captureFill);
RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill,
+ ui::Dataspace reqDataSpace,
ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
: mReqWidth(reqWidth),
mReqHeight(reqHeight),
+ mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill),
mRotationFlags(rotation) {}
@@ -66,6 +69,9 @@
int getReqWidth() const { return mReqWidth; };
int getReqHeight() const { return mReqHeight; };
+ // Returns the composition data space of the render area.
+ ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
+
// Returns the fill color of the physical render area. Regions not
// covered by any rendered layer should be filled with this color.
CaptureFill getCaptureFill() const { return mCaptureFill; };
@@ -73,6 +79,7 @@
private:
const uint32_t mReqWidth;
const uint32_t mReqHeight;
+ const ui::Dataspace mReqDataSpace;
const CaptureFill mCaptureFill;
const ui::Transform::orientation_flags mRotationFlags;
};
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index cba9181..172c418 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -25,6 +25,7 @@
#include <algorithm>
#include <log/log.h>
+#include <cutils/properties.h>
#include <utils/String8.h>
#include <utils/Thread.h>
#include <utils/Trace.h>
@@ -520,27 +521,12 @@
void DispSync::setPeriod(nsecs_t period) {
Mutex::Autolock lock(mMutex);
- mPeriodBase = mPeriod = period;
+ mPeriod = period;
mPhase = 0;
mReferenceTime = 0;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
-void DispSync::scalePeriod(HWC2::Device::FrequencyScaler frequencyScaler) {
- Mutex::Autolock lock(mMutex);
-
- // if only 1 of the properties is updated, we will get to this
- // point "attempting" to set the scale to 1 when it is already
- // 1. Check that special case so that we don't do a useless
- // update of the model.
- if ((frequencyScaler.multiplier == 1) &&
- (frequencyScaler.divisor == 1) &&
- (mPeriod == mPeriodBase)) return;
-
- mPeriod = mPeriodBase * frequencyScaler.multiplier / frequencyScaler.divisor;
- mThread->updateModel(mPeriod, mPhase, mReferenceTime);
-}
-
nsecs_t DispSync::getPeriod() {
// lock mutex as mPeriod changes multiple times in updateModelLocked
Mutex::Autolock lock(mMutex);
@@ -565,7 +551,7 @@
// Exclude the min and max from the average
durationSum -= minDuration + maxDuration;
- mPeriodBase = mPeriod = durationSum / (mNumResyncSamples - 3);
+ mPeriod = durationSum / (mNumResyncSamples - 3);
ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 5b511f4..5d19093 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -24,7 +24,6 @@
#include <utils/Timers.h>
#include <ui/FenceTime.h>
-#include <DisplayHardware/HWC2.h>
#include <memory>
@@ -49,7 +48,6 @@
virtual bool addResyncSample(nsecs_t timestamp) = 0;
virtual void endResync() = 0;
virtual void setPeriod(nsecs_t period) = 0;
- virtual void scalePeriod(HWC2::Device::FrequencyScaler) = 0;
virtual nsecs_t getPeriod() = 0;
virtual void setRefreshSkipCount(int count) = 0;
virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) = 0;
@@ -120,12 +118,6 @@
// turned on. It should NOT be used after that.
void setPeriod(nsecs_t period) override;
- // The scalePeriod method applies the multiplier and divisor to
- // scale the vsync event model's period. The function is added
- // for an experimental test mode and should not be used outside
- // of that purpose.
- void scalePeriod(HWC2::Device::FrequencyScaler frequencyScaler);
-
// The getPeriod method returns the current vsync period.
nsecs_t getPeriod() override;
@@ -188,7 +180,6 @@
// mPeriod is the computed period of the modeled vsync events in
// nanoseconds.
nsecs_t mPeriod;
- nsecs_t mPeriodBase;
// mPhase is the phase offset of the modeled vsync events. It is the
// number of nanoseconds from time 0 to the first vsync event.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 18a8bb1..4286cc9 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "Scheduler.h"
#include <cinttypes>
#include <cstdint>
#include <memory>
+#include <numeric>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
@@ -27,6 +30,7 @@
#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
+#include <utils/Trace.h>
#include "DispSync.h"
#include "DispSyncSource.h"
@@ -196,4 +200,58 @@
mPrimaryDispSync->setIgnorePresentFences(ignore);
}
+void Scheduler::makeHWSyncAvailable(bool makeAvailable) {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ mHWVsyncAvailable = makeAvailable;
+}
+
+void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp) {
+ ATRACE_INT("AutoTimestamp", isAutoTimestamp);
+ // Video does not have timestamp automatically set, so we discard timestamps that are
+ // coming in from other sources for now.
+ if (isAutoTimestamp) {
+ return;
+ }
+ int64_t differenceMs = (newFrameTimestamp - mPreviousFrameTimestamp) / 1000000;
+ mPreviousFrameTimestamp = newFrameTimestamp;
+
+ if (differenceMs < 10 || differenceMs > 100) {
+ // Dismiss noise.
+ return;
+ }
+ ATRACE_INT("TimestampDiff", differenceMs);
+
+ mTimeDifferences[mCounter % ARRAY_SIZE] = differenceMs;
+ mCounter++;
+ nsecs_t average = calculateAverage();
+ ATRACE_INT("TimestampAverage", average);
+
+ // TODO(b/113612090): This are current numbers from trial and error while running videos
+ // from YouTube at 24, 30, and 60 fps.
+ if (average > 14 && average < 18) {
+ ATRACE_INT("FPS", 60);
+ } else if (average > 31 && average < 34) {
+ ATRACE_INT("FPS", 30);
+ updateFrameSkipping(1);
+ return;
+ } else if (average > 39 && average < 42) {
+ ATRACE_INT("FPS", 24);
+ }
+ updateFrameSkipping(0);
+}
+
+nsecs_t Scheduler::calculateAverage() const {
+ nsecs_t sum = std::accumulate(mTimeDifferences.begin(), mTimeDifferences.end(), 0);
+ return (sum / ARRAY_SIZE);
+}
+
+void Scheduler::updateFrameSkipping(const int64_t skipCount) {
+ ATRACE_INT("FrameSkipCount", skipCount);
+ if (mSkipCount != skipCount) {
+ // Only update DispSync if it hasn't been updated yet.
+ mPrimaryDispSync->setRefreshSkipCount(skipCount);
+ mSkipCount = skipCount;
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fdafe58..dd1f24b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -102,6 +102,8 @@
void addResyncSample(const nsecs_t timestamp);
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
+ void makeHWSyncAvailable(bool makeAvailable);
+ void addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp);
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
@@ -110,6 +112,9 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ nsecs_t calculateAverage() const;
+ void updateFrameSkipping(const int64_t skipCount);
+
// TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
// should make request to Scheduler to compute next refresh.
friend class BufferQueueLayer;
@@ -133,6 +138,18 @@
std::unique_ptr<DispSync> mPrimaryDispSync;
std::unique_ptr<EventControlThread> mEventControlThread;
+
+ // TODO(b/113612090): The following set of variables needs to be revised. For now, this is
+ // a proof of concept. We turn on frame skipping if the difference between the timestamps
+ // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz.
+ nsecs_t mPreviousFrameTimestamp = 0;
+ // Keeping track of whether we are skipping the refresh count. If we want to
+ // simulate 30Hz rendering, we skip every other frame, and this variable is set
+ // to 1.
+ int64_t mSkipCount = 0;
+ static constexpr size_t ARRAY_SIZE = 30;
+ std::array<int64_t, ARRAY_SIZE> mTimeDifferences;
+ size_t mCounter = 0;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4a96e89..ce3fb2d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -45,6 +45,7 @@
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
+#include <gui/IProducerListener.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <renderengine/RenderEngine.h>
@@ -75,7 +76,9 @@
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
+#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
+#include "SurfaceInterceptor.h"
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/DisplayIdentification.h"
@@ -88,6 +91,7 @@
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/InjectVSyncSource.h"
+#include "Scheduler/MessageQueue.h"
#include "Scheduler/Scheduler.h"
#include <cutils/compiler.h>
@@ -102,8 +106,6 @@
#include <layerproto/LayerProtoParser.h>
-#define DISPLAY_COUNT 1
-
namespace android {
using namespace android::hardware::configstore;
@@ -170,6 +172,11 @@
bool mLocked;
};
+// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
+bool validateCompositionDataspace(Dataspace dataspace) {
+ return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
+}
+
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -188,13 +195,14 @@
bool SurfaceFlinger::hasSyncFramework;
bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
-// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
bool SurfaceFlinger::hasWideColorDisplay;
int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
bool SurfaceFlinger::useColorManagement;
bool SurfaceFlinger::useContextPriority;
-Dataspace SurfaceFlinger::compositionDataSpace = Dataspace::V0_SRGB;
-ui::PixelFormat SurfaceFlinger::compositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
std::string getHwcServiceName() {
char value[PROPERTY_VALUE_MAX] = {};
@@ -233,14 +241,15 @@
mComposerSequenceId(0) {
}
-SurfaceFlinger::SurfaceFlinger(SurfaceFlinger::SkipInitializationTag)
+SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory,
+ SurfaceFlinger::SkipInitializationTag)
: BnSurfaceComposer(),
+ mFactory(factory),
mTransactionPending(false),
mAnimTransactionPending(false),
mLayersRemoved(false),
mLayersAdded(false),
mBootTime(systemTime()),
- mDisplayTokens(),
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
@@ -258,11 +267,10 @@
mHasPoweredOff(false),
mNumLayers(0),
mVrFlingerRequestsDisplay(false),
- mMainThreadId(std::this_thread::get_id()),
- mCreateBufferQueue(&BufferQueue::createBufferQueue),
- mCreateNativeWindowSurface(&surfaceflinger::impl::createNativeWindowSurface) {}
+ mMainThreadId(std::this_thread::get_id()) {}
-SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
+SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory)
+ : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
@@ -299,11 +307,16 @@
auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
if (surfaceFlingerConfigsServiceV1_2) {
surfaceFlingerConfigsServiceV1_2->getCompositionPreference(
- [&](Dataspace tmpDataSpace, ui::PixelFormat tmpPixelFormat) {
- compositionDataSpace = tmpDataSpace;
- compositionPixelFormat = tmpPixelFormat;
- });
+ [&](auto tmpDefaultDataspace, auto tmpDefaultPixelFormat,
+ auto tmpWideColorGamutDataspace, auto tmpWideColorGamutPixelFormat) {
+ defaultCompositionDataspace = tmpDefaultDataspace;
+ defaultCompositionPixelFormat = tmpDefaultPixelFormat;
+ wideColorGamutCompositionDataspace = tmpWideColorGamutDataspace;
+ wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
+ });
}
+ mDefaultCompositionDataspace = defaultCompositionDataspace;
+ mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
useContextPriority = getBool<ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::useContextPriority>(true);
@@ -329,13 +342,9 @@
}
ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
- // Note: We create a local temporary with the real DispSync implementation
- // type temporarily so we can initialize it with the configured values,
- // before storing it for more generic use using the interface type.
- auto primaryDispSync = std::make_unique<impl::DispSync>("PrimaryDispSync");
- primaryDispSync->init(SurfaceFlinger::hasSyncFramework,
- SurfaceFlinger::dispSyncPresentTimeOffset);
- mPrimaryDispSync = std::move(primaryDispSync);
+ mPrimaryDispSync =
+ getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework,
+ SurfaceFlinger::dispSyncPresentTimeOffset);
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -477,40 +486,57 @@
sp<BBinder> token = new DisplayToken(this);
Mutex::Autolock _l(mStateLock);
- DisplayDeviceState info;
- info.type = DisplayDevice::DISPLAY_VIRTUAL;
- info.displayName = displayName;
- info.isSecure = secure;
- mCurrentState.displays.add(token, info);
- mInterceptor->saveDisplayCreation(info);
+ // Display ID is assigned when virtual display is allocated by HWC.
+ DisplayDeviceState state;
+ state.isSecure = secure;
+ state.displayName = displayName;
+ mCurrentState.displays.add(token, state);
+ mInterceptor->saveDisplayCreation(state);
return token;
}
void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) {
Mutex::Autolock _l(mStateLock);
- ssize_t idx = mCurrentState.displays.indexOfKey(displayToken);
- if (idx < 0) {
+ ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
+ if (index < 0) {
ALOGE("destroyDisplay: Invalid display token %p", displayToken.get());
return;
}
- const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- if (!info.isVirtual()) {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ if (!state.isVirtual()) {
ALOGE("destroyDisplay called for non-virtual display");
return;
}
- mInterceptor->saveDisplayDeletion(info.sequenceId);
- mCurrentState.displays.removeItemsAt(idx);
+ mInterceptor->saveDisplayDeletion(state.sequenceId);
+ mCurrentState.displays.removeItemsAt(index);
setTransactionFlags(eDisplayTransactionNeeded);
}
sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
- if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
- ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
+ std::optional<DisplayId> displayId;
+
+ if (id == HWC_DISPLAY_PRIMARY) {
+ displayId = getInternalDisplayId();
+ } else if (id == HWC_DISPLAY_EXTERNAL) {
+ displayId = getExternalDisplayId();
+ }
+
+ if (!displayId) {
+ ALOGE("%s: Invalid display %d", __FUNCTION__, id);
return nullptr;
}
- return mDisplayTokens[id];
+
+ return getPhysicalDisplayToken(*displayId);
+}
+
+status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
+ if (!outGetColorManagement) {
+ return BAD_VALUE;
+ }
+ *outGetColorManagement = useColorManagement;
+ return NO_ERROR;
}
void SurfaceFlinger::bootFinished()
@@ -585,8 +611,10 @@
// start the EventThread
if (mUseScheduler) {
- mScheduler = std::make_unique<Scheduler>(
- [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
+ mScheduler = getFactory().createScheduler([this](bool enabled) {
+ setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
+ });
+
mAppConnectionHandle =
mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
[this] { resyncWithRateLimit(); },
@@ -634,26 +662,21 @@
// TODO(b/77156734): We need to stop casting and use HAL types when possible.
getBE().mRenderEngine =
- renderengine::RenderEngine::create(static_cast<int32_t>(compositionPixelFormat),
- renderEngineFeature);
+ renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
+ renderEngineFeature);
LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
- getBE().mHwc.reset(
- new HWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));
+ getBE().mHwc = getFactory().createHWComposer(getBE().mHwcServiceName);
getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
- LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getId()),
+ LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
"Internal display is disconnected.");
- // make the default display GLContext current so that we can create textures
- // when creating Layers (which may happens before we render something)
- display->makeCurrent();
-
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
// This callback is called from the vr flinger dispatch thread. We
@@ -670,7 +693,7 @@
};
mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
getHwComposer()
- .getHwcDisplayId(display->getId())
+ .fromPhysicalDisplayId(*display->getId())
.value_or(0),
vrFlingerRequestDisplayCallback);
if (!mVrFlinger) {
@@ -678,8 +701,8 @@
}
}
- mEventControlThread = std::make_unique<impl::EventControlThread>(
- [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
+ mEventControlThread = getFactory().createEventControlThread(
+ [this](bool enabled) { setVsyncEnabled(EventThread::DisplayType::Primary, enabled); });
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -690,12 +713,10 @@
getBE().mRenderEngine->primeCache();
// Inform native graphics APIs whether the present timestamp is supported:
- if (getHwComposer().hasCapability(
- HWC2::Capability::PresentFenceIsNotReliable)) {
- mStartPropertySetThread = new StartPropertySetThread(false);
- } else {
- mStartPropertySetThread = new StartPropertySetThread(true);
- }
+
+ const bool presentFenceReliable =
+ !getHwComposer().hasCapability(HWC2::Capability::PresentFenceIsNotReliable);
+ mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGE("Run StartPropertySetThread failed!");
@@ -707,8 +728,8 @@
// and apply this saturation matrix on Display P3 content. Unless the risk of applying
// such saturation matrix on Display P3 is understood fully, the API should always return
// identify matrix.
- mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(display->getId(),
- Dataspace::SRGB_LINEAR);
+ mEnhancedSaturationMatrix =
+ getHwComposer().getDataspaceSaturationMatrix(*display->getId(), Dataspace::SRGB_LINEAR);
// we will apply this on Display P3.
if (mEnhancedSaturationMatrix != mat4()) {
@@ -795,16 +816,9 @@
return BAD_VALUE;
}
- int32_t type = NAME_NOT_FOUND;
- for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
- if (displayToken == mDisplayTokens[i]) {
- type = i;
- break;
- }
- }
-
- if (type < 0) {
- return type;
+ const auto displayId = getPhysicalDisplayId(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
}
// TODO: Not sure if display density should handled by SF any longer
@@ -828,7 +842,7 @@
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
- for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
+ for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
DisplayInfo info = DisplayInfo();
float xdpi = hwConfig->getDpiX();
@@ -840,7 +854,7 @@
info.viewportW = info.w;
info.viewportH = info.h;
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (displayId == getInternalDisplayId()) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
if (density == 0) {
@@ -896,7 +910,7 @@
// All non-virtual displays are currently considered secure.
info.secure = true;
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
+ if (displayId == getInternalDisplayId() &&
primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
@@ -912,7 +926,6 @@
return BAD_VALUE;
}
- // FIXME for now we always return stats for the primary display.
if (mUseScheduler) {
mScheduler->getDisplayStatInfo(stats);
} else {
@@ -933,18 +946,21 @@
}
void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
int currentMode = display->getActiveConfig();
if (mode == currentMode) {
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set config for virtual display");
- return;
- }
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(mode);
- getHwComposer().setActiveConfig(display->getDisplayType(), mode);
+ getHwComposer().setActiveConfig(*displayId, mode);
}
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -969,29 +985,23 @@
return NO_ERROR;
}
+
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
Vector<ColorMode>* outColorModes) {
if (!displayToken || !outColorModes) {
return BAD_VALUE;
}
- int32_t type = NAME_NOT_FOUND;
- for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
- if (displayToken == mDisplayTokens[i]) {
- type = i;
- break;
- }
- }
-
- if (type < 0) {
- return type;
+ const auto displayId = getPhysicalDisplayId(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
}
std::vector<ColorMode> modes;
{
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
- modes = getHwComposer().getColorModes(type);
+ modes = getHwComposer().getColorModes(*displayId);
}
outColorModes->clear();
std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
@@ -1008,6 +1018,11 @@
void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& display, ColorMode mode,
Dataspace dataSpace, RenderIntent renderIntent) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
ColorMode currentMode = display->getActiveColorMode();
Dataspace currentDataSpace = display->getCompositionDataSpace();
RenderIntent currentRenderIntent = display->getActiveRenderIntent();
@@ -1017,19 +1032,17 @@
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set config for virtual display");
- return;
- }
-
display->setActiveColorMode(mode);
display->setCompositionDataSpace(dataSpace);
display->setActiveRenderIntent(renderIntent);
- getHwComposer().setActiveColorMode(display->getDisplayType(), mode, renderIntent);
- ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ getHwComposer().setActiveColorMode(*displayId, mode, renderIntent);
+
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), display=%" PRIu64,
decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent, display->getDisplayType());
+ renderIntent, *displayId);
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
@@ -1156,10 +1169,14 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getCompositionPreference(Dataspace* outDataSpace,
- ui::PixelFormat* outPixelFormat) const {
- *outDataSpace = compositionDataSpace;
- *outPixelFormat = compositionPixelFormat;
+status_t SurfaceFlinger::getCompositionPreference(
+ Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+ Dataspace* outWideColorGamutDataspace,
+ ui::PixelFormat* outWideColorGamutPixelFormat) const {
+ *outDataspace = mDefaultCompositionDataspace;
+ *outPixelFormat = defaultCompositionPixelFormat;
+ *outWideColorGamutDataspace = mWideColorGamutCompositionDataspace;
+ *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
return NO_ERROR;
}
@@ -1235,18 +1252,22 @@
if (makeAvailable) {
mHWVsyncAvailable = true;
+ // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
+ if (mUseScheduler) {
+ mScheduler->makeHWSyncAvailable(true);
+ }
} else if (!mHWVsyncAvailable) {
// Hardware vsync is not currently available, so abort the resync
// attempt for now
return;
}
- const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- if (!getHwComposer().isConnected(displayId)) {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId || !getHwComposer().isConnected(*displayId)) {
return;
}
- const auto activeConfig = getHwComposer().getActiveConfig(displayId);
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
if (mUseScheduler) {
@@ -1297,12 +1318,11 @@
return;
}
- int32_t type;
- if (!getBE().mHwc->onVsync(hwcDisplayId, timestamp, &type)) {
+ if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
return;
}
- if (type != DisplayDevice::DISPLAY_PRIMARY) {
+ if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
// For now, we don't do anything with external display vsyncs.
return;
}
@@ -1365,11 +1385,13 @@
repaintEverything();
}
-void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
+void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
- getHwComposer().setVsyncEnabled(disp,
- enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ if (const auto displayId = getInternalDisplayId()) {
+ getHwComposer().setVsyncEnabled(*displayId,
+ enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ }
}
// Note: it is assumed the caller holds |mStateLock| when this is called
@@ -1384,7 +1406,6 @@
// mCurrentState and mDrawingState and re-apply all changes when we make the
// transition.
mDrawingState.displays.clear();
- getRenderEngine().resetCurrentSurface();
mDisplays.clear();
}
@@ -1420,8 +1441,8 @@
resetDisplayState();
getBE().mHwc.reset(); // Delete the current instance before creating the new one
- getBE().mHwc.reset(new HWComposer(std::make_unique<Hwc2::impl::Composer>(
- vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName)));
+ getBE().mHwc = getFactory().createHWComposer(
+ vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName);
getBE().mHwc->registerCallback(this, ++getBE().mComposerSequenceId);
LOG_ALWAYS_FATAL_IF(!getBE().mHwc->getComposer()->isRemote(),
@@ -1440,7 +1461,7 @@
setPowerModeInternal(display, currentDisplayPowerMode, /*stateLockHeld*/ true);
// Reset the timing values to account for the period of the swapped in HWC
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -1558,8 +1579,7 @@
getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
for (const auto& [token, display] : mDisplays) {
- const auto displayId = display->getId();
- for (auto& compositionInfo : getBE().mEndOfFrameCompositionInfo[displayId]) {
+ for (auto& compositionInfo : getBE().mEndOfFrameCompositionInfo[token]) {
compositionInfo.hwc.hwcLayer = nullptr;
}
}
@@ -1582,24 +1602,25 @@
mGeometryInvalid = false;
for (const auto& [token, display] : mDisplays) {
const auto displayId = display->getId();
- if (displayId >= 0) {
- const Vector<sp<Layer>>& currentLayers(
- display->getVisibleLayersSortedByZ());
- for (size_t i = 0; i < currentLayers.size(); i++) {
- const auto& layer = currentLayers[i];
+ if (!displayId) {
+ continue;
+ }
- if (!layer->hasHwcLayer(displayId)) {
- if (!layer->createHwcLayer(getBE().mHwc.get(), displayId)) {
- layer->forceClientComposition(displayId);
- continue;
- }
- }
+ const Vector<sp<Layer>>& currentLayers = display->getVisibleLayersSortedByZ();
+ for (size_t i = 0; i < currentLayers.size(); i++) {
+ const auto& layer = currentLayers[i];
- layer->setGeometry(display, i);
- if (mDebugDisableHWC || mDebugRegion) {
- layer->forceClientComposition(displayId);
+ if (!layer->hasHwcLayer(*displayId)) {
+ if (!layer->createHwcLayer(&getHwComposer(), *displayId)) {
+ layer->forceClientComposition(*displayId);
+ continue;
}
}
+
+ layer->setGeometry(display, i);
+ if (mDebugDisableHWC || mDebugRegion) {
+ layer->forceClientComposition(*displayId);
+ }
}
}
}
@@ -1607,41 +1628,43 @@
// Set the per-frame data
for (const auto& [token, display] : mDisplays) {
const auto displayId = display->getId();
- if (displayId < 0) {
+ if (!displayId) {
continue;
}
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
- status_t result = getBE().mHwc->setColorTransform(displayId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
- "display %d: %d", displayId, result);
+ status_t result =
+ getHwComposer().setColorTransform(*displayId, mDrawingState.colorMatrix);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %" PRIu64 ": %d",
+ *displayId, result);
}
for (auto& layer : display->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
!display->hasHDR10Support()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
!display->hasHLGSupport()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
}
// TODO(b/111562338) remove when composer 2.3 is shipped.
if (layer->hasColorTransform()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
}
- if (layer->getForceClientComposition(displayId)) {
+ if (layer->getForceClientComposition(*displayId)) {
ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(displayId, HWC2::Composition::Client);
+ layer->setCompositionType(*displayId, HWC2::Composition::Client);
continue;
}
- layer->setPerFrameData(display);
+ layer->setPerFrameData(*displayId, display->getTransform(), display->getViewport(),
+ display->getSupportedPerFrameMetadata());
}
if (useColorManagement) {
@@ -1656,16 +1679,20 @@
mDrawingState.colorMatrixChanged = false;
for (const auto& [token, display] : mDisplays) {
- const auto displayId = display->getId();
- getBE().mCompositionInfo[displayId].clear();
+ getBE().mCompositionInfo[token].clear();
+
for (auto& layer : display->getVisibleLayersSortedByZ()) {
- auto displayId = display->getId();
+ const auto displayId = display->getId();
layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
- if (!layer->setHwcLayer(displayId)) {
- ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+
+ if (displayId) {
+ if (!layer->setHwcLayer(*displayId)) {
+ ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+ }
+ layer->getBE().compositionInfo.hwc.displayId = *displayId;
}
- layer->getBE().compositionInfo.hwc.displayId = displayId;
- getBE().mCompositionInfo[displayId].push_back(layer->getBE().compositionInfo);
+
+ getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
layer->getBE().compositionInfo.hwc.hwcLayer = nullptr;
}
}
@@ -1673,7 +1700,6 @@
void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything)
{
- const auto displayId = display->getId();
// is debugging enabled
if (CC_LIKELY(!mDebugRegion))
return;
@@ -1689,7 +1715,7 @@
auto& engine(getRenderEngine());
engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
- display->swapBuffers(getHwComposer());
+ display->queueBuffer(getHwComposer());
}
}
@@ -1699,14 +1725,7 @@
usleep(mDebugRegion * 1000);
}
- if (display->isPoweredOn()) {
- status_t result = display->prepareFrame(
- *getBE().mHwc, getBE().mCompositionInfo[displayId]);
- ALOGE_IF(result != NO_ERROR,
- "prepareFrame for display %d failed:"
- " %d (%s)",
- display->getId(), result, strerror(-result));
- }
+ prepareFrame(display);
}
void SurfaceFlinger::doTracing(const char* where) {
@@ -1832,7 +1851,7 @@
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFence =
- display ? getHwComposer().getPresentFence(display->getId()) : Fence::NO_FENCE;
+ display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
getBE().mDisplayTimeline.push(presentFenceTime);
@@ -1855,8 +1874,8 @@
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
- bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ bool frameLatched = layer->onPostComposition(display->getId(), glCompositionDoneFenceTime,
+ presentFenceTime, compositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
@@ -1876,7 +1895,7 @@
}
if (!hasSyncFramework) {
- if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
+ if (display && getHwComposer().isConnected(*display->getId()) && display->isPoweredOn()) {
if (mUseScheduler) {
mScheduler->enableHardwareVsync();
} else {
@@ -1891,10 +1910,10 @@
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else if (display && getHwComposer().isConnected(display->getId())) {
+ } else if (display && getHwComposer().isConnected(*display->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(display->getId());
+ const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId());
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
@@ -1907,8 +1926,7 @@
mTimeStats.setPresentFenceGlobal(presentFenceTime);
- if (display && getHwComposer().isConnected(display->getId()) &&
- display->getPowerMode() == HWC_POWER_MODE_OFF) {
+ if (display && getHwComposer().isConnected(*display->getId()) && !display->isPoweredOn()) {
return;
}
@@ -1937,6 +1955,9 @@
ATRACE_INT("TexturePoolSize", mTexturePool.size());
}
}
+
+ mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
+ mTransactionCompletedThread.sendCallbacks();
}
void SurfaceFlinger::rebuildLayerStacks() {
@@ -1962,6 +1983,7 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool hwcLayerDestroyed = false;
+ const auto displayId = display->getId();
if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
@@ -1971,13 +1993,13 @@
} else {
// Clear out the HWC layer if this layer was
// previously visible, but no longer is
- hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
+ hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
}
} else {
// WM changes display->layerStack upon sleep/awake.
// Here we make sure we delete the HWC layers even if
// WM changed their layer stack.
- hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
+ hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
}
// If a layer is not going to get a release fence because
@@ -2102,12 +2124,11 @@
// emit any black frames until a layer is added to the layer stack.
bool mustRecompose = dirty && !(empty && wasEmpty);
- ALOGV_IF(display->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
- "id[%d]: %s composition (%sdirty %sempty %swasEmpty)", display->getId(),
- mustRecompose ? "doing" : "skipping",
- dirty ? "+" : "-",
- empty ? "+" : "-",
- wasEmpty ? "+" : "-");
+ const char flagPrefix[] = {'-', '+'};
+ static_cast<void>(flagPrefix);
+ ALOGV_IF(display->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
+ __FUNCTION__, mustRecompose ? "doing" : "skipping", display->getDebugName().c_str(),
+ flagPrefix[dirty], flagPrefix[empty], flagPrefix[wasEmpty]);
display->beginFrame(mustRecompose);
@@ -2118,17 +2139,14 @@
void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& display)
{
- const auto displayId = display->getId();
if (!display->isPoweredOn()) {
return;
}
- status_t result = display->prepareFrame(
- *getBE().mHwc, getBE().mCompositionInfo[displayId]);
- ALOGE_IF(result != NO_ERROR,
- "prepareFrame for display %d failed:"
- " %d (%s)",
- display->getId(), result, strerror(-result));
+ status_t result = display->prepareFrame(getHwComposer(),
+ getBE().mCompositionInfo[display->getDisplayToken()]);
+ ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
+ display->getDebugName().c_str(), result, strerror(-result));
}
void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
@@ -2151,8 +2169,9 @@
void SurfaceFlinger::postFrame()
{
// |mStateLock| not needed as we are on the main thread
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
- uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (display && getHwComposer().isConnected(*display->getId())) {
+ uint32_t flipCount = display->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
logFrameStats();
}
@@ -2168,20 +2187,19 @@
if (display->isPoweredOn()) {
const auto displayId = display->getId();
- if (displayId >= 0) {
- getBE().mHwc->presentAndGetReleaseFences(displayId);
+ if (displayId) {
+ getHwComposer().presentAndGetReleaseFences(*displayId);
}
- display->onSwapBuffersCompleted();
- display->makeCurrent();
+ display->onPresentDisplayCompleted();
for (auto& layer : display->getVisibleLayersSortedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
- auto hwcLayer = layer->getHwcLayer(displayId);
- if (displayId >= 0) {
- releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer);
+ if (displayId && layer->hasHwcLayer(*displayId)) {
+ releaseFence = getHwComposer().getLayerReleaseFence(*displayId,
+ layer->getHwcLayer(*displayId));
}
// If the layer was client composited in the previous frame, we
@@ -2201,14 +2219,15 @@
// display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
if (!display->getLayersNeedingFences().isEmpty()) {
- sp<Fence> presentFence = getBE().mHwc->getPresentFence(displayId);
+ sp<Fence> presentFence =
+ displayId ? getBE().mHwc->getPresentFence(*displayId) : Fence::NO_FENCE;
for (auto& layer : display->getLayersNeedingFences()) {
layer->getBE().onLayerDisplayed(presentFence);
}
}
- if (displayId >= 0) {
- getBE().mHwc->clearReleaseFences(displayId);
+ if (displayId) {
+ getHwComposer().clearReleaseFences(*displayId);
}
}
}
@@ -2243,72 +2262,36 @@
// here the transaction has been committed
}
-DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t hwcDisplayId,
- HWC2::Connection connection) const {
- // Figure out whether the event is for the primary display or an
- // external display by matching the Hwc display id against one for a
- // connected display. If we did not find a match, we then check what
- // displays are not already connected to determine the type. If we don't
- // have a connected primary display, we assume the new display is meant to
- // be the primary display, and then if we don't have an external display,
- // we assume it is that.
- const auto primaryHwcDisplayId = getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
- const auto externalHwcDisplayId =
- getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
- if (primaryHwcDisplayId && primaryHwcDisplayId == hwcDisplayId) {
- return DisplayDevice::DISPLAY_PRIMARY;
- } else if (externalHwcDisplayId && externalHwcDisplayId == hwcDisplayId) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- } else if (connection == HWC2::Connection::Connected && !primaryHwcDisplayId) {
- return DisplayDevice::DISPLAY_PRIMARY;
- } else if (connection == HWC2::Connection::Connected && !externalHwcDisplayId) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- }
-
- return DisplayDevice::DISPLAY_ID_INVALID;
-}
-
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
for (const auto& event : mPendingHotplugEvents) {
- auto displayType = determineDisplayType(event.hwcDisplayId, event.connection);
- if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
- ALOGW("Unable to determine the display type for display %" PRIu64, event.hwcDisplayId);
- continue;
- }
+ const std::optional<DisplayIdentificationInfo> info =
+ getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
- if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
- ALOGE("External displays are not supported by the vr hardware composer.");
+ if (!info) {
continue;
}
- const auto displayId =
- getBE().mHwc->onHotplug(event.hwcDisplayId, displayType, event.connection);
- if (displayId) {
- ALOGV("Display %" PRIu64 " has stable ID %" PRIu64, event.hwcDisplayId, *displayId);
- }
-
if (event.connection == HWC2::Connection::Connected) {
- if (!mDisplayTokens[displayType].get()) {
- ALOGV("Creating built in display %d", displayType);
- mDisplayTokens[displayType] = new BBinder();
- DisplayDeviceState info;
- info.type = displayType;
- info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
- "Built-in Screen" : "External Screen";
- info.isSecure = true; // All physical displays are currently considered secure.
- mCurrentState.displays.add(mDisplayTokens[displayType], info);
- mInterceptor->saveDisplayCreation(info);
+ if (!mPhysicalDisplayTokens.count(info->id)) {
+ ALOGV("Creating display %" PRIu64, info->id);
+ mPhysicalDisplayTokens[info->id] = new BBinder();
+ DisplayDeviceState state;
+ state.displayId = info->id;
+ state.isSecure = true; // All physical displays are currently considered secure.
+ state.displayName = info->name;
+ mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+ mInterceptor->saveDisplayCreation(state);
}
} else {
- ALOGV("Removing built in display %d", displayType);
+ ALOGV("Removing display %" PRIu64, info->id);
- ssize_t idx = mCurrentState.displays.indexOfKey(mDisplayTokens[displayType]);
- if (idx >= 0) {
- const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- mInterceptor->saveDisplayDeletion(info.sequenceId);
- mCurrentState.displays.removeItemsAt(idx);
+ ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+ if (index >= 0) {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ mInterceptor->saveDisplayDeletion(state.sequenceId);
+ mCurrentState.displays.removeItemsAt(index);
}
- mDisplayTokens[displayType].clear();
+ mPhysicalDisplayTokens.erase(info->id);
}
processDisplayChangesLocked();
@@ -2318,67 +2301,56 @@
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
- const wp<IBinder>& displayToken, int32_t displayId, const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
- DisplayDeviceCreationArgs creationArgs(this, displayToken, state.type, displayId);
+ const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
+ const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface,
+ const sp<IGraphicBufferProducer>& producer) {
+ DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
+ creationArgs.isVirtual = state.isVirtual();
creationArgs.isSecure = state.isSecure;
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
- if (useColorManagement && displayId >= 0) {
- std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
+ const bool isInternalDisplay = displayId && displayId == getInternalDisplayId();
+ creationArgs.isPrimary = isInternalDisplay;
+
+ if (useColorManagement && displayId) {
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (ColorMode colorMode : modes) {
if (isWideColorMode(colorMode)) {
creationArgs.hasWideColorGamut = true;
}
std::vector<RenderIntent> renderIntents =
- getHwComposer().getRenderIntents(displayId, colorMode);
+ getHwComposer().getRenderIntents(*displayId, colorMode);
creationArgs.hwcColorModes.emplace(colorMode, renderIntents);
}
}
- if (displayId >= 0) {
- getHwComposer().getHdrCapabilities(displayId, &creationArgs.hdrCapabilities);
+ if (displayId) {
+ getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities);
creationArgs.supportedPerFrameMetadata =
- getHwComposer().getSupportedPerFrameMetadata(displayId);
+ getHwComposer().getSupportedPerFrameMetadata(*displayId);
}
- auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
+ auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);
auto nativeWindow = nativeWindowSurface->getNativeWindow();
creationArgs.nativeWindow = nativeWindow;
- /*
- * Create our display's surface
- */
- std::unique_ptr<renderengine::Surface> renderSurface = getRenderEngine().createSurface();
- renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
- renderSurface->setAsync(state.isVirtual());
- renderSurface->setNativeWindow(nativeWindow.get());
- creationArgs.displayWidth = renderSurface->getWidth();
- creationArgs.displayHeight = renderSurface->getHeight();
- creationArgs.renderSurface = std::move(renderSurface);
-
// Make sure that composition can never be stalled by a virtual display
// consumer that isn't processing buffers fast enough. We have to do this
- // in two places:
- // * Here, in case the display is composed entirely by HWC.
- // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
- // window's swap interval in eglMakeCurrent, so they'll override the
- // interval we set here.
+ // here, in case the display is composed entirely by HWC.
if (state.isVirtual()) {
nativeWindow->setSwapInterval(nativeWindow.get(), 0);
}
- creationArgs.displayInstallOrientation = state.type == DisplayDevice::DISPLAY_PRIMARY
- ? primaryDisplayOrientation
- : DisplayState::eOrientationDefault;
+ creationArgs.displayInstallOrientation =
+ isInternalDisplay ? primaryDisplayOrientation : DisplayState::eOrientationDefault;
// virtual displays are always considered enabled
creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
- sp<DisplayDevice> display = new DisplayDevice(std::move(creationArgs));
+ sp<DisplayDevice> display = getFactory().createDisplayDevice(std::move(creationArgs));
if (maxFrameBufferAcquiredBuffers >= 3) {
nativeWindowSurface->preallocateBuffers();
@@ -2392,9 +2364,11 @@
}
setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
RenderIntent::COLORIMETRIC);
- if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
- display->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+ if (!state.isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
}
+
display->setLayerStack(state.layerStack);
display->setProjection(state.orientation, state.viewport, state.frame);
display->setDisplayName(state.displayName);
@@ -2420,24 +2394,22 @@
for (size_t i = 0; i < dc;) {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < 0) {
+ // Save display IDs before disconnecting.
+ const auto internalDisplayId = getInternalDisplayId();
+ const auto externalDisplayId = getExternalDisplayId();
+
// in drawing state but not in current state
- // Call makeCurrent() on the primary display so we can
- // be sure that nothing associated with this display
- // is current.
- if (const auto defaultDisplay = getDefaultDisplayDeviceLocked()) {
- defaultDisplay->makeCurrent();
- }
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
display->disconnect(getHwComposer());
}
- if (draw[i].type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (internalDisplayId && internalDisplayId == draw[i].displayId) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::Primary, false);
} else {
mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
}
- } else if (draw[i].type == DisplayDevice::DISPLAY_EXTERNAL) {
+ } else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::External, false);
@@ -2493,16 +2465,16 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
- mCreateBufferQueue(&bqProducer, &bqConsumer, false);
+ getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);
- int32_t displayId = -1;
+ std::optional<DisplayId> displayId;
if (state.isVirtual()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
if (state.surface != nullptr) {
// Allow VR composer to use virtual displays.
- if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
+ if (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()) {
int width = 0;
int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
@@ -2514,14 +2486,14 @@
ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
auto format = static_cast<ui::PixelFormat>(intFormat);
- getBE().mHwc->allocateVirtualDisplay(width, height, &format,
- &displayId);
+ displayId =
+ getHwComposer().allocateVirtualDisplay(width, height, &format);
}
// TODO: Plumb requested format back up to consumer
sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(*getBE().mHwc, displayId, state.surface,
+ new VirtualDisplaySurface(getHwComposer(), displayId, state.surface,
bqProducer, bqConsumer,
state.displayName);
@@ -2534,8 +2506,9 @@
"surface is provided (%p), ignoring it",
state.surface.get());
- displayId = state.type;
- dispSurface = new FramebufferSurface(*getBE().mHwc, displayId, bqConsumer);
+ displayId = state.displayId;
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
producer = bqProducer;
}
@@ -2545,7 +2518,9 @@
setupNewDisplayDeviceInternal(displayToken, displayId, state,
dispSurface, producer));
if (!state.isVirtual()) {
- if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
+ if (displayId == getInternalDisplayId()) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::Primary,
@@ -2554,7 +2529,7 @@
mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
true);
}
- } else if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+ } else if (displayId == getExternalDisplayId()) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::External,
@@ -2708,7 +2683,7 @@
void SurfaceFlinger::updateCursorAsync()
{
for (const auto& [token, display] : mDisplays) {
- if (display->getId() < 0) {
+ if (!display->getId()) {
continue;
}
@@ -2725,7 +2700,19 @@
for (const auto& l : mLayersPendingRemoval) {
recordBufferingStats(l->getName().string(),
l->getOccupancyHistory(true));
- l->onRemoved();
+
+ // We need to release the HWC layers when the Layer is removed
+ // from the current state otherwise the HWC layer just continues
+ // showing at its last configured state until we eventually
+ // abandon the buffer queue.
+ if (l->isRemovedFromCurrentState()) {
+ l->destroyAllHwcLayers();
+ // destroyAllHwcLayers traverses to children, but releasePendingBuffer
+ // doesn't in other scenarios. So we have to traverse explicitly here.
+ l->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* child) {
+ child->releasePendingBuffer(systemTime());
+ });
+ }
}
mLayersPendingRemoval.clear();
}
@@ -2962,7 +2949,7 @@
mGeometryInvalid = true;
}
-void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& display,
+void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& display,
const Region& inDirtyRegion) {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
@@ -2978,10 +2965,10 @@
if (!doComposeSurfaces(display)) return;
// swap buffers (presentation)
- display->swapBuffers(getHwComposer());
+ display->queueBuffer(getHwComposer());
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& display) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& display) {
ALOGV("doComposeSurfaces");
const Region bounds(display->bounds());
@@ -2994,9 +2981,31 @@
bool applyColorMatrix = false;
bool needsEnhancedColorMatrix = false;
+ // Framebuffer will live in this scope for GPU composition.
+ std::unique_ptr<renderengine::BindNativeBufferAsFramebuffer> fbo;
+
if (hasClientComposition) {
ALOGV("hasClientComposition");
+ sp<GraphicBuffer> buf = display->dequeueBuffer();
+
+ if (buf == nullptr) {
+ ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+ "client composition for this frame",
+ display->getDisplayName().c_str());
+ return false;
+ }
+
+ // Bind the framebuffer in this scope.
+ fbo = std::make_unique<renderengine::BindNativeBufferAsFramebuffer>(getRenderEngine(),
+ buf->getNativeBuffer());
+
+ if (fbo->getStatus() != NO_ERROR) {
+ ALOGW("Binding buffer for display [%s] failed with status: %d",
+ display->getDisplayName().c_str(), fbo->getStatus());
+ return false;
+ }
+
Dataspace outputDataspace = Dataspace::UNKNOWN;
if (display->hasWideColorGamut()) {
outputDataspace = display->getCompositionDataSpace();
@@ -3025,18 +3034,7 @@
colorMatrix *= mEnhancedSaturationMatrix;
}
- if (!display->makeCurrent()) {
- ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
- display->getDisplayName().c_str());
- getRenderEngine().resetCurrentSurface();
-
- // |mStateLock| not needed as we are on the main thread
- const auto defaultDisplay = getDefaultDisplayDeviceLocked();
- if (!defaultDisplay || !defaultDisplay->makeCurrent()) {
- ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
- }
- return false;
- }
+ display->setViewportAndProjection();
// Never touch the framebuffer if we don't have any framebuffer layers
if (hasDeviceComposition) {
@@ -3092,8 +3090,9 @@
case HWC2::Composition::Device:
case HWC2::Composition::Sideband:
case HWC2::Composition::SolidColor: {
+ LOG_ALWAYS_FATAL_IF(!displayId);
const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(displayId) && !firstLayer &&
+ if (layer->getClearClientTarget(*displayId) && !firstLayer &&
layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
hasClientComposition) {
// never clear the very first layer since we're
@@ -3128,11 +3127,15 @@
firstLayer = false;
}
- // Clear color transform matrix at the end of the frame.
- getRenderEngine().setColorTransform(mat4());
-
- // disable scissor at the end of the frame
- getBE().mRenderEngine->disableScissor();
+ // Perform some cleanup steps if we used client composition.
+ if (hasClientComposition) {
+ getRenderEngine().setColorTransform(mat4());
+ getBE().mRenderEngine->disableScissor();
+ display->finishBuffer();
+ // Clear out error flags here so that we don't wait until next
+ // composition to log.
+ getRenderEngine().checkErrors();
+ }
return true;
}
@@ -3158,7 +3161,7 @@
if (parent == nullptr) {
mCurrentState.layersSortedByZ.add(lbc);
} else {
- if (parent->isPendingRemoval()) {
+ if (parent->isRemovedFromCurrentState()) {
ALOGE("addClientLayer called with a removed parent");
return NAME_NOT_FOUND;
}
@@ -3174,7 +3177,6 @@
mMaxGraphicBufferProducerListSize, mNumLayers);
}
mLayersAdded = true;
- mNumLayers++;
}
// attach this layer to the client
@@ -3188,52 +3190,22 @@
return removeLayerLocked(mStateLock, layer, topLevelOnly);
}
-status_t SurfaceFlinger::removeLayerLocked(const Mutex&, const sp<Layer>& layer,
+status_t SurfaceFlinger::removeLayerLocked(const Mutex& lock, const sp<Layer>& layer,
bool topLevelOnly) {
- if (layer->isPendingRemoval()) {
- return NO_ERROR;
- }
-
const auto& p = layer->getParent();
ssize_t index;
if (p != nullptr) {
if (topLevelOnly) {
return NO_ERROR;
}
-
- sp<Layer> ancestor = p;
- while (ancestor->getParent() != nullptr) {
- ancestor = ancestor->getParent();
- }
- if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
- ALOGE("removeLayer called with a layer whose parent has been removed");
- return NAME_NOT_FOUND;
- }
-
index = p->removeChild(layer);
} else {
index = mCurrentState.layersSortedByZ.remove(layer);
}
- // As a matter of normal operation, the LayerCleaner will produce a second
- // attempt to remove the surface. The Layer will be kept alive in mDrawingState
- // so we will succeed in promoting it, but it's already been removed
- // from mCurrentState. As long as we can find it in mDrawingState we have no problem
- // otherwise something has gone wrong and we are leaking the layer.
- if (index < 0 && mDrawingState.layersSortedByZ.indexOf(layer) < 0) {
- ALOGE("Failed to find layer (%s) in layer parent (%s).",
- layer->getName().string(),
- (p != nullptr) ? p->getName().string() : "no-parent");
- return BAD_VALUE;
- } else if (index < 0) {
- return NO_ERROR;
- }
-
layer->onRemovedFromCurrentState();
- mLayersPendingRemoval.add(layer);
- mLayersRemoved = true;
- mNumLayers -= 1 + layer->getChildrenCount();
- setTransactionFlags(eTransactionNeeded);
+
+ markLayerPendingRemovalLocked(lock, layer);
return NO_ERROR;
}
@@ -3314,9 +3286,15 @@
transactionFlags |= setDisplayStateLocked(display);
}
+ uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
- transactionFlags |= setClientStateLocked(state);
+ clientStateFlags |= setClientStateLocked(state);
}
+ // If the state doesn't require a traversal and there are callbacks, send them now
+ if (!(clientStateFlags & eTraversalNeeded)) {
+ mTransactionCompletedThread.sendCallbacks();
+ }
+ transactionFlags |= clientStateFlags;
// Iterate through all layers again to determine if any need to be destroyed. Marking layers
// as destroyed should only occur after setting all other states. This is to allow for a
@@ -3434,11 +3412,6 @@
return 0;
}
- if (layer->isPendingRemoval()) {
- ALOGW("Attempting to set client state on removed layer: %s", layer->getName().string());
- return 0;
- }
-
uint32_t flags = 0;
const uint32_t what = s.what;
@@ -3630,6 +3603,17 @@
if (what & layer_state_t::eSidebandStreamChanged) {
if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
}
+
+ std::vector<sp<CallbackHandle>> callbackHandles;
+ if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
+ mTransactionCompletedThread.run();
+ for (const auto& [listener, callbackIds] : s.listenerCallbacks) {
+ callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+ }
+ }
+ if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
+ // Do not put anything that updates layer state or modifies flags after
+ // setTransactionCompletedListener
return flags;
}
@@ -3642,11 +3626,6 @@
return;
}
- if (layer->isPendingRemoval()) {
- ALOGW("Attempting to destroy on removed layer: %s", layer->getName().string());
- return;
- }
-
if (state.what & layer_state_t::eDestroySurface) {
removeLayerLocked(mStateLock, layer);
}
@@ -3763,7 +3742,7 @@
}
sp<BufferQueueLayer> layer =
- new BufferQueueLayer(LayerCreationArgs(this, client, name, w, h, flags));
+ getFactory().createBufferQueueLayer(LayerCreationArgs(this, client, name, w, h, flags));
status_t err = layer->setDefaultBufferProperties(w, h, format);
if (err == NO_ERROR) {
*handle = layer->getHandle();
@@ -3779,7 +3758,7 @@
uint32_t w, uint32_t h, uint32_t flags,
sp<IBinder>* handle, sp<Layer>* outLayer) {
sp<BufferStateLayer> layer =
- new BufferStateLayer(LayerCreationArgs(this, client, name, w, h, flags));
+ getFactory().createBufferStateLayer(LayerCreationArgs(this, client, name, w, h, flags));
*handle = layer->getHandle();
*outLayer = layer;
@@ -3790,7 +3769,7 @@
const String8& name, uint32_t w, uint32_t h, uint32_t flags,
sp<IBinder>* handle, sp<Layer>* outLayer)
{
- *outLayer = new ColorLayer(LayerCreationArgs(this, client, name, w, h, flags));
+ *outLayer = getFactory().createColorLayer(LayerCreationArgs(this, client, name, w, h, flags));
*handle = (*outLayer)->getHandle();
return NO_ERROR;
}
@@ -3799,7 +3778,8 @@
const String8& name, uint32_t w, uint32_t h, uint32_t flags,
sp<IBinder>* handle, sp<Layer>* outLayer)
{
- *outLayer = new ContainerLayer(LayerCreationArgs(this, client, name, w, h, flags));
+ *outLayer =
+ getFactory().createContainerLayer(LayerCreationArgs(this, client, name, w, h, flags));
*handle = (*outLayer)->getHandle();
return NO_ERROR;
}
@@ -3819,23 +3799,22 @@
return err;
}
-status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
+void SurfaceFlinger::markLayerPendingRemovalLocked(const Mutex&, const sp<Layer>& layer) {
+ mLayersPendingRemoval.add(layer);
+ mLayersRemoved = true;
+ setTransactionFlags(eTransactionNeeded);
+}
+
+void SurfaceFlinger::onHandleDestroyed(const sp<Layer>& layer)
{
- // called by ~LayerCleaner() when all references to the IBinder (handle)
- // are gone
- sp<Layer> l = layer.promote();
- if (l == nullptr) {
- // The layer has already been removed, carry on
- return NO_ERROR;
- }
- // If we have a parent, then we can continue to live as long as it does.
- return removeLayer(l, true);
+ Mutex::Autolock lock(mStateLock);
+ markLayerPendingRemovalLocked(mStateLock, layer);
}
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
- const auto displayToken = mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY];
+ const auto displayToken = getInternalDisplayToken();
if (!displayToken) return;
// reset screen orientation and use primary layer stack
@@ -3859,7 +3838,7 @@
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL, /*stateLockHeld*/ false);
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -3876,16 +3855,18 @@
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
bool stateLockHeld) {
- const int32_t displayId = display->getId();
- ALOGD("Setting power mode %d on display %d", mode, displayId);
-
- int currentMode = display->getPowerMode();
- if (mode == currentMode) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set power mode for virtual display");
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
+ ALOGD("Setting power mode %d on display %" PRIu64, mode, *displayId);
+
+ int currentMode = display->getPowerMode();
+ if (mode == currentMode) {
return;
}
@@ -3901,12 +3882,10 @@
mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).sequenceId, mode);
}
- int32_t type = display->getDisplayType();
if (currentMode == HWC_POWER_MODE_OFF) {
// Turn on the display
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
} else {
@@ -3937,7 +3916,6 @@
} else {
disableHardwareVsync(true); // also cancels any in-progress resync
}
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
} else {
@@ -3945,15 +3923,14 @@
}
}
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
} else if (mode == HWC_POWER_MODE_DOZE ||
mode == HWC_POWER_MODE_NORMAL) {
// Update display while dozing
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
} else {
@@ -3969,24 +3946,23 @@
} else {
disableHardwareVsync(true); // also cancels any in-progress resync
}
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
} else {
mEventThread->onScreenReleased();
}
}
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
} else {
ALOGE("Attempting to set unknown power mode: %d\n", mode);
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
}
if (display->isPrimary()) {
mTimeStats.setPowerMode(mode);
}
- ALOGD("Finished setting power mode %d on display %d", mode, displayId);
+ ALOGD("Finished setting power mode %d on display %" PRIu64, mode, *displayId);
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
@@ -4165,9 +4141,9 @@
index++;
}
- if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- getHwComposer().isConnected(displayId)) {
- const auto activeConfig = getBE().mHwc->getActiveConfig(displayId);
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
result.appendFormat("%" PRId64 "\n", period);
}
@@ -4308,13 +4284,17 @@
void SurfaceFlinger::dumpDisplayIdentificationData(String8& result) const {
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- const auto hwcDisplayId = getHwComposer().getHwcDisplayId(displayId);
+ const auto displayId = display->getId();
+ if (!displayId) {
+ continue;
+ }
+ const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
if (!hwcDisplayId) {
continue;
}
- result.appendFormat("Display %d (HWC display %" PRIu64 "): ", displayId, *hwcDisplayId);
+ result.appendFormat("Display %" PRIu64 " (HWC display %" PRIu64 "): ", *displayId,
+ *hwcDisplayId);
uint8_t port;
DisplayIdentificationData data;
if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
@@ -4345,7 +4325,6 @@
result.append(edid->displayName.data(), edid->displayName.length());
result.append("\"\n");
}
- result.append("\n");
}
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
@@ -4357,13 +4336,13 @@
// TODO: print out if wide-color mode is active or not
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
- result.appendFormat("Display %d color modes:\n", displayId);
- std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
+ result.appendFormat("Display %" PRIu64 " color modes:\n", *displayId);
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (auto&& mode : modes) {
result.appendFormat(" %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
@@ -4379,17 +4358,13 @@
std::string stringResult;
for (const auto& [token, display] : mDisplays) {
- const auto displayId = display->getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ const auto it = getBE().mEndOfFrameCompositionInfo.find(token);
+ if (it == getBE().mEndOfFrameCompositionInfo.end()) {
continue;
}
- const auto& compositionInfoIt = getBE().mEndOfFrameCompositionInfo.find(displayId);
- if (compositionInfoIt == getBE().mEndOfFrameCompositionInfo.end()) {
- break;
- }
- const auto& compositionInfoList = compositionInfoIt->second;
- stringResult += base::StringPrintf("Display: %d\n", displayId);
+ const auto& compositionInfoList = it->second;
+ stringResult += base::StringPrintf("%s\n", display->getDebugName().c_str());
stringResult += base::StringPrintf("numComponents: %zu\n", compositionInfoList.size());
for (const auto& compositionInfo : compositionInfoList) {
compositionInfo.dump(stringResult, nullptr);
@@ -4423,11 +4398,12 @@
layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
- const int32_t displayId = display.getId();
+ const auto displayId = display.getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(displayId)) {
+ if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, displayId);
+ layer->writeToProto(layerProto, *displayId);
}
});
@@ -4481,25 +4457,19 @@
const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
- if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- getHwComposer().isConnected(displayId)) {
- const auto activeConfig = getHwComposer().getActiveConfig(displayId);
- result.appendFormat("Display %d: "
- "app phase %" PRId64 " ns, "
- "sf phase %" PRId64 " ns, "
- "early app phase %" PRId64 " ns, "
- "early sf phase %" PRId64 " ns, "
- "early app gl phase %" PRId64 " ns, "
- "early sf gl phase %" PRId64 " ns, "
- "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- displayId,
- vsyncPhaseOffsetNs,
- sfVsyncPhaseOffsetNs,
- appEarlyOffset,
- sfEarlyOffset,
- appEarlyGlOffset,
- sfEarlyGlOffset,
- dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+ result.appendFormat("Display %" PRIu64 ": app phase %" PRId64 " ns, "
+ "sf phase %" PRId64 " ns, "
+ "early app phase %" PRId64 " ns, "
+ "early sf phase %" PRId64 " ns, "
+ "early app gl phase %" PRId64 " ns, "
+ "early sf gl phase %" PRId64 " ns, "
+ "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+ *displayId, vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset,
+ sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
+ dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
}
result.append("\n");
@@ -4552,12 +4522,9 @@
result.append("SurfaceFlinger global state:\n");
colorizer.reset(result);
- HWComposer& hwc(getHwComposer());
- const auto display = getDefaultDisplayDeviceLocked();
-
getBE().mRenderEngine->dump(result);
- if (display) {
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
display->undefinedRegion.dump(result, "undefinedRegion");
result.appendFormat(" orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
display->isPoweredOn());
@@ -4566,8 +4533,9 @@
" gpu_to_cpu_unsupported : %d\n",
mTransactionFlags.load(), !mGpuToCpuSupported);
- if (display) {
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
result.appendFormat(" refresh-rate : %f fps\n"
" x-dpi : %f\n"
" y-dpi : %f\n",
@@ -4599,14 +4567,14 @@
* HWC layer minidump
*/
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
- result.appendFormat("Display %d HWC layers:\n", displayId);
+ result.appendFormat("Display %" PRIu64 " HWC layers:\n", *displayId);
Layer::miniDumpHeader(result);
- mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, displayId); });
+ mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, *displayId); });
result.append("\n");
}
@@ -4619,7 +4587,7 @@
bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
result.appendFormat(" h/w composer %s\n",
hwcDisabled ? "disabled" : "enabled");
- hwc.dump(result);
+ getHwComposer().dump(result);
/*
* Dump gralloc state
@@ -4637,7 +4605,7 @@
}
}
-const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int32_t displayId) {
+const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
// Note: mStateLock is held here
for (const auto& [token, display] : mDisplays) {
if (display->getId() == displayId) {
@@ -4645,7 +4613,7 @@
}
}
- ALOGE("%s: Invalid display %d", __FUNCTION__, displayId);
+ ALOGE("%s: Invalid display %" PRIu64, __FUNCTION__, displayId);
static const Vector<sp<Layer>> empty;
return empty;
}
@@ -4746,6 +4714,7 @@
case SET_TRANSACTION_STATE:
// Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
case CREATE_SCOPED_CONNECTION:
+ case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE: {
return OK;
}
@@ -4778,9 +4747,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1029 are currently use for backdoors. The code
+ // Numbers from 1000 to 1031 are currently use for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1029) {
+ if (code >= 1000 && code <= 1031) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -4976,11 +4945,9 @@
repaintEverything();
return NO_ERROR;
}
- // TODO(b/111505327): Find out whether the usage of 1024 can switch to 1030,
- // deprecate 1024 if they can.
- case 1024: { // Does device have wide color gamut display?
- reply->writeBool(hasWideColorDisplay);
- return NO_ERROR;
+ // Deprecate, use 1030 to check whether the device is color managed.
+ case 1024: {
+ return NAME_NOT_FOUND;
}
case 1025: { // Set layer tracing
n = data.readInt32();
@@ -5031,59 +4998,43 @@
reply->writeBool(getBE().mHwc->isUsingVrComposer());
return NO_ERROR;
}
- case 1029: {
- // Code 1029 is an experimental feature that allows applications to
- // simulate a high frequency panel by setting a multiplier and divisor
- // on the VSYNC-sf clock. If either the multiplier or divisor are
- // 0, then the code simply return the current multiplier and divisor.
- HWC2::Device::FrequencyScaler frequencyScaler;
- frequencyScaler.multiplier = data.readInt32();
- frequencyScaler.divisor = data.readInt32();
-
- if ((frequencyScaler.multiplier == 0) || (frequencyScaler.divisor == 0)) {
- frequencyScaler = getBE().mHwc->getDisplayFrequencyScaleParameters();
- reply->writeInt32(frequencyScaler.multiplier);
- reply->writeInt32(frequencyScaler.divisor);
- return NO_ERROR;
- }
-
- if ((frequencyScaler.multiplier == 1) && (frequencyScaler.divisor == 1)) {
- if (mUseScheduler) {
- mScheduler->enableHardwareVsync();
- } else {
- enableHardwareVsync();
- }
- } else {
- if (mUseScheduler) {
- mScheduler->disableHardwareVsync(true);
- } else {
- disableHardwareVsync(true);
- }
- }
- mPrimaryDispSync->scalePeriod(frequencyScaler);
- getBE().mHwc->setDisplayFrequencyScaleParameters(frequencyScaler);
-
- ATRACE_INT("PeriodMultiplier", frequencyScaler.multiplier);
- ATRACE_INT("PeriodDivisor", frequencyScaler.divisor);
-
- const hwc2_display_t hwcDisplayId = getBE().mHwc->getActiveConfig(
- DisplayDevice::DISPLAY_PRIMARY)->getDisplayId();
-
- onHotplugReceived(getBE().mComposerSequenceId,
- hwcDisplayId, HWC2::Connection::Disconnected);
- onHotplugReceived(getBE().mComposerSequenceId,
- hwcDisplayId, HWC2::Connection::Connected);
- frequencyScaler = getBE().mHwc->getDisplayFrequencyScaleParameters();
- reply->writeInt32(frequencyScaler.multiplier);
- reply->writeInt32(frequencyScaler.divisor);
-
- return NO_ERROR;
- }
// Is device color managed?
case 1030: {
reply->writeBool(useColorManagement);
return NO_ERROR;
}
+ // Override default composition data space
+ // adb shell service call SurfaceFlinger 1031 i32 1 DATASPACE_NUMBER DATASPACE_NUMBER \
+ // && adb shell stop zygote && adb shell start zygote
+ // to restore: adb shell service call SurfaceFlinger 1031 i32 0 && \
+ // adb shell stop zygote && adb shell start zygote
+ case 1031: {
+ Mutex::Autolock _l(mStateLock);
+ n = data.readInt32();
+ if (n) {
+ n = data.readInt32();
+ if (n) {
+ Dataspace dataspace = static_cast<Dataspace>(n);
+ if (!validateCompositionDataspace(dataspace)) {
+ return BAD_VALUE;
+ }
+ mDefaultCompositionDataspace = dataspace;
+ }
+ n = data.readInt32();
+ if (n) {
+ Dataspace dataspace = static_cast<Dataspace>(n);
+ if (!validateCompositionDataspace(dataspace)) {
+ return BAD_VALUE;
+ }
+ mWideColorGamutCompositionDataspace = dataspace;
+ }
+ } else {
+ // restore composition data space.
+ mDefaultCompositionDataspace = defaultCompositionDataspace;
+ mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
+ }
+ return NO_ERROR;
+ }
}
}
return err;
@@ -5108,7 +5059,8 @@
};
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
- sp<GraphicBuffer>* outBuffer, Rect sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
uint32_t reqWidth, uint32_t reqHeight,
bool useIdentityTransform,
ISurfaceComposer::Rotation rotation) {
@@ -5125,10 +5077,6 @@
display = getDisplayDeviceLocked(displayToken);
if (!display) return BAD_VALUE;
- // ignore sourceCrop (i.e., use the projected logical display
- // viewport) until the framework is fixed
- sourceCrop.clear();
-
// set the requested width/height to the logical display viewport size
// by default
if (reqWidth == 0 || reqHeight == 0) {
@@ -5137,23 +5085,27 @@
}
}
- DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, renderAreaRotation);
+ DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
+ renderAreaRotation);
auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
display, std::placeholders::_1);
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform);
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
+ useIdentityTransform);
}
status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
- sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
float frameScale, bool childrenOnly) {
ATRACE_CALL();
class LayerRenderArea : public RenderArea {
public:
LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
- int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
- : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR),
+ int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace,
+ bool childrenOnly)
+ : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace),
mLayer(layer),
mCrop(crop),
mNeedsFiltering(false),
@@ -5200,7 +5152,7 @@
drawLayers();
} else {
Rect bounds = getBounds();
- screenshotParentLayer = new ContainerLayer(
+ screenshotParentLayer = mFlinger->getFactory().createContainerLayer(
LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
bounds.getWidth(), bounds.getHeight(), 0));
@@ -5226,7 +5178,7 @@
auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
auto parent = layerHandle->owner.promote();
- if (parent == nullptr || parent->isPendingRemoval()) {
+ if (parent == nullptr || parent->isRemovedFromCurrentState()) {
ALOGE("captureLayers called with a removed parent");
return NAME_NOT_FOUND;
}
@@ -5260,7 +5212,7 @@
reqHeight = 1;
}
- LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
+ LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly);
auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
@@ -5272,19 +5224,23 @@
visitor(layer);
});
};
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, false);
+ return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false);
}
status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer,
+ const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform) {
ATRACE_CALL();
+ // TODO(b/116112787) Make buffer usage a parameter.
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
- *outBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
- HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+ *outBuffer =
+ getFactory().createGraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+ static_cast<android_pixel_format>(reqPixelFormat), 1,
+ usage, "screenshot");
// This mutex protects syncFd and captureResult for communication of the return values from the
// main thread back to this Binder thread
@@ -5360,8 +5316,7 @@
const auto sourceCrop = renderArea.getSourceCrop();
const auto rotation = renderArea.getRotationFlags();
- // assume ColorMode::SRGB / RenderIntent::COLORIMETRIC
- engine.setOutputDataSpace(Dataspace::SRGB);
+ engine.setOutputDataSpace(renderArea.getReqDataSpace());
engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
// make sure to clear all GL error flags
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 658f04e..f5218b1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -59,9 +59,10 @@
#include "LayerBE.h"
#include "LayerStats.h"
#include "LayerVector.h"
-#include "StartPropertySetThread.h"
+#include "SurfaceFlingerFactory.h"
#include "SurfaceInterceptor.h"
#include "SurfaceTracing.h"
+#include "TransactionCompletedThread.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
@@ -76,10 +77,11 @@
#include <map>
#include <mutex>
#include <queue>
+#include <set>
#include <string>
#include <thread>
+#include <unordered_map>
#include <utility>
-#include "RenderArea.h"
#include <layerproto/LayerProtoHeader.h>
@@ -222,8 +224,8 @@
// instances. Each hardware composer instance gets a different sequence id.
int32_t mComposerSequenceId;
- std::unordered_map<int32_t, std::vector<CompositionInfo>> mCompositionInfo;
- std::unordered_map<int32_t, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
+ std::map<wp<IBinder>, std::vector<CompositionInfo>> mCompositionInfo;
+ std::map<wp<IBinder>, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
};
@@ -294,8 +296,14 @@
// The data space and pixel format that SurfaceFlinger expects hardware composer
// to composite efficiently. Meaning under most scenarios, hardware composer
// will accept layers with the data space and pixel format.
- static ui::Dataspace compositionDataSpace;
- static ui::PixelFormat compositionPixelFormat;
+ static ui::Dataspace defaultCompositionDataspace;
+ static ui::PixelFormat defaultCompositionPixelFormat;
+
+ // The data space and pixel format that SurfaceFlinger expects hardware composer
+ // to composite efficiently for wide color gamut surfaces. Meaning under most scenarios,
+ // hardware composer will accept layers with the data space and pixel format.
+ static ui::Dataspace wideColorGamutCompositionDataspace;
+ static ui::PixelFormat wideColorGamutCompositionPixelFormat;
static char const* getServiceName() ANDROID_API {
return "SurfaceFlinger";
@@ -303,8 +311,8 @@
struct SkipInitializationTag {};
static constexpr SkipInitializationTag SkipInitialization;
- explicit SurfaceFlinger(SkipInitializationTag) ANDROID_API;
- SurfaceFlinger() ANDROID_API;
+ SurfaceFlinger(surfaceflinger::Factory&, SkipInitializationTag) ANDROID_API;
+ explicit SurfaceFlinger(surfaceflinger::Factory&) ANDROID_API;
// must be called before clients can connect
void init() ANDROID_API;
@@ -325,6 +333,8 @@
// force full composition on all displays
void repaintEverything();
+ surfaceflinger::Factory& getFactory() { return mFactory; }
+
// returns the default Display
sp<const DisplayDevice> getDefaultDisplayDevice() const {
Mutex::Autolock _l(mStateLock);
@@ -340,7 +350,7 @@
// enable/disable h/w composer event
// TODO: this should be made accessible only to EventThread
- void setVsyncEnabled(int disp, int enabled);
+ void setVsyncEnabled(EventThread::DisplayType displayType, bool enabled);
// called on the main thread by MessageQueue when an internal message
// is received
@@ -349,13 +359,20 @@
// for debugging only
// TODO: this should be made accessible only to HWComposer
- const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id);
+ const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
renderengine::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
bool authenticateSurfaceTextureLocked(
const sp<IGraphicBufferProducer>& bufferProducer) const;
+ inline void onLayerCreated() { mNumLayers++; }
+ inline void onLayerDestroyed() { mNumLayers--; }
+
+ TransactionCompletedThread& getTransactionCompletedThread() {
+ return mTransactionCompletedThread;
+ }
+
private:
friend class Client;
friend class DisplayEventConnection;
@@ -433,10 +450,14 @@
virtual sp<IDisplayEventConnection> createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
virtual status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
+ const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ ISurfaceComposer::Rotation rotation);
virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
- const Rect& sourceCrop, float frameScale, bool childrenOnly);
+ const ui::Dataspace reqDataspace,
+ const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
+ float frameScale, bool childrenOnly);
virtual status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
virtual status_t getDisplayConfigs(const sp<IBinder>& displayToken,
Vector<DisplayInfo>* configs);
@@ -454,8 +475,10 @@
virtual status_t enableVSyncInjections(bool enable);
virtual status_t injectVSync(nsecs_t when);
virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
- status_t getCompositionPreference(ui::Dataspace* outDataSpace,
- ui::PixelFormat* outPixelFormat) const override;
+ virtual status_t getColorManagement(bool* outGetColorManagement) const;
+ status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+ ui::Dataspace* outWideColorGamutDataspace,
+ ui::PixelFormat* outWideColorGamutPixelFormat) const override;
/* ------------------------------------------------------------------------
* DeathRecipient interface
@@ -561,10 +584,12 @@
// ISurfaceComposerClient::destroySurface()
status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
+ void markLayerPendingRemovalLocked(const Mutex& /* mStateLock */, const sp<Layer>& layer);
+
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
// resources associated to this layer.
- status_t onLayerDestroyed(const wp<Layer>& layer);
+ void onHandleDestroyed(const sp<Layer>& layer);
// remove a layer from SurfaceFlinger immediately
status_t removeLayer(const sp<Layer>& layer, bool topLevelOnly = false);
@@ -586,7 +611,7 @@
void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
bool useIdentityTransform);
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- sp<GraphicBuffer>* outBuffer,
+ sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform);
status_t captureScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
@@ -595,7 +620,7 @@
void traverseLayersInDisplay(const sp<const DisplayDevice>& display,
const LayerVector::Visitor& visitor);
- sp<StartPropertySetThread> mStartPropertySetThread = nullptr;
+ sp<StartPropertySetThread> mStartPropertySetThread;
/* ------------------------------------------------------------------------
* Properties
@@ -640,7 +665,10 @@
}
sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
- return getDisplayDeviceLocked(mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY]);
+ if (const auto token = getInternalDisplayToken()) {
+ return getDisplayDeviceLocked(token);
+ }
+ return nullptr;
}
// mark a region of a layer stack dirty. this updates the dirty
@@ -693,10 +721,10 @@
void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
void doTracing(const char* where);
void logLayerStats();
- void doDisplayComposition(const sp<const DisplayDevice>& display, const Region& dirtyRegion);
+ void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
// This fails if using GL and the surface has been destroyed.
- bool doComposeSurfaces(const sp<const DisplayDevice>& display);
+ bool doComposeSurfaces(const sp<DisplayDevice>& display);
void postFramebuffer(const sp<DisplayDevice>& display);
void postFrame();
@@ -705,10 +733,8 @@
/* ------------------------------------------------------------------------
* Display management
*/
- DisplayDevice::DisplayType determineDisplayType(hwc2_display_t hwcDisplayId,
- HWC2::Connection connection) const;
sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
- int32_t displayId,
+ const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer);
@@ -740,6 +766,37 @@
}
private:
+ sp<IBinder> getPhysicalDisplayToken(DisplayId displayId) const {
+ const auto it = mPhysicalDisplayTokens.find(displayId);
+ return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
+ }
+
+ std::optional<DisplayId> getPhysicalDisplayId(const sp<IBinder>& displayToken) const {
+ for (const auto& [id, token] : mPhysicalDisplayTokens) {
+ if (token == displayToken) {
+ return id;
+ }
+ }
+ return {};
+ }
+
+ // TODO(b/74619554): Remove special cases for primary display.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ }
+
+ std::optional<DisplayId> getInternalDisplayId() const {
+ const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
+ return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+ }
+
+ // TODO(b/74619554): Remove special cases for external display.
+ std::optional<DisplayId> getExternalDisplayId() const {
+ const auto hwcDisplayId = getHwComposer().getExternalHwcDisplayId();
+ return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+ }
+
void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
@@ -781,6 +838,8 @@
* Attributes
*/
+ surfaceflinger::Factory& mFactory;
+
// access must be protected by mStateLock
mutable Mutex mStateLock;
State mCurrentState{LayerVector::StateSet::Current};
@@ -815,7 +874,7 @@
std::unique_ptr<VSyncSource> mSfEventThreadSource;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
std::unique_ptr<EventControlThread> mEventControlThread;
- sp<IBinder> mDisplayTokens[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
+ std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
VSyncModulator mVsyncModulator;
@@ -858,19 +917,20 @@
nsecs_t mPostFramebufferTime;
bool mForceFullDamage;
bool mPropagateBackpressure = true;
- std::unique_ptr<SurfaceInterceptor> mInterceptor =
- std::make_unique<impl::SurfaceInterceptor>(this);
+ std::unique_ptr<SurfaceInterceptor> mInterceptor{mFactory.createSurfaceInterceptor(this)};
SurfaceTracing mTracing;
LayerStats mLayerStats;
TimeStats& mTimeStats = TimeStats::getInstance();
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount{0};
+ TransactionCompletedThread mTransactionCompletedThread;
+
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
// these are thread safe
- mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};
+ mutable std::unique_ptr<MessageQueue> mEventQueue{mFactory.createMessageQueue()};
FrameTracker mAnimFrameTracker;
std::unique_ptr<DispSync> mPrimaryDispSync;
@@ -917,16 +977,8 @@
// Applied on Display P3 layers when the render intent is non-colorimetric.
mat4 mEnhancedSaturationMatrix;
- using CreateBufferQueueFunction =
- std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
- sp<IGraphicBufferConsumer>* /* outConsumer */,
- bool /* consumerIsSurfaceFlinger */)>;
- CreateBufferQueueFunction mCreateBufferQueue;
-
- using CreateNativeWindowSurfaceFunction =
- std::function<std::unique_ptr<surfaceflinger::NativeWindowSurface>(
- const sp<IGraphicBufferProducer>&)>;
- CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
+ ui::Dataspace mDefaultCompositionDataspace;
+ ui::Dataspace mWideColorGamutCompositionDataspace;
SurfaceFlingerBE mBE;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index b37d6f0..1261aee 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -14,13 +14,112 @@
* limitations under the License.
*/
-#include "SurfaceFlingerFactory.h"
+#include <ui/GraphicBuffer.h>
+
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "ContainerLayer.h"
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "NativeWindowSurface.h"
+#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
+#include "SurfaceFlingerFactory.h"
+#include "SurfaceInterceptor.h"
+
+#include "DisplayHardware/ComposerHal.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventControlThread.h"
+#include "Scheduler/MessageQueue.h"
+#include "Scheduler/Scheduler.h"
namespace android::surfaceflinger {
sp<SurfaceFlinger> createSurfaceFlinger() {
- return new SurfaceFlinger();
+ class Factory final : public surfaceflinger::Factory {
+ public:
+ Factory() = default;
+ ~Factory() = default;
+
+ std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework,
+ int64_t dispSyncPresentTimeOffset) override {
+ // Note: We create a local temporary with the real DispSync implementation
+ // type temporarily so we can initialize it with the configured values,
+ // before storing it for more generic use using the interface type.
+ auto primaryDispSync = std::make_unique<android::impl::DispSync>(name);
+ primaryDispSync->init(hasSyncFramework, dispSyncPresentTimeOffset);
+ return primaryDispSync;
+ }
+
+ std::unique_ptr<EventControlThread> createEventControlThread(
+ std::function<void(bool)> setVSyncEnabled) override {
+ return std::make_unique<android::impl::EventControlThread>(setVSyncEnabled);
+ }
+
+ std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override {
+ return std::make_unique<HWComposer>(
+ std::make_unique<Hwc2::impl::Composer>(serviceName));
+ }
+
+ std::unique_ptr<MessageQueue> createMessageQueue() override {
+ return std::make_unique<android::impl::MessageQueue>();
+ }
+
+ std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) override {
+ return std::make_unique<Scheduler>(callback);
+ }
+
+ std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(
+ SurfaceFlinger* flinger) override {
+ return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+ }
+
+ sp<StartPropertySetThread> createStartPropertySetThread(
+ bool timestampPropertyValue) override {
+ return new StartPropertySetThread(timestampPropertyValue);
+ }
+
+ sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
+ return new DisplayDevice(std::move(creationArgs));
+ }
+
+ sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ std::string requestorName) override {
+ return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+ }
+
+ void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+ sp<IGraphicBufferConsumer>* outConsumer,
+ bool consumerIsSurfaceFlinger) override {
+ BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+ }
+
+ std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+ const sp<IGraphicBufferProducer>& producer) override {
+ return surfaceflinger::impl::createNativeWindowSurface(producer);
+ }
+
+ sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override {
+ return new ContainerLayer(args);
+ }
+
+ sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override {
+ return new BufferQueueLayer(args);
+ }
+
+ sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override {
+ return new BufferStateLayer(args);
+ }
+
+ sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override {
+ return new ColorLayer(args);
+ }
+ };
+ static Factory factory;
+
+ return new SurfaceFlinger(factory);
}
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 65eb797..496bbf0 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -16,15 +16,76 @@
#pragma once
+#include <cinttypes>
+#include <functional>
+#include <memory>
+#include <string>
+
#include <cutils/compiler.h>
#include <utils/StrongPointer.h>
namespace android {
+typedef int32_t PixelFormat;
+
+class BufferQueueLayer;
+class BufferStateLayer;
+class ColorLayer;
+class ContainerLayer;
+class DisplayDevice;
+class DispSync;
+class EventControlThread;
+class GraphicBuffer;
+class HWComposer;
+class IGraphicBufferConsumer;
+class IGraphicBufferProducer;
+class MessageQueue;
+class Scheduler;
+class StartPropertySetThread;
class SurfaceFlinger;
+class SurfaceInterceptor;
+
+struct DisplayDeviceCreationArgs;
+struct LayerCreationArgs;
namespace surfaceflinger {
+class NativeWindowSurface;
+
+// The interface that SurfaceFlinger uses to create all of the implementations
+// of each interface.
+class Factory {
+public:
+ virtual std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework,
+ int64_t dispSyncPresentTimeOffset) = 0;
+ virtual std::unique_ptr<EventControlThread> createEventControlThread(
+ std::function<void(bool)> setVSyncEnabled) = 0;
+ virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
+ virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
+ virtual std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) = 0;
+ virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
+
+ virtual sp<StartPropertySetThread> createStartPropertySetThread(
+ bool timestampPropertyValue) = 0;
+ virtual sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&&) = 0;
+ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t layerCount,
+ uint64_t usage, std::string requestorName) = 0;
+ virtual void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+ sp<IGraphicBufferConsumer>* outConsumer,
+ bool consumerIsSurfaceFlinger) = 0;
+ virtual std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+ const sp<IGraphicBufferProducer>&) = 0;
+
+ virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0;
+ virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
+ virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
+ virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
+
+protected:
+ ~Factory() = default;
+};
+
ANDROID_API sp<SurfaceFlinger> createSurfaceFlinger();
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 57bda5a..7faaff6 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -495,8 +495,10 @@
DisplayCreation* creation(increment->mutable_display_creation());
creation->set_id(info.sequenceId);
creation->set_name(info.displayName);
- creation->set_type(info.type);
creation->set_is_secure(info.isSecure);
+ if (info.displayId) {
+ creation->set_display_id(*info.displayId);
+ }
}
void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t sequenceId) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 43fa262..9730e8c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -173,8 +173,8 @@
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
+ const std::string& layerName = layerRecord.layerName;
if (prevTimeRecord.ready) {
- const std::string& layerName = layerRecord.layerName;
if (!mTimeStats.stats.count(layerName)) {
mTimeStats.stats[layerName].layerName = layerName;
mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,6 +220,18 @@
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
+
+ // Output additional trace points to track frame time.
+ ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
+ ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
+ timeRecords[0].frameTime.acquireTime);
+ ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
+ timeRecords[0].frameTime.latchTime);
+ ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
+ timeRecords[0].frameTime.desiredTime);
+ ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
+ timeRecords[0].frameTime.presentTime);
+
prevTimeRecord = timeRecords[0];
timeRecords.pop_front();
layerRecord.waitData--;
@@ -241,25 +253,18 @@
return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
}
-void TimeStats::setLayerName(int32_t layerID, const std::string& layerName) {
+void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+ nsecs_t postTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%d]-[%s]", layerID, layerName.c_str());
+ ALOGV("[%d]-[%" PRIu64 "]-[%s]-PostTime[%" PRId64 "]", layerID, frameNumber, layerName.c_str(),
+ postTime);
std::lock_guard<std::mutex> lock(mMutex);
if (!mTimeStatsTracker.count(layerID) && layerNameIsValid(layerName)) {
mTimeStatsTracker[layerID].layerName = layerName;
}
-}
-
-void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime) {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
- ALOGV("[%d]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerID, frameNumber, postTime);
-
- std::lock_guard<std::mutex> lock(mMutex);
if (!mTimeStatsTracker.count(layerID)) return;
LayerRecord& layerRecord = mTimeStatsTracker[layerID];
if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
@@ -451,6 +456,8 @@
}
void TimeStats::flushPowerTimeLocked() {
+ if (!mEnabled.load()) return;
+
nsecs_t curTime = systemTime();
// elapsedTime is in milliseconds.
int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
@@ -500,10 +507,14 @@
ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
mGlobalRecord.presentFences.front()->getSignalTime());
- const int32_t presentToPresentMs = msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
- ALOGV("Global present2present[%d]", presentToPresentMs);
+ if (mGlobalRecord.prevPresentTime != 0) {
+ const int32_t presentToPresentMs =
+ msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
+ ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
+ presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
+ mTimeStats.presentToPresent.insert(presentToPresentMs);
+ }
- mTimeStats.presentToPresent.insert(presentToPresentMs);
mGlobalRecord.prevPresentTime = curPresentTime;
mGlobalRecord.presentFences.pop_front();
}
@@ -514,7 +525,15 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (presentFence == nullptr) {
+ if (presentFence == nullptr || !presentFence->isValid()) {
+ mGlobalRecord.prevPresentTime = 0;
+ return;
+ }
+
+ if (mPowerTime.powerMode != HWC_POWER_MODE_NORMAL) {
+ // Try flushing the last present fence on HWC_POWER_MODE_NORMAL.
+ flushAvailableGlobalRecordsToStatsLocked();
+ mGlobalRecord.presentFences.clear();
mGlobalRecord.prevPresentTime = 0;
return;
}
@@ -537,10 +556,10 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Enabled");
mEnabled.store(true);
mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
+ ALOGD("Enabled");
}
void TimeStats::disable() {
@@ -549,16 +568,17 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Disabled");
+ flushPowerTimeLocked();
mEnabled.store(false);
mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ ALOGD("Disabled");
}
void TimeStats::clear() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Cleared");
+ mTimeStatsTracker.clear();
mTimeStats.stats.clear();
mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
mTimeStats.statsEnd = 0;
@@ -568,6 +588,9 @@
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
mPowerTime.prevTime = systemTime();
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.clear();
+ ALOGD("Cleared");
}
bool TimeStats::isEnabled() {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index d1e554c..184bf40 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -86,8 +86,8 @@
void incrementMissedFrames();
void incrementClientCompositionFrames();
- void setLayerName(int32_t layerID, const std::string& layerName);
- void setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime);
+ void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+ nsecs_t postTime);
void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index c701224..599ff5c 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -39,7 +39,7 @@
if (delta < 0) return;
// std::lower_bound won't work on out of range values
if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
- hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
+ hist[histogramConfig[HISTOGRAM_SIZE - 1]] += delta / histogramConfig[HISTOGRAM_SIZE - 1];
return;
}
auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
new file mode 100644
index 0000000..9b9dc57
--- /dev/null
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "TransactionCompletedThread"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "TransactionCompletedThread.h"
+
+#include <cinttypes>
+
+#include <binder/IInterface.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+TransactionCompletedThread::~TransactionCompletedThread() {
+ {
+ std::lock_guard lock(mMutex);
+ mKeepRunning = false;
+ mConditionVariable.notify_all();
+ }
+
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+
+ {
+ std::lock_guard lock(mMutex);
+ for (const auto& [listener, listenerStats] : mListenerStats) {
+ listener->unlinkToDeath(mDeathRecipient);
+ }
+ }
+}
+
+void TransactionCompletedThread::run() {
+ std::lock_guard lock(mMutex);
+ if (mRunning) {
+ return;
+ }
+ mDeathRecipient = new ThreadDeathRecipient();
+ mRunning = true;
+ mThread = std::thread(&TransactionCompletedThread::threadMain, this);
+}
+
+void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
+ const sp<CallbackHandle>& handle) {
+ std::lock_guard lock(mMutex);
+
+ sp<IBinder> listener = IInterface::asBinder(handle->listener);
+ const auto& callbackIds = handle->callbackIds;
+
+ mPendingTransactions[listener][callbackIds]++;
+}
+
+void TransactionCompletedThread::addLatchedCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
+ const sp<Fence>& previousReleaseFence) {
+ std::lock_guard lock(mMutex);
+
+ // If the previous release fences have not signaled, something as probably gone wrong.
+ // Store the fences and check them again before sending a callback.
+ if (previousReleaseFence &&
+ previousReleaseFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+ ALOGD("release fence from the previous frame has not signaled");
+ mPreviousReleaseFences.push_back(previousReleaseFence);
+ }
+
+ for (const auto& handle : handles) {
+ auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
+ auto& pendingCallbacks = listener->second;
+ auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
+
+ if (pendingCallback != pendingCallbacks.end()) {
+ auto& pendingCount = pendingCallback->second;
+
+ // Decrease the pending count for this listener
+ if (--pendingCount == 0) {
+ pendingCallbacks.erase(pendingCallback);
+ }
+ } else {
+ ALOGE("there are more latched callbacks than there were registered callbacks");
+ }
+
+ addCallbackHandle(handle, latchTime);
+ }
+}
+
+void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+ std::lock_guard lock(mMutex);
+ addCallbackHandle(handle);
+}
+
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
+ nsecs_t latchTime) {
+ const sp<IBinder> listener = IInterface::asBinder(handle->listener);
+
+ // If we don't already have a reference to this listener, linkToDeath so we get a notification
+ // if it dies.
+ if (mListenerStats.count(listener) == 0) {
+ status_t error = listener->linkToDeath(mDeathRecipient);
+ if (error != NO_ERROR) {
+ ALOGE("cannot add callback handle because linkToDeath failed, err: %d", error);
+ return;
+ }
+ }
+
+ auto& listenerStats = mListenerStats[listener];
+ listenerStats.listener = handle->listener;
+
+ auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
+ transactionStats.latchTime = latchTime;
+ transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
+ handle->releasePreviousBuffer);
+}
+
+void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mPresentFence = presentFence;
+}
+
+void TransactionCompletedThread::sendCallbacks() {
+ std::lock_guard lock(mMutex);
+ if (mRunning) {
+ mConditionVariable.notify_all();
+ }
+}
+
+void TransactionCompletedThread::threadMain() {
+ std::lock_guard lock(mMutex);
+
+ while (mKeepRunning) {
+ mConditionVariable.wait(mMutex);
+
+ // Present fence should fire almost immediately. If the fence has not signaled in 100ms,
+ // there is a major problem and it will probably never fire.
+ nsecs_t presentTime = -1;
+ if (mPresentFence) {
+ status_t status = mPresentFence->wait(100);
+ if (status == NO_ERROR) {
+ presentTime = mPresentFence->getSignalTime();
+ } else {
+ ALOGE("present fence has not signaled, err %d", status);
+ }
+ }
+
+ // We should never hit this case. The release fences from the previous frame should have
+ // signaled long before the current frame is presented.
+ for (const auto& fence : mPreviousReleaseFences) {
+ status_t status = fence->wait(100);
+ if (status != NO_ERROR) {
+ ALOGE("previous release fence has not signaled, err %d", status);
+ }
+ }
+
+ // For each listener
+ auto it = mListenerStats.begin();
+ while (it != mListenerStats.end()) {
+ auto& [listener, listenerStats] = *it;
+
+ // For each transaction
+ bool sendCallback = true;
+ for (auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+ // If we are still waiting on the callback handles for this transaction, skip it
+ if (mPendingTransactions[listener].count(callbackIds) != 0) {
+ sendCallback = false;
+ break;
+ }
+
+ // If the transaction has been latched
+ if (transactionStats.latchTime >= 0) {
+ // If the present time is < 0, this transaction has been latched but not
+ // presented. Skip it for now. This can happen when a new transaction comes
+ // in between the latch and present steps. sendCallbacks is called by
+ // SurfaceFlinger when the transaction is received to ensure that if the
+ // transaction that didn't update state it still got a callback.
+ if (presentTime < 0) {
+ sendCallback = false;
+ break;
+ }
+
+ transactionStats.presentTime = presentTime;
+ }
+ }
+ // If the listener has no pending transactions and all latched transactions have been
+ // presented
+ if (sendCallback) {
+ // If the listener is still alive
+ if (listener->isBinderAlive()) {
+ // Send callback
+ listenerStats.listener->onTransactionCompleted(listenerStats);
+ listener->unlinkToDeath(mDeathRecipient);
+ }
+ it = mListenerStats.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ if (mPresentFence) {
+ mPresentFence.clear();
+ mPreviousReleaseFences.clear();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+CallbackHandle::CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+ const std::vector<CallbackId>& ids, const sp<IBinder>& sc)
+ : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
+
+} // namespace android
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
new file mode 100644
index 0000000..5af4097
--- /dev/null
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+
+#include <binder/IBinder.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <ui/Fence.h>
+
+namespace android {
+
+class CallbackHandle : public RefBase {
+public:
+ CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+ const std::vector<CallbackId>& ids, const sp<IBinder>& sc);
+
+ sp<ITransactionCompletedListener> listener;
+ std::vector<CallbackId> callbackIds;
+ sp<IBinder> surfaceControl;
+
+ bool releasePreviousBuffer = false;
+ nsecs_t acquireTime = -1;
+};
+
+class TransactionCompletedThread {
+public:
+ ~TransactionCompletedThread();
+
+ void run();
+
+ // Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle
+ // that needs to be latched and presented this frame. This function should be called once the
+ // layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
+ // a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
+ // presented.
+ void registerPendingLatchedCallbackHandle(const sp<CallbackHandle>& handle);
+ // Notifies the TransactionCompletedThread that a pending CallbackHandle has been latched.
+ void addLatchedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
+ const sp<Fence>& previousReleaseFence);
+
+ // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
+ // presented this frame.
+ void addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle);
+
+ void addPresentFence(const sp<Fence>& presentFence);
+
+ void sendCallbacks();
+
+private:
+ void threadMain();
+
+ void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
+ REQUIRES(mMutex);
+
+ class ThreadDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ // This function is a no-op. isBinderAlive needs a linked DeathRecipient to work.
+ // Death recipients needs a binderDied function.
+ //
+ // (isBinderAlive checks if BpBinder's mAlive is 0. mAlive is only set to 0 in sendObituary.
+ // sendObituary is only called if linkToDeath was called with a DeathRecipient.)
+ void binderDied(const wp<IBinder>& /*who*/) override {}
+ };
+ sp<ThreadDeathRecipient> mDeathRecipient;
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+ };
+
+ std::thread mThread;
+
+ std::mutex mMutex;
+ std::condition_variable_any mConditionVariable;
+
+ std::unordered_map<
+ sp<IBinder /*listener*/>,
+ std::unordered_map<std::vector<CallbackId>, uint32_t /*count*/, CallbackIdsHash>,
+ IBinderHash>
+ mPendingTransactions GUARDED_BY(mMutex);
+ std::unordered_map<sp<IBinder /*listener*/>, ListenerStats, IBinderHash> mListenerStats
+ GUARDED_BY(mMutex);
+
+ bool mRunning GUARDED_BY(mMutex) = false;
+ bool mKeepRunning GUARDED_BY(mMutex) = true;
+
+ sp<Fence> mPresentFence GUARDED_BY(mMutex);
+ std::vector<sp<Fence>> mPreviousReleaseFences GUARDED_BY(mMutex);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 9c2edca..92ae87b 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -28,7 +28,6 @@
#include <cutils/sched_policy.h>
#include <displayservice/DisplayService.h>
#include <hidl/LegacySupport.h>
-#include "GpuService.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
@@ -104,10 +103,6 @@
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
- // publish GpuService
- sp<GpuService> gpuservice = new GpuService();
- sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
-
startDisplayService(); // dependency on SF getting registered above
struct sched_param param = {0};
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 9e762f0..a73ec6c 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -267,8 +267,9 @@
sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
std::function<status_t()> condition = [=]() {
sp<GraphicBuffer> outBuffer;
- return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, false,
- ROTATION, &outBuffer);
+ return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/,
+ 0 /*reqHeight*/, false, ROTATION, &outBuffer);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
@@ -278,8 +279,9 @@
sp<GraphicBuffer> outBuffer;
std::function<status_t()> condition = [=]() {
sp<GraphicBuffer> outBuffer;
- return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), Rect(), FRAME_SCALE,
- &outBuffer);
+ return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(),
+ ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+ Rect(), FRAME_SCALE, &outBuffer);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index aed1f78..988454a 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -15,9 +15,12 @@
*/
#include <algorithm>
+#include <chrono>
+#include <cinttypes>
#include <functional>
#include <limits>
#include <ostream>
+#include <thread>
#include <gtest/gtest.h>
@@ -30,6 +33,7 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <ui/ColorSpace.h>
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <utils/String8.h>
@@ -63,6 +67,7 @@
const Color Color::TRANSPARENT{0, 0, 0, 0};
using android::hardware::graphics::common::V1_1::BufferUsage;
+using namespace std::chrono_literals;
std::ostream& operator<<(std::ostream& os, const Color& color) {
os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
@@ -314,6 +319,10 @@
ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<IBinder> binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
}
virtual void TearDown() {
@@ -322,10 +331,11 @@
mClient = 0;
}
- virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
+ const char* name, uint32_t width, uint32_t height,
uint32_t flags = 0) {
auto layer =
- mClient->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
+ client->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
Transaction t;
@@ -344,6 +354,11 @@
return layer;
}
+ virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0) {
+ return createLayer(mClient, name, width, height, flags);
+ }
+
ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
// wait for previous transactions (such as setSize) to complete
Transaction().apply(true);
@@ -474,6 +489,8 @@
void setMatrixWithResizeHelper(uint32_t layerType);
sp<SurfaceControl> mBlackBgSurface;
+ bool mColorManagementUsed;
+
private:
void SetUpDisplay() {
mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
@@ -1951,7 +1968,7 @@
"test");
fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
- sp<Fence> fence = new Fence(-1);
+ sp<Fence> fence = Fence::NO_FENCE;
Transaction()
.setBuffer(layer, buffer)
@@ -2069,6 +2086,47 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
+class ColorTransformHelper {
+public:
+ static void DegammaColorSingle(half& s) {
+ if (s <= 0.03928f)
+ s = s / 12.92f;
+ else
+ s = pow((s + 0.055f) / 1.055f, 2.4f);
+ }
+
+ static void DegammaColor(half3& color) {
+ DegammaColorSingle(color.r);
+ DegammaColorSingle(color.g);
+ DegammaColorSingle(color.b);
+ }
+
+ static void GammaColorSingle(half& s) {
+ if (s <= 0.0031308f) {
+ s = s * 12.92f;
+ } else {
+ s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
+ }
+ }
+
+ static void GammaColor(half3& color) {
+ GammaColorSingle(color.r);
+ GammaColorSingle(color.g);
+ GammaColorSingle(color.b);
+ }
+
+ static void applyMatrix(half3& color, const mat3& mat) {
+ half3 ret = half3(0);
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ ret[i] = ret[i] + color[j] * mat[j][i];
+ }
+ }
+ color = ret;
+ }
+};
+
TEST_F(LayerTransactionTest, SetColorTransformBasic) {
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(
@@ -2081,22 +2139,659 @@
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- const Color expected = {90, 90, 90, 255};
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
+ half3 expected = color;
mat3 matrix;
matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrix);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
Transaction().setColor(colorLayer, color)
.setColorTransform(colorLayer, matrix, vec3()).apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+ screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
+class ExpectedResult {
+public:
+ enum Transaction {
+ NOT_PRESENTED = 0,
+ PRESENTED,
+ };
+
+ enum Buffer {
+ NOT_ACQUIRED = 0,
+ ACQUIRED,
+ };
+
+ enum PreviousBuffer {
+ NOT_RELEASED = 0,
+ RELEASED,
+ };
+
+ void reset() {
+ mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ mExpectedSurfaceResults.clear();
+ }
+
+ void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
+ ExpectedResult::Buffer bufferResult = NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ mTransactionResult = transactionResult;
+ mExpectedSurfaceResults.emplace(std::piecewise_construct,
+ std::forward_as_tuple(layer->getHandle()),
+ std::forward_as_tuple(bufferResult, previousBufferResult));
+ }
+
+ void addSurfaces(ExpectedResult::Transaction transactionResult,
+ const std::vector<sp<SurfaceControl>>& layers,
+ ExpectedResult::Buffer bufferResult = NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ for (const auto& layer : layers) {
+ addSurface(transactionResult, layer, bufferResult, previousBufferResult);
+ }
+ }
+
+ void verifyTransactionStats(const TransactionStats& transactionStats) const {
+ const auto& [latchTime, presentTime, surfaceStats] = transactionStats;
+ if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
+ ASSERT_GE(latchTime, 0) << "bad latch time";
+ ASSERT_GE(presentTime, 0) << "bad present time";
+ } else {
+ ASSERT_EQ(presentTime, -1) << "transaction shouldn't have been presented";
+ ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
+ }
+
+ ASSERT_EQ(surfaceStats.size(), mExpectedSurfaceResults.size())
+ << "wrong number of surfaces";
+
+ for (const auto& stats : surfaceStats) {
+ const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
+ ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
+ << "unexpected surface control";
+ expectedSurfaceResult->second.verifySurfaceStats(stats, latchTime);
+ }
+ }
+
+private:
+ class ExpectedSurfaceResult {
+ public:
+ ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
+ ExpectedResult::PreviousBuffer previousBufferResult)
+ : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
+
+ void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
+ const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+
+ ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+ << "bad acquire time";
+ ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+ ASSERT_EQ(releasePreviousBuffer,
+ mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED)
+ << "bad previous buffer released";
+ }
+
+ private:
+ ExpectedResult::Buffer mBufferResult;
+ ExpectedResult::PreviousBuffer mPreviousBufferResult;
+ };
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+ };
+ ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ std::unordered_map<sp<IBinder>, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults;
+};
+
+class CallbackHelper {
+public:
+ static void function(void* callbackContext, const TransactionStats& transactionStats) {
+ if (!callbackContext) {
+ ALOGE("failed to get callback context");
+ }
+ CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
+ std::lock_guard lock(helper->mMutex);
+ helper->mTransactionStatsQueue.push(transactionStats);
+ helper->mConditionVariable.notify_all();
+ }
+
+ void getTransactionStats(TransactionStats* outStats) {
+ std::unique_lock lock(mMutex);
+
+ if (mTransactionStatsQueue.empty()) {
+ ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive callback";
+ }
+
+ *outStats = std::move(mTransactionStatsQueue.front());
+ mTransactionStatsQueue.pop();
+ }
+
+ void verifyFinalState() {
+ // Wait to see if there are extra callbacks
+ std::this_thread::sleep_for(500ms);
+
+ std::lock_guard lock(mMutex);
+ EXPECT_EQ(mTransactionStatsQueue.size(), 0) << "extra callbacks received";
+ mTransactionStatsQueue = {};
+ }
+
+ void* getContext() { return static_cast<void*>(this); }
+
+ std::mutex mMutex;
+ std::condition_variable mConditionVariable;
+ std::queue<TransactionStats> mTransactionStatsQueue;
+};
+
+class LayerCallbackTest : public LayerTransactionTest {
+protected:
+ virtual sp<SurfaceControl> createBufferStateLayer() {
+ return createLayer(mClient, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ }
+
+ virtual void fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
+ const sp<SurfaceControl>& layer = nullptr) {
+ if (layer) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(mWidth, mHeight, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY |
+ BufferUsage::GPU_TEXTURE,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, mWidth, mHeight), Color::RED);
+
+ sp<Fence> fence = new Fence(-1);
+
+ transaction.setBuffer(layer, buffer)
+ .setAcquireFence(layer, fence)
+ .setSize(layer, mWidth, mHeight);
+ }
+
+ transaction.addTransactionCompletedCallback(callbackHelper->function,
+ callbackHelper->getContext());
+ }
+
+ void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState = false) {
+ TransactionStats transactionStats;
+ ASSERT_NO_FATAL_FAILURE(helper.getTransactionStats(&transactionStats));
+ EXPECT_NO_FATAL_FAILURE(expectedResult.verifyTransactionStats(transactionStats));
+
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+
+ void waitForCallbacks(CallbackHelper& helper,
+ const std::vector<ExpectedResult>& expectedResults,
+ bool finalState = false) {
+ for (const auto& expectedResult : expectedResults) {
+ waitForCallback(helper, expectedResult);
+ }
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+
+ uint32_t mWidth = 32;
+ uint32_t mHeight = 32;
+};
+
+TEST_F(LayerCallbackTest, Basic) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBuffer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoStateChange) {
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, OffScreen) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.setPosition(layer, -100, -100).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameCallback) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback;
+ fillTransaction(transaction1, &callback, layer1);
+ fillTransaction(transaction2, &callback, layer2);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer);
+ fillTransaction(transaction2, &callback2, layer);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SingleBuffer) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ ExpectedResult expected;
+
+ if (i == 0) {
+ fillTransaction(transaction, &callback, layer);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ if (i == 0) {
+ fillTransaction(transaction, &callback, layer);
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expected;
+ expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
+ : ExpectedResult::Transaction::NOT_PRESENTED,
+ layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ fillTransaction(transaction1, &callback1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ fillTransaction(transaction1, &callback1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ std::vector<ExpectedResult> expectedResults(50);
+ ExpectedResult::PreviousBuffer previousBufferResult =
+ ExpectedResult::PreviousBuffer::NOT_RELEASED;
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED, previousBufferResult);
+ previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ std::vector<ExpectedResult> expectedResults(50);
+ bool first = true;
+ for (auto& expected : expectedResults) {
+ expected.reset();
+
+ if (first) {
+ fillTransaction(transaction, &callback, layer);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ first = false;
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.apply();
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ // Normal call to set up test
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expectedResult;
+ expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
+
+ // Test
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
+
+ fillTransaction(transaction, &callback);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
class LayerUpdateTest : public LayerTransactionTest {
protected:
virtual void SetUp() {
@@ -2557,6 +3252,37 @@
}
}
+TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
+ sp<SurfaceControl> mGrandChild =
+ mClient->createSurface(String8("Grand Child"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+ {
+ SCOPED_TRACE("Grandchild visible");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 111, 111, 111);
+ }
+
+ mChild->clear();
+
+ {
+ SCOPED_TRACE("After destroying child");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectFGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparent(mGrandChild, mFGSurfaceControl->getHandle());
+ });
+
+ {
+ SCOPED_TRACE("After reparenting grandchild");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 111, 111, 111);
+ }
+}
+
TEST_F(ChildLayerTest, DetachChildrenSameClient) {
asTransaction([&](Transaction& t) {
t.show(mChild);
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index f71f1ea..d24c0de 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -37,6 +37,7 @@
#include "mock/MockEventThread.h"
#include "mock/MockMessageQueue.h"
#include "mock/RenderEngine/MockRenderEngine.h"
+#include "mock/system/window/MockNativeWindow.h"
namespace android {
namespace {
@@ -45,6 +46,7 @@
using testing::AtLeast;
using testing::ByMove;
using testing::DoAll;
+using testing::Invoke;
using testing::IsNull;
using testing::Mock;
using testing::NotNull;
@@ -65,6 +67,7 @@
constexpr hwc2_layer_t HWC_LAYER = 5000;
constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
+constexpr DisplayId DEFAULT_DISPLAY_ID = 42;
constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
@@ -91,6 +94,10 @@
EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
EXPECT_CALL(*mPrimaryDispSync, getPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
setupComposer(0);
@@ -137,7 +144,10 @@
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
- renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
+ mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+
+ sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+ ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
mock::EventThread* mEventThread = new mock::EventThread();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
@@ -190,7 +200,8 @@
constexpr bool forSystem = true;
DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
- DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0);
+ DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB,
+ ui::Transform::ROT_0);
auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
return mFlinger.traverseLayersInDisplay(mDisplay, visitor);
@@ -225,16 +236,20 @@
static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
static void setupPreconditions(CompositionTest* test) {
- FakeHwcDisplayInjector(DisplayDevice::DISPLAY_PRIMARY, HWC2::DisplayType::Physical)
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
+ true /* isPrimary */)
.setCapabilities(&test->mDefaultCapabilities)
.inject(&test->mFlinger, test->mComposer);
- test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DisplayDevice::DISPLAY_PRIMARY,
- DisplayDevice::DISPLAY_PRIMARY)
- .setDisplaySize(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
+ test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
+ false /* isVirtual */, true /* isPrimary */)
.setDisplaySurface(test->mDisplaySurface)
- .setRenderSurface(std::unique_ptr<renderengine::Surface>(
- test->mRenderSurface))
+ .setNativeWindow(test->mNativeWindow)
.setSecure(Derived::IS_SECURE)
.setPowerMode(Derived::INIT_POWER_MODE)
.inject();
@@ -256,13 +271,9 @@
EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
- EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
- .WillOnce(Return(true));
- EXPECT_CALL(*test->mRenderEngine,
- setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
- Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::Transform::ROT_0))
- .Times(1);
+ EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
+ return base::unique_fd(0);
+ }));
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
@@ -288,7 +299,7 @@
EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
- EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(_)).Times(1);
EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
.Times(1);
// This expectation retires on saturation as setViewportAndProjection is
@@ -313,8 +324,6 @@
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
-
- EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
}
static void setupRECompositionCallExpectations(CompositionTest* test) {
@@ -334,12 +343,18 @@
setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
ui::Transform::ROT_0))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
- .WillOnce(Return(true))
- .RetiresOnSaturation();
- EXPECT_CALL(*test->mRenderSurface, swapBuffers()).Times(1);
+ .Times(1);
+ EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
+ EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+ EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
+ .WillOnce(Return(
+ ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
+ EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
+ EXPECT_CALL(*test->mNativeWindow, queueBuffer(_, _)).WillOnce(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, dequeueBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
+ Return(0)));
}
template <typename Case>
@@ -552,10 +567,6 @@
IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
.Times(1);
- // TODO: ColorLayer::onPreComposition() always returns true, triggering an
- // extra layer update in SurfaceFlinger::preComposition(). This seems
- // wrong on the surface.
- EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
}
static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
@@ -748,7 +759,9 @@
EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
.WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
- layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), test->mDisplay->getId());
+ const auto displayId = test->mDisplay->getId();
+ ASSERT_TRUE(displayId);
+ layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), *displayId);
Mock::VerifyAndClear(test->mComposer);
@@ -761,8 +774,10 @@
static void cleanupInjectedLayers(CompositionTest* test) {
EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
.WillOnce(Return(Error::NONE));
+ const auto displayId = test->mDisplay->getId();
+ ASSERT_TRUE(displayId);
for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
- layer->destroyHwcLayer(test->mDisplay->getId());
+ layer->destroyHwcLayer(*displayId);
}
test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
}
@@ -953,7 +968,7 @@
struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
static void setupLayerState(CompositionTest*, sp<Layer> layer) {
- layer->forceClientComposition(DisplayDevice::DISPLAY_PRIMARY);
+ layer->forceClientComposition(DEFAULT_DISPLAY_ID);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 4f1c99e..55995d0 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -68,32 +68,44 @@
} // namespace
+const DisplayIdentificationData& getInternalEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kInternalEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getExternalEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kExternalEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getExternalEedid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kExternalEedid);
+ return data;
+}
+
TEST(DisplayIdentificationTest, isEdid) {
EXPECT_FALSE(isEdid({}));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kInternalEdid)));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEdid)));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEedid)));
+ EXPECT_TRUE(isEdid(getInternalEdid()));
+ EXPECT_TRUE(isEdid(getExternalEdid()));
+ EXPECT_TRUE(isEdid(getExternalEedid()));
}
TEST(DisplayIdentificationTest, parseEdid) {
- auto data = asDisplayIdentificationData(kInternalEdid);
- auto edid = parseEdid(data);
+ auto edid = parseEdid(getInternalEdid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x4ca3u, edid->manufacturerId);
EXPECT_STREQ("SEC", edid->pnpId.data());
// ASCII text should be used as fallback if display name and serial number are missing.
EXPECT_EQ("121AT11-801", edid->displayName);
- data = asDisplayIdentificationData(kExternalEdid);
- edid = parseEdid(data);
+ edid = parseEdid(getExternalEdid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x22f0u, edid->manufacturerId);
EXPECT_STREQ("HWP", edid->pnpId.data());
EXPECT_EQ("HP ZR30w", edid->displayName);
- data = asDisplayIdentificationData(kExternalEedid);
- edid = parseEdid(data);
+ edid = parseEdid(getExternalEedid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x4c2du, edid->manufacturerId);
EXPECT_STREQ("SAM", edid->pnpId.data());
@@ -105,7 +117,7 @@
EXPECT_FALSE(parseEdid({}));
// Display name must be printable.
- auto data = asDisplayIdentificationData(kExternalEdid);
+ auto data = getExternalEdid();
data[97] = '\x1b';
auto edid = parseEdid(data);
ASSERT_TRUE(edid);
@@ -128,20 +140,32 @@
EXPECT_STREQ("SAM", getPnpId(0x4c2du).value_or(PnpId{}).data());
}
-TEST(DisplayIdentificationTest, generateDisplayId) {
- const auto primaryId = generateDisplayId(0, asDisplayIdentificationData(kInternalEdid));
- ASSERT_TRUE(primaryId);
+TEST(DisplayIdentificationTest, parseDisplayIdentificationData) {
+ const auto primaryInfo = parseDisplayIdentificationData(0, getInternalEdid());
+ ASSERT_TRUE(primaryInfo);
- const auto secondaryId = generateDisplayId(1, asDisplayIdentificationData(kExternalEdid));
- ASSERT_TRUE(secondaryId);
+ const auto secondaryInfo = parseDisplayIdentificationData(1, getExternalEdid());
+ ASSERT_TRUE(secondaryInfo);
- const auto tertiaryId = generateDisplayId(2, asDisplayIdentificationData(kExternalEedid));
- ASSERT_TRUE(tertiaryId);
+ const auto tertiaryInfo = parseDisplayIdentificationData(2, getExternalEedid());
+ ASSERT_TRUE(tertiaryInfo);
// Display IDs should be unique.
- EXPECT_NE(primaryId, secondaryId);
- EXPECT_NE(primaryId, tertiaryId);
- EXPECT_NE(secondaryId, tertiaryId);
+ EXPECT_NE(primaryInfo->id, secondaryInfo->id);
+ EXPECT_NE(primaryInfo->id, tertiaryInfo->id);
+ EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
+}
+
+TEST(DisplayIdentificationTest, getFallbackDisplayId) {
+ // Manufacturer ID should be invalid.
+ ASSERT_FALSE(getPnpId(getFallbackDisplayId(0)));
+ ASSERT_FALSE(getPnpId(getFallbackDisplayId(0xffu)));
+}
+
+TEST(DisplayIdentificationTest, getVirtualDisplayId) {
+ // Manufacturer ID should be invalid.
+ ASSERT_FALSE(getPnpId(getVirtualDisplayId(0)));
+ ASSERT_FALSE(getPnpId(getVirtualDisplayId(0xffff'ffffu)));
}
} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
similarity index 69%
copy from services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
copy to services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
index 6595466..1c8e5cc 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
@@ -16,19 +16,12 @@
#pragma once
-#include <cstdint>
-
-struct ANativeWindowBuffer;
+#include "DisplayHardware/DisplayIdentification.h"
namespace android {
-namespace renderengine {
-class Framebuffer {
-public:
- virtual ~Framebuffer() = default;
+const DisplayIdentificationData& getInternalEdid();
+const DisplayIdentificationData& getExternalEdid();
+const DisplayIdentificationData& getExternalEedid();
- virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) = 0;
-};
-
-} // namespace renderengine
-} // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index d32627a..aa1fc1a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -17,12 +17,16 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <type_traits>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <ui/DebugUtils.h>
+
+#include "DisplayIdentificationTest.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplaySurface.h"
@@ -75,9 +79,11 @@
#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
-BOOL_SUBSTITUTE(Critical);
BOOL_SUBSTITUTE(Async);
+BOOL_SUBSTITUTE(Critical);
+BOOL_SUBSTITUTE(Primary);
BOOL_SUBSTITUTE(Secure);
+BOOL_SUBSTITUTE(Virtual);
/* ------------------------------------------------------------------------
*
@@ -98,7 +104,7 @@
// --------------------------------------------------------------------
// Postcondition helpers
- bool hasHwcDisplay(hwc2_display_t displayId);
+ bool hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId);
bool hasTransactionFlagSet(int flag);
bool hasDisplayDevice(sp<IBinder> displayToken);
sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
@@ -113,6 +119,8 @@
TestableSurfaceFlinger mFlinger;
mock::EventThread* mEventThread = new mock::EventThread();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+ sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
+ sp<GraphicBuffer> mBuffer = new GraphicBuffer();
// These mocks are created by the test, but are destroyed by SurfaceFlinger
// by virtue of being stored into a std::unique_ptr. However we still need
@@ -127,8 +135,6 @@
sp<mock::GraphicBufferConsumer> mConsumer;
sp<mock::GraphicBufferProducer> mProducer;
surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
- sp<mock::NativeWindow> mNativeWindow;
- renderengine::mock::Surface* mRenderSurface = nullptr;
};
DisplayTransactionTest::DisplayTransactionTest() {
@@ -197,15 +203,14 @@
ASSERT_TRUE(mNativeWindowSurface == nullptr);
mNativeWindowSurface = new surfaceflinger::mock::NativeWindowSurface();
- mNativeWindow = new mock::NativeWindow();
mFlinger.setCreateNativeWindowSurface([this](auto) {
return std::unique_ptr<surfaceflinger::NativeWindowSurface>(mNativeWindowSurface);
});
}
-bool DisplayTransactionTest::hasHwcDisplay(hwc2_display_t displayId) {
- return mFlinger.mutableHwcDisplaySlots().count(displayId) == 1;
+bool DisplayTransactionTest::hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId) {
+ return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
}
bool DisplayTransactionTest::hasTransactionFlagSet(int flag) {
@@ -240,20 +245,67 @@
*
*/
-template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType displayId, int width,
- int height, Critical critical, Async async, Secure secure, int grallocUsage>
+template <typename PhysicalDisplay>
+struct PhysicalDisplayId {};
+
+template <DisplayId displayId>
+using VirtualDisplayId = std::integral_constant<DisplayId, displayId>;
+
+struct NoDisplayId {};
+
+template <typename>
+struct IsPhysicalDisplayId : std::bool_constant<false> {};
+
+template <typename PhysicalDisplay>
+struct IsPhysicalDisplayId<PhysicalDisplayId<PhysicalDisplay>> : std::bool_constant<true> {};
+
+template <typename>
+struct DisplayIdGetter;
+
+template <typename PhysicalDisplay>
+struct DisplayIdGetter<PhysicalDisplayId<PhysicalDisplay>> {
+ static std::optional<DisplayId> get() {
+ if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+ return getFallbackDisplayId(static_cast<bool>(PhysicalDisplay::PRIMARY)
+ ? HWC_DISPLAY_PRIMARY
+ : HWC_DISPLAY_EXTERNAL);
+ }
+
+ const auto info =
+ parseDisplayIdentificationData(PhysicalDisplay::PORT,
+ PhysicalDisplay::GET_IDENTIFICATION_DATA());
+ return info ? std::make_optional(info->id) : std::nullopt;
+ }
+};
+
+template <DisplayId displayId>
+struct DisplayIdGetter<VirtualDisplayId<displayId>> {
+ static std::optional<DisplayId> get() { return displayId; }
+};
+
+template <>
+struct DisplayIdGetter<NoDisplayId> {
+ static std::optional<DisplayId> get() { return {}; }
+};
+
+// DisplayIdType can be:
+// 1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
+// 2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
+// 3) NoDisplayId for virtual display without HWC backing.
+template <typename DisplayIdType, int width, int height, Critical critical, Async async,
+ Secure secure, Primary primary, int grallocUsage>
struct DisplayVariant {
+ using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+
// The display width and height
static constexpr int WIDTH = width;
static constexpr int HEIGHT = height;
static constexpr int GRALLOC_USAGE = grallocUsage;
- // The type for this display
- static constexpr DisplayDevice::DisplayType TYPE = type;
- static_assert(TYPE != DisplayDevice::DISPLAY_ID_INVALID);
-
- static constexpr DisplayDevice::DisplayType DISPLAY_ID = displayId;
+ // Whether the display is virtual or physical
+ static constexpr Virtual VIRTUAL =
+ IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
// When creating native window surfaces for the framebuffer, whether those should be critical
static constexpr Critical CRITICAL = critical;
@@ -264,9 +316,23 @@
// Whether the display should be treated as secure
static constexpr Secure SECURE = secure;
+ // Whether the display is primary
+ static constexpr Primary PRIMARY = primary;
+
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
- auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, DISPLAY_ID);
+ auto injector =
+ FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
+ static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+
injector.setSecure(static_cast<bool>(SECURE));
+ injector.setNativeWindow(test->mNativeWindow);
+
+ // Creating a DisplayDevice requires getting default dimensions from the
+ // native window.
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
return injector;
}
@@ -274,20 +340,11 @@
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
.WillOnce(Return(test->mNativeWindow));
- EXPECT_CALL(*test->mNativeWindow, perform(19)).WillRepeatedly(Return(NO_ERROR));
- // For simplicity, we only expect to create a single render surface for
- // each test.
- ASSERT_TRUE(test->mRenderSurface == nullptr);
- test->mRenderSurface = new renderengine::mock::Surface();
- EXPECT_CALL(*test->mRenderEngine, createSurface())
- .WillOnce(Return(ByMove(
- std::unique_ptr<renderengine::Surface>(test->mRenderSurface))));
- EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast<bool>(ASYNC))).Times(1);
- EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast<bool>(CRITICAL))).Times(1);
- EXPECT_CALL(*test->mRenderSurface, setNativeWindow(test->mNativeWindow.get())).Times(1);
- EXPECT_CALL(*test->mRenderSurface, getWidth()).WillOnce(Return(WIDTH));
- EXPECT_CALL(*test->mRenderSurface, getHeight()).WillOnce(Return(HEIGHT));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
}
static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
@@ -306,7 +363,8 @@
}
};
-template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant>
+template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant,
+ typename PhysicalDisplay = void>
struct HwcDisplayVariant {
// The display id supplied by the HWC
static constexpr hwc2_display_t HWC_DISPLAY_ID = hwcDisplayId;
@@ -325,7 +383,10 @@
// Called by tests to inject a HWC display setup
static void injectHwcDisplay(DisplayTransactionTest* test) {
- FakeHwcDisplayInjector(DisplayVariant::TYPE, HWC_DISPLAY_TYPE)
+ const auto displayId = DisplayVariant::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ FakeHwcDisplayInjector(*displayId, HWC_DISPLAY_TYPE,
+ static_cast<bool>(DisplayVariant::PRIMARY))
.setHwcDisplayId(HWC_DISPLAY_ID)
.setWidth(DisplayVariant::WIDTH)
.setHeight(DisplayVariant::HEIGHT)
@@ -362,8 +423,16 @@
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_Y, _))
.WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
- .WillRepeatedly(Return(Error::UNSUPPORTED));
+
+ if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
+ SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
+ Return(Error::NONE)));
+ } else {
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillOnce(Return(Error::UNSUPPORTED));
+ }
}
// Called by tests to set up HWC call expectations
@@ -373,50 +442,67 @@
}
};
-struct NonHwcDisplayVariant {
- static void injectHwcDisplay(DisplayTransactionTest*) {}
-
- static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
- }
-};
-
// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
-template <hwc2_display_t hwcDisplayId, DisplayDevice::DisplayType type, int width, int height,
+template <hwc2_display_t hwcDisplayId, typename PhysicalDisplay, int width, int height,
Critical critical>
struct PhysicalDisplayVariant
- : public DisplayVariant<type, type, width, height, critical, Async::FALSE, Secure::TRUE,
- GRALLOC_USAGE_PHYSICAL_DISPLAY>,
- public HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
- DisplayVariant<type, type, width, height, critical, Async::FALSE,
- Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {};
+ : DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height, critical, Async::FALSE,
+ Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+ HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
+ DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height,
+ critical, Async::FALSE, Secure::TRUE,
+ PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+ PhysicalDisplay> {};
+
+template <bool hasIdentificationData>
+struct PrimaryDisplay {
+ static constexpr Primary PRIMARY = Primary::TRUE;
+ static constexpr uint8_t PORT = 255;
+ static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+ static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
+};
+
+template <bool hasIdentificationData>
+struct ExternalDisplay {
+ static constexpr Primary PRIMARY = Primary::FALSE;
+ static constexpr uint8_t PORT = 254;
+ static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+ static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
+};
+
+struct TertiaryDisplay {
+ static constexpr Primary PRIMARY = Primary::FALSE;
+};
// A primary display is a physical display that is critical
using PrimaryDisplayVariant =
- PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>;
+ PhysicalDisplayVariant<1001, PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
// An external display is physical display that is not critical.
using ExternalDisplayVariant =
- PhysicalDisplayVariant<1002, DisplayDevice::DISPLAY_EXTERNAL, 1920, 1280, Critical::FALSE>;
+ PhysicalDisplayVariant<1002, ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
using TertiaryDisplayVariant =
- PhysicalDisplayVariant<1003, DisplayDevice::DISPLAY_EXTERNAL, 1600, 1200, Critical::FALSE>;
+ PhysicalDisplayVariant<1003, TertiaryDisplay, 1600, 1200, Critical::FALSE>;
// A virtual display not supported by the HWC.
constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
template <int width, int height, Secure secure>
struct NonHwcVirtualDisplayVariant
- : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
- width, height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>,
- public NonHwcDisplayVariant {
- using Base = DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
- width, height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+ : DisplayVariant<NoDisplayId, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
+ using Base = DisplayVariant<NoDisplayId, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+
+ static void injectHwcDisplay(DisplayTransactionTest*) {}
+
+ static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
+ }
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
Base::setupNativeWindowSurfaceCreationCallExpectations(test);
@@ -429,14 +515,14 @@
template <int width, int height, Secure secure>
struct HwcVirtualDisplayVariant
- : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
- height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
- public HwcDisplayVariant<1010, HWC2::DisplayType::Virtual,
- NonHwcVirtualDisplayVariant<width, height, secure>> {
- using Base =
- DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
- height, Critical::FALSE, Async::TRUE, secure, GRALLOC_USAGE_HW_COMPOSER>;
+ : DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
+ HwcDisplayVariant<
+ 1010, HWC2::DisplayType::Virtual,
+ DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
+ using Base = DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
using Self = HwcVirtualDisplayVariant<width, height, secure>;
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
@@ -850,8 +936,8 @@
// The display should have been added to the current state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& display = getCurrentDisplayState(displayToken);
- EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
- EXPECT_EQ(false, display.isSecure);
+ EXPECT_TRUE(display.isVirtual());
+ EXPECT_FALSE(display.isSecure);
EXPECT_EQ(name.string(), display.displayName);
// --------------------------------------------------------------------
@@ -881,8 +967,8 @@
// The display should have been added to the current state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& display = getCurrentDisplayState(displayToken);
- EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
- EXPECT_EQ(true, display.isSecure);
+ EXPECT_TRUE(display.isVirtual());
+ EXPECT_TRUE(display.isSecure);
EXPECT_EQ(name.string(), display.displayName);
// --------------------------------------------------------------------
@@ -969,9 +1055,6 @@
// The call disable vsyncs
EXPECT_CALL(*mEventControlThread, setVsyncEnabled(false)).Times(1);
- // The call clears the current render engine surface
- EXPECT_CALL(*mRenderEngine, resetCurrentSurface());
-
// The call ends any display resyncs
EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
@@ -1002,9 +1085,12 @@
*/
class GetBestColorModeTest : public DisplayTransactionTest {
public:
+ static constexpr DisplayId DEFAULT_DISPLAY_ID = 777;
+
GetBestColorModeTest()
: DisplayTransactionTest(),
- mInjector(FakeDisplayDeviceInjector(mFlinger, DisplayDevice::DISPLAY_PRIMARY, 0)) {}
+ mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
+ true /* isPrimary */)) {}
void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
@@ -1020,6 +1106,15 @@
void getBestColorMode() {
mInjector.setHwcColorModes(mHwcColorModes);
mInjector.setHasWideColorGamut(mHasWideColorGamut);
+ mInjector.setNativeWindow(mNativeWindow);
+
+ // Creating a DisplayDevice requires getting default dimensions from the
+ // native window.
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0)));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0)));
+ EXPECT_CALL(*mNativeWindow, perform(13)).Times(1);
auto displayDevice = mInjector.inject();
displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
@@ -1127,18 +1222,22 @@
// Invocation
DisplayDeviceState state;
- state.type = Case::Display::TYPE;
+ state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get();
state.isSecure = static_cast<bool>(Case::Display::SECURE);
- auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::TYPE, state,
- displaySurface, producer);
+ auto device =
+ mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::DISPLAY_ID::get(),
+ state, displaySurface, producer);
// --------------------------------------------------------------------
// Postconditions
ASSERT_TRUE(device != nullptr);
- EXPECT_EQ(Case::Display::TYPE, device->getDisplayType());
+ EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
@@ -1166,11 +1265,14 @@
}
TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
- // We need to resize this so that the HWC thinks the virtual display
- // is something it created.
- mFlinger.mutableHwcDisplayData().resize(3);
+ using Case = HwcVirtualDisplayCase;
- setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
+ // Insert display data so that the HWC thinks it created the virtual display.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
+
+ setupNewDisplayDeviceInternalTest<Case>();
}
TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
@@ -1258,7 +1360,7 @@
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
EXPECT_CALL(*mEventThread,
- onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+ onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
? EventThread::DisplayType::Primary
: EventThread::DisplayType::External,
true))
@@ -1269,7 +1371,7 @@
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
EXPECT_CALL(*mEventThread,
- onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+ onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
? EventThread::DisplayType::Primary
: EventThread::DisplayType::External,
false))
@@ -1282,30 +1384,35 @@
ASSERT_TRUE(hasDisplayDevice(displayToken));
const auto& device = getDisplayDevice(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
- EXPECT_EQ(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY, device->isPrimary());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
// The display should have been set up in the current display state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& current = getCurrentDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, current.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get(),
+ current.displayId);
// The display should have been set up in the drawing display state
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, draw.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get(),
+ draw.displayId);
}
template <typename Case>
void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
// HWComposer should have an entry for the display
- EXPECT_TRUE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should be set up as a built-in display.
- static_assert(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "Must use a valid physical display type index for the fixed-size array");
- auto& displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- ASSERT_TRUE(displayToken != nullptr);
+ // SF should have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1);
+ auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[*displayId];
verifyDisplayIsConnected<Case>(displayToken);
}
@@ -1371,7 +1478,7 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
}
template <typename Case>
@@ -1407,13 +1514,12 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should not be set up as a built-in display.
- ASSERT_TRUE(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
- auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- EXPECT_TRUE(displayToken == nullptr);
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0);
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
@@ -1500,13 +1606,12 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should not be set up as a primary built-in display.
- ASSERT_TRUE(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
- auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- EXPECT_TRUE(displayToken == nullptr);
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0);
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
@@ -1545,10 +1650,10 @@
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
- static_assert(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "Display type must be a built-in display");
- EXPECT_NE(existing.token(), mFlinger.mutableDisplayTokens()[Case::Display::TYPE]);
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1);
+ EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[*displayId]);
// A new display should be connected in its place
@@ -1578,13 +1683,12 @@
// surface(producer)
sp<BBinder> displayToken = new BBinder();
- DisplayDeviceState info;
- info.type = Case::Display::TYPE;
- info.isSecure = static_cast<bool>(Case::Display::SECURE);
+ DisplayDeviceState state;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
- info.surface = surface;
- mFlinger.mutableCurrentState().displays.add(displayToken, info);
+ state.surface = surface;
+ mFlinger.mutableCurrentState().displays.add(displayToken, state);
// --------------------------------------------------------------------
// Call Expectations
@@ -1604,7 +1708,6 @@
EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
- EXPECT_CALL(*mProducer, connect(_, _, _, _)).Times(1);
EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
@@ -1646,11 +1749,10 @@
// surface.
sp<BBinder> displayToken = new BBinder();
- DisplayDeviceState info;
- info.type = Case::Display::TYPE;
- info.isSecure = static_cast<bool>(Case::Display::SECURE);
+ DisplayDeviceState state;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
- mFlinger.mutableCurrentState().displays.add(displayToken, info);
+ mFlinger.mutableCurrentState().displays.add(displayToken, state);
// --------------------------------------------------------------------
// Call Expectations
@@ -1669,7 +1771,7 @@
// The drawing display state will be set from the current display state.
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, draw.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
@@ -1679,7 +1781,9 @@
// Preconditions
// A virtual display is set up but is removed from the current state.
- mFlinger.mutableHwcDisplayData().resize(3);
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
Case::Display::injectHwcDisplay(this);
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
existing.inject();
@@ -1827,11 +1931,16 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
- auto renderSurface = new renderengine::mock::Surface();
+ sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
- display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
+ // Setup injection expections
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+ EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
display.inject();
// There is a change to the viewport state
@@ -1843,11 +1952,7 @@
// --------------------------------------------------------------------
// Call Expectations
- EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
- EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
- EXPECT_CALL(*renderSurface, getWidth()).WillOnce(Return(newWidth));
- EXPECT_CALL(*renderSurface, getHeight()).WillOnce(Return(oldHeight));
// --------------------------------------------------------------------
// Invocation
@@ -1868,11 +1973,16 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
- auto renderSurface = new renderengine::mock::Surface();
+ sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
- display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
+ // Setup injection expections
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+ EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
display.inject();
// There is a change to the viewport state
@@ -1884,11 +1994,7 @@
// --------------------------------------------------------------------
// Call Expectations
- EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
- EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
- EXPECT_CALL(*renderSurface, getWidth()).WillOnce(Return(oldWidth));
- EXPECT_CALL(*renderSurface, getHeight()).WillOnce(Return(newHeight));
// --------------------------------------------------------------------
// Invocation
@@ -2799,9 +2905,10 @@
// --------------------------------------------------------------------
// Preconditions
- // We need to resize this so that the HWC thinks the virtual display
- // is something it created.
- mFlinger.mutableHwcDisplayData().resize(3);
+ // Insert display data so that the HWC thinks it created the virtual display.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
// A virtual display device is set up
Case::Display::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 07cabd3..85c835e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -16,21 +16,134 @@
#pragma once
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "ContainerLayer.h"
#include "DisplayDevice.h"
#include "Layer.h"
+#include "NativeWindowSurface.h"
+#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
+#include "SurfaceFlingerFactory.h"
+#include "SurfaceInterceptor.h"
namespace android {
class EventThread;
namespace renderengine {
+
class RenderEngine;
-}
+
+} // namespace renderengine
namespace Hwc2 {
+
class Composer;
-}
+
+} // namespace Hwc2
+
+namespace surfaceflinger::test {
+
+class Factory final : public surfaceflinger::Factory {
+public:
+ ~Factory() = default;
+
+ std::unique_ptr<DispSync> createDispSync(const char*, bool, int64_t) override {
+ // TODO: Use test-fixture controlled factory
+ return nullptr;
+ }
+
+ std::unique_ptr<EventControlThread> createEventControlThread(
+ std::function<void(bool)>) override {
+ // TODO: Use test-fixture controlled factory
+ return nullptr;
+ }
+
+ std::unique_ptr<HWComposer> createHWComposer(const std::string&) override {
+ // TODO: Use test-fixture controlled factory
+ return nullptr;
+ }
+
+ std::unique_ptr<MessageQueue> createMessageQueue() override {
+ // TODO: Use test-fixture controlled factory
+ return std::make_unique<android::impl::MessageQueue>();
+ }
+
+ std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>) override {
+ // TODO: Use test-fixture controlled factory
+ return nullptr;
+ }
+
+ std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
+ // TODO: Use test-fixture controlled factory
+ return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+ }
+
+ sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
+ // TODO: Use test-fixture controlled factory
+ return new StartPropertySetThread(timestampPropertyValue);
+ }
+
+ sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
+ // TODO: Use test-fixture controlled factory
+ return new DisplayDevice(std::move(creationArgs));
+ }
+
+ sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ std::string requestorName) override {
+ // TODO: Use test-fixture controlled factory
+ return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+ }
+
+ void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+ sp<IGraphicBufferConsumer>* outConsumer,
+ bool consumerIsSurfaceFlinger) override {
+ if (!mCreateBufferQueue) return;
+ mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+ }
+
+ std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+ const sp<IGraphicBufferProducer>& producer) override {
+ if (!mCreateNativeWindowSurface) return nullptr;
+ return mCreateNativeWindowSurface(producer);
+ }
+
+ sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
+ // TODO: Use test-fixture controlled factory
+ return nullptr;
+ }
+
+ sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override {
+ // TODO: Use test-fixture controlled factory
+ return nullptr;
+ }
+
+ sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
+ // TODO: Use test-fixture controlled factory
+ return nullptr;
+ }
+
+ sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
+ // TODO: Use test-fixture controlled factory
+ return nullptr;
+ }
+
+ using CreateBufferQueueFunction =
+ std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
+ sp<IGraphicBufferConsumer>* /* outConsumer */,
+ bool /* consumerIsSurfaceFlinger */)>;
+ CreateBufferQueueFunction mCreateBufferQueue;
+
+ using CreateNativeWindowSurfaceFunction =
+ std::function<std::unique_ptr<surfaceflinger::NativeWindowSurface>(
+ const sp<IGraphicBufferProducer>&)>;
+ CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
+};
+
+} // namespace surfaceflinger::test
class TestableSurfaceFlinger {
public:
@@ -45,14 +158,15 @@
mFlinger->getBE().mHwc.reset(new HWComposer(std::move(composer)));
}
- using CreateBufferQueueFunction = SurfaceFlinger::CreateBufferQueueFunction;
+ using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
- mFlinger->mCreateBufferQueue = f;
+ mFactory.mCreateBufferQueue = f;
}
- using CreateNativeWindowSurfaceFunction = SurfaceFlinger::CreateNativeWindowSurfaceFunction;
+ using CreateNativeWindowSurfaceFunction =
+ surfaceflinger::test::Factory::CreateNativeWindowSurfaceFunction;
void setCreateNativeWindowSurface(CreateNativeWindowSurfaceFunction f) {
- mFlinger->mCreateNativeWindowSurface = f;
+ mFactory.mCreateNativeWindowSurface = f;
}
using HotplugEvent = SurfaceFlinger::HotplugEvent;
@@ -65,10 +179,6 @@
layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
}
- void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
- layer->getBE().mHwcLayers[DisplayDevice::DISPLAY_PRIMARY].compositionType = type;
- };
-
void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
layer->mPotentialCursor = potentialCursor;
}
@@ -87,7 +197,8 @@
auto resetDisplayState() { return mFlinger->resetDisplayState(); }
- auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken, int32_t displayId,
+ auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
+ const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
@@ -150,7 +261,6 @@
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
auto& mutableDisplays() { return mFlinger->mDisplays; }
- auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
auto& mutableEventQueue() { return mFlinger->mEventQueue; }
@@ -160,6 +270,7 @@
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+ auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
@@ -167,8 +278,13 @@
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
- auto& mutableHwcDisplayData() { return mFlinger->getBE().mHwc->mDisplayData; }
- auto& mutableHwcDisplaySlots() { return mFlinger->getBE().mHwc->mHwcDisplaySlots; }
+ auto& mutableHwcDisplayData() { return mFlinger->getHwComposer().mDisplayData; }
+ auto& mutableHwcPhysicalDisplayIdMap() {
+ return mFlinger->getHwComposer().mPhysicalDisplayIdMap;
+ }
+
+ auto& mutableInternalHwcDisplayId() { return mFlinger->getHwComposer().mInternalHwcDisplayId; }
+ auto& mutableExternalHwcDisplayId() { return mFlinger->getHwComposer().mExternalHwcDisplayId; }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
@@ -220,8 +336,9 @@
static constexpr int32_t DEFAULT_DPI = 320;
static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
- FakeHwcDisplayInjector(DisplayDevice::DisplayType type, HWC2::DisplayType hwcDisplayType)
- : mType(type), mHwcDisplayType(hwcDisplayType) {}
+ FakeHwcDisplayInjector(DisplayId displayId, HWC2::DisplayType hwcDisplayType,
+ bool isPrimary)
+ : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {}
auto& setHwcDisplayId(hwc2_display_t displayId) {
mHwcDisplayId = displayId;
@@ -290,17 +407,22 @@
display->mutableConfigs().emplace(mActiveConfig, config.build());
display->mutableIsConnected() = true;
- ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType));
- flinger->mutableHwcDisplayData()[mType] = HWComposer::DisplayData();
- flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get();
- flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType);
+ flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = display.get();
+
+ if (mHwcDisplayType == HWC2::DisplayType::Physical) {
+ flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, mDisplayId);
+ (mIsPrimary ? flinger->mutableInternalHwcDisplayId()
+ : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
+ }
flinger->mFakeHwcDisplays.push_back(std::move(display));
}
private:
- DisplayDevice::DisplayType mType;
- HWC2::DisplayType mHwcDisplayType;
+ const DisplayId mDisplayId;
+ const HWC2::DisplayType mHwcDisplayType;
+ const bool mIsPrimary;
+
hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
int32_t mWidth = DEFAULT_WIDTH;
int32_t mHeight = DEFAULT_HEIGHT;
@@ -314,10 +436,13 @@
class FakeDisplayDeviceInjector {
public:
- FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, DisplayDevice::DisplayType type,
- int32_t displayId)
- : mFlinger(flinger),
- mCreationArgs(flinger.mFlinger.get(), mDisplayToken, type, displayId) {}
+ FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
+ const std::optional<DisplayId>& displayId, bool isVirtual,
+ bool isPrimary)
+ : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
+ mCreationArgs.isVirtual = isVirtual;
+ mCreationArgs.isPrimary = isPrimary;
+ }
sp<IBinder> token() const { return mDisplayToken; }
@@ -349,22 +474,11 @@
return *this;
}
- auto& setRenderSurface(std::unique_ptr<renderengine::Surface> renderSurface) {
- mCreationArgs.renderSurface = std::move(renderSurface);
- return *this;
- }
-
auto& setSecure(bool secure) {
mCreationArgs.isSecure = secure;
return *this;
}
- auto& setDisplaySize(int width, int height) {
- mCreationArgs.displayWidth = width;
- mCreationArgs.displayHeight = height;
- return *this;
- }
-
auto& setPowerMode(int mode) {
mCreationArgs.initialPowerMode = mode;
return *this;
@@ -384,7 +498,7 @@
sp<DisplayDevice> inject() {
DisplayDeviceState state;
- state.type = mCreationArgs.type;
+ state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
state.isSecure = mCreationArgs.isSecure;
sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
@@ -392,9 +506,9 @@
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
- if (state.type >= DisplayDevice::DISPLAY_PRIMARY &&
- state.type < DisplayDevice::DISPLAY_VIRTUAL) {
- mFlinger.mutableDisplayTokens()[state.type] = mDisplayToken;
+ if (!mCreationArgs.isVirtual) {
+ LOG_ALWAYS_FATAL_IF(!state.displayId);
+ mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
}
return device;
@@ -406,7 +520,8 @@
DisplayDeviceCreationArgs mCreationArgs;
};
- sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization);
+ surfaceflinger::test::Factory mFactory;
+ sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
// We need to keep a reference to these so they are properly destroyed.
std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 495b3f2..34e71cb 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -35,7 +35,6 @@
MOCK_METHOD1(addResyncSample, bool(nsecs_t));
MOCK_METHOD0(endResync, void());
MOCK_METHOD1(setPeriod, void(nsecs_t));
- MOCK_METHOD1(scalePeriod, void(HWC2::Device::FrequencyScaler));
MOCK_METHOD0(getPeriod, nsecs_t());
MOCK_METHOD1(setRefreshSkipCount, void(int));
MOCK_METHOD3(addEventListener, status_t(const char*, nsecs_t, Callback*));
diff --git a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
index 561fd58..4950a4b 100644
--- a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
+++ b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
@@ -36,6 +36,7 @@
MOCK_METHOD1(queueBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
MOCK_CONST_METHOD2(query, int(int, int*));
MOCK_METHOD1(perform, int(int));
+ MOCK_METHOD2(perform, int(int, int));
MOCK_METHOD1(cancelBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
diff --git a/services/thermalservice/Android.bp b/services/thermalservice/Android.bp
deleted file mode 100644
index d754560..0000000
--- a/services/thermalservice/Android.bp
+++ /dev/null
@@ -1,61 +0,0 @@
-subdirs = [
- "libthermalcallback"
-]
-
-cc_library {
- name: "libthermalservice",
-
- srcs: [
- "aidl/android/os/IThermalEventListener.aidl",
- "aidl/android/os/IThermalService.aidl",
- "aidl/android/os/Temperature.cpp",
- ],
- aidl: {
- include_dirs: ["frameworks/native/services/thermalservice/aidl"],
- export_aidl_headers: true,
- },
- export_include_dirs: ["aidl"],
-
- shared_libs: [
- "libbinder",
- "libutils",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
-
-cc_binary {
- name: "thermalserviced",
-
- srcs: [
- "ThermalService.cpp",
- "thermalserviced.cpp",
- ],
-
- include_dirs: ["frameworks/native"],
-
- shared_libs: [
- "libthermalservice",
- "libbinder",
- "libutils",
- "libthermalcallback",
- "android.hardware.thermal@1.1",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
-
- init_rc: ["thermalservice.rc"],
-}
diff --git a/services/thermalservice/ThermalService.cpp b/services/thermalservice/ThermalService.cpp
deleted file mode 100644
index 6e09a83..0000000
--- a/services/thermalservice/ThermalService.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2017 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 "ThermalService.h"
-#include <android/os/IThermalService.h>
-#include <android/os/IThermalEventListener.h>
-#include <android/os/Temperature.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-
-namespace android {
-namespace os {
-
-/**
- * Notify registered listeners of a thermal throttling start/stop event.
- * @param temperature the temperature at which the event was generated
- */
-binder::Status ThermalService::notifyThrottling(
- const bool isThrottling, const Temperature& temperature) {
- Mutex::Autolock _l(mListenersLock);
-
- mThrottled = isThrottling;
- mThrottleTemperature = temperature;
-
- for (size_t i = 0; i < mListeners.size(); i++) {
- mListeners[i]->notifyThrottling(isThrottling, temperature);
- }
- return binder::Status::ok();
-}
-
-/**
- * Query whether the system is currently thermal throttling.
- * @return true if currently thermal throttling, else false
- */
-binder::Status ThermalService::isThrottling(bool* _aidl_return) {
- Mutex::Autolock _l(mListenersLock);
- *_aidl_return = mThrottled;
- return binder::Status::ok();
-}
-
-/**
- * Register a new thermal event listener.
- * @param listener the client's IThermalEventListener instance to which
- * notifications are to be sent
- */
-binder::Status ThermalService::registerThermalEventListener(
- const sp<IThermalEventListener>& listener) {
- {
- if (listener == NULL)
- return binder::Status::ok();
- Mutex::Autolock _l(mListenersLock);
- // check whether this is a duplicate
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) ==
- IInterface::asBinder(listener)) {
- return binder::Status::ok();
- }
- }
-
- mListeners.add(listener);
- IInterface::asBinder(listener)->linkToDeath(this);
- }
-
- return binder::Status::ok();
-}
-
-/**
- * Unregister a previously-registered thermal event listener.
- * @param listener the client's IThermalEventListener instance to which
- * notifications are to no longer be sent
- */
-binder::Status ThermalService::unregisterThermalEventListener(
- const sp<IThermalEventListener>& listener) {
- if (listener == NULL)
- return binder::Status::ok();
- Mutex::Autolock _l(mListenersLock);
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) ==
- IInterface::asBinder(listener)) {
- IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
- mListeners.removeAt(i);
- break;
- }
- }
-
- return binder::Status::ok();
-}
-
-void ThermalService::binderDied(const wp<IBinder>& who) {
- Mutex::Autolock _l(mListenersLock);
-
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == who) {
- mListeners.removeAt(i);
- break;
- }
- }
-}
-
-/**
- * Publish the supplied ThermalService to servicemanager.
- */
-void ThermalService::publish(
- const sp<ThermalService>& service) {
- defaultServiceManager()->addService(String16("thermalservice"),
- service);
-}
-
-} // namespace os
-} // namespace android
diff --git a/services/thermalservice/ThermalService.h b/services/thermalservice/ThermalService.h
deleted file mode 100644
index 17dfcbc..0000000
--- a/services/thermalservice/ThermalService.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef ANDROID_THERMALSERVICE_THERMALSERVICE_H
-#define ANDROID_THERMALSERVICE_THERMALSERVICE_H
-
-#include <android/os/BnThermalService.h>
-#include <android/os/IThermalEventListener.h>
-#include <android/os/Temperature.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace os {
-
-class ThermalService : public BnThermalService,
- public IBinder::DeathRecipient {
-public:
- ThermalService() : mThrottled(false) {};
- void publish(const sp<ThermalService>& service);
- binder::Status notifyThrottling(
- const bool isThrottling, const Temperature& temperature);
-
-private:
- Mutex mListenersLock;
- Vector<sp<IThermalEventListener> > mListeners;
- bool mThrottled;
- Temperature mThrottleTemperature;
-
- binder::Status registerThermalEventListener(
- const sp<IThermalEventListener>& listener);
- binder::Status unregisterThermalEventListener(
- const sp<IThermalEventListener>& listener);
- binder::Status isThrottling(bool* _aidl_return);
- void binderDied(const wp<IBinder>& who);
-};
-
-}; // namespace os
-}; // namespace android
-
-#endif // ANDROID_THERMALSERVICE_THERMALSERVICE_H
diff --git a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
deleted file mode 100644
index 050325e..0000000
--- a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.Temperature;
-
-/**
- * Listener for thermal events.
- * {@hide}
- */
-oneway interface IThermalEventListener {
- /**
- * Called when a thermal throttling start/stop event is received.
- * @param temperature the temperature at which the event was generated.
- */
- void notifyThrottling(
- in boolean isThrottling, in Temperature temperature);
-}
diff --git a/services/thermalservice/aidl/android/os/IThermalService.aidl b/services/thermalservice/aidl/android/os/IThermalService.aidl
deleted file mode 100644
index e699202..0000000
--- a/services/thermalservice/aidl/android/os/IThermalService.aidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.IThermalEventListener;
-import android.os.Temperature;
-
-/** {@hide} */
-interface IThermalService {
- /**
- * Register a listener for thermal events.
- * @param listener the IThermalEventListener to be notified.
- * {@hide}
- */
- void registerThermalEventListener(in IThermalEventListener listener);
- /**
- * Unregister a previously-registered listener for thermal events.
- * @param listener the IThermalEventListener to no longer be notified.
- * {@hide}
- */
- void unregisterThermalEventListener(in IThermalEventListener listener);
- /**
- * Send a thermal throttling start/stop notification to all listeners.
- * @param temperature the temperature at which the event was generated.
- * {@hide}
- */
- oneway void notifyThrottling(
- in boolean isThrottling, in Temperature temperature);
- /**
- * Return whether system performance is currently thermal throttling.
- * {@hide}
- */
- boolean isThrottling();
-}
diff --git a/services/thermalservice/aidl/android/os/Temperature.aidl b/services/thermalservice/aidl/android/os/Temperature.aidl
deleted file mode 100644
index 0293c39..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.aidl
+++ /dev/null
@@ -1,5 +0,0 @@
-package android.os;
-
-/* Encodes a temperature used by ThermalService. */
-
-parcelable Temperature cpp_header "android/os/Temperature.h";
diff --git a/services/thermalservice/aidl/android/os/Temperature.cpp b/services/thermalservice/aidl/android/os/Temperature.cpp
deleted file mode 100644
index df207b7..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 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/os/Temperature.h"
-
-#include <math.h>
-#include <stdint.h>
-#include <binder/Parcel.h>
-#include <hardware/thermal.h>
-#include <sys/types.h>
-#include <utils/Errors.h>
-
-namespace android {
-namespace os {
-
-Temperature::Temperature() : value_(NAN), type_(DEVICE_TEMPERATURE_UNKNOWN) {}
-
-Temperature::Temperature(const float value, const int type) :
- value_(value), type_(type) {}
-
-Temperature::~Temperature() {}
-
-/*
- * Parcel read/write code must be kept in sync with
- * frameworks/base/core/java/android/os/Temperature.java
- */
-
-status_t Temperature::readFromParcel(const Parcel* p) {
- value_ = p->readFloat();
- type_ = p->readInt32();
- return OK;
-}
-
-status_t Temperature::writeToParcel(Parcel* p) const {
- p->writeFloat(value_);
- p->writeInt32(type_);
- return OK;
-}
-
-} // namespace os
-} // namespace android
diff --git a/services/thermalservice/aidl/android/os/Temperature.h b/services/thermalservice/aidl/android/os/Temperature.h
deleted file mode 100644
index bbc5607..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
-#define ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
-
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace os {
-
-class Temperature : public Parcelable {
- public:
-
- Temperature();
- Temperature(const float value, const int type);
- ~Temperature() override;
-
- float getValue() const {return value_;};
- float getType() const {return type_;};
-
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
- private:
- // The value of the temperature as a float, or NAN if unknown.
- float value_;
- // The type of the temperature, an enum temperature_type from
- // hardware/thermal.h
- int type_;
-};
-
-} // namespace os
-} // namespace android
-
-#endif // ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
diff --git a/services/thermalservice/libthermalcallback/Android.bp b/services/thermalservice/libthermalcallback/Android.bp
deleted file mode 100644
index e98506e..0000000
--- a/services/thermalservice/libthermalcallback/Android.bp
+++ /dev/null
@@ -1,19 +0,0 @@
-cc_library_shared {
- name: "libthermalcallback",
- srcs: [
- "ThermalCallback.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- include_dirs: ["frameworks/native"],
- shared_libs: [
- "android.hardware.thermal@1.1",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libthermalservice",
- "libutils",
- ],
-}
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.cpp b/services/thermalservice/libthermalcallback/ThermalCallback.cpp
deleted file mode 100644
index 5e094fa..0000000
--- a/services/thermalservice/libthermalcallback/ThermalCallback.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#define LOG_TAG "android.hardware.thermal.thermalcallback@1.1-impl"
-#include <log/log.h>
-
-#include "ThermalCallback.h"
-#include "services/thermalservice/ThermalService.h"
-#include <math.h>
-#include <android/os/Temperature.h>
-#include <hardware/thermal.h>
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::os::ThermalService;
-using ::android::hardware::thermal::V1_0::TemperatureType;
-
-// Register a binder ThermalService object for sending events
-void ThermalCallback::registerThermalService(sp<ThermalService> thermalService)
-{
- mThermalService = thermalService;
-}
-
-// Methods from IThermalCallback::V1_1 follow.
-Return<void> ThermalCallback::notifyThrottling(
- bool isThrottling,
- const android::hardware::thermal::V1_0::Temperature& temperature) {
-
- // Convert HIDL IThermal Temperature to binder IThermalService Temperature.
- if (mThermalService != nullptr) {
- float value = NAN;
- int type = DEVICE_TEMPERATURE_UNKNOWN;
-
- switch(temperature.type) {
- case TemperatureType::CPU:
- type = DEVICE_TEMPERATURE_CPU;
- break;
- case TemperatureType::GPU:
- type = DEVICE_TEMPERATURE_GPU;
- break;
- case TemperatureType::BATTERY:
- type = DEVICE_TEMPERATURE_BATTERY;
- break;
- case TemperatureType::SKIN:
- type = DEVICE_TEMPERATURE_SKIN;
- break;
- case TemperatureType::UNKNOWN:
- default:
- type = DEVICE_TEMPERATURE_UNKNOWN;
- break;
- }
-
- value = temperature.currentValue == UNKNOWN_TEMPERATURE ? NAN :
- temperature.currentValue;
-
- android::os::Temperature thermal_svc_temp(value, type);
- mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
- } else {
- ALOGE("IThermalService binder service not created, drop throttling event");
- }
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace thermal
-} // namespace hardware
-} // namespace android
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.h b/services/thermalservice/libthermalcallback/ThermalCallback.h
deleted file mode 100644
index 3d72c68..0000000
--- a/services/thermalservice/libthermalcallback/ThermalCallback.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
-#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
-
-#include <android/hardware/thermal/1.1/IThermalCallback.h>
-#include <android/hardware/thermal/1.0/types.h>
-#include <android/os/Temperature.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::os::ThermalService;
-
-class ThermalCallback : public IThermalCallback {
- public:
- // Register a binder ThermalService object for sending events
- void registerThermalService(sp<ThermalService> thermalService);
-
- // Methods from IThermalCallback::V1_1 follow.
- Return<void> notifyThrottling(
- bool isThrottling,
- const android::hardware::thermal::V1_0::Temperature& temperature)
- override;
-
- private:
- // Our registered binder ThermalService object to use for sending events
- sp<android::os::ThermalService> mThermalService;
-};
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace thermal
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc
deleted file mode 100644
index 94c2c78..0000000
--- a/services/thermalservice/thermalservice.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service thermalservice /system/bin/thermalserviced
- class core
- user system
- group system
diff --git a/services/thermalservice/thermalserviced.cpp b/services/thermalservice/thermalserviced.cpp
deleted file mode 100644
index 8e27266..0000000
--- a/services/thermalservice/thermalserviced.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 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 "thermalserviced"
-#include <log/log.h>
-
-#include "thermalserviced.h"
-#include "ThermalService.h"
-#include "libthermalcallback/ThermalCallback.h"
-
-#include <android/hardware/thermal/1.1/IThermal.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <hidl/HidlTransportSupport.h>
-
-using namespace android;
-using ::android::hardware::thermal::V1_1::IThermal;
-using ::android::hardware::thermal::V1_0::Temperature;
-using ::android::hardware::thermal::V1_1::IThermalCallback;
-using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::hidl_death_recipient;
-using ::android::hidl::base::V1_0::IBase;
-using ::android::os::ThermalService;
-
-template<typename T>
-using Return = hardware::Return<T>;
-
-namespace {
-
-// Our thermalserviced main object
-ThermalServiceDaemon* gThermalServiceDaemon;
-
-// Thermal HAL client
-sp<IThermal> gThermalHal = nullptr;
-
-// Binder death notifier informing of Thermal HAL death.
-struct ThermalServiceDeathRecipient : hidl_death_recipient {
- virtual void serviceDied(
- uint64_t cookie __unused, const wp<IBase>& who __unused) {
- gThermalHal = nullptr;
- ALOGE("IThermal HAL died");
- gThermalServiceDaemon->getThermalHal();
- }
-};
-
-sp<ThermalServiceDeathRecipient> gThermalHalDied = nullptr;
-
-} // anonymous namespace
-
-void ThermalServiceDaemon::thermalServiceStartup() {
- // Binder IThermalService startup
- mThermalService = new android::os::ThermalService;
- mThermalService->publish(mThermalService);
- // Register IThermalService object with IThermalCallback
- if (mThermalCallback != nullptr)
- mThermalCallback->registerThermalService(mThermalService);
- IPCThreadState::self()->joinThreadPool();
-}
-
-// Lookup Thermal HAL, register death notifier, register our
-// ThermalCallback with the Thermal HAL.
-void ThermalServiceDaemon::getThermalHal() {
- gThermalHal = IThermal::getService();
- if (gThermalHal == nullptr) {
- ALOGW("Unable to get Thermal HAL V1.1, vendor thermal event notification not available");
- return;
- }
-
- // Binder death notifier for Thermal HAL
- if (gThermalHalDied == nullptr)
- gThermalHalDied = new ThermalServiceDeathRecipient();
-
- if (gThermalHalDied != nullptr)
- gThermalHal->linkToDeath(gThermalHalDied, 0x451F /* cookie */);
-
- if (mThermalCallback != nullptr) {
- Return<void> ret = gThermalHal->registerThermalCallback(
- mThermalCallback);
- if (!ret.isOk())
- ALOGE("registerThermalCallback failed, status: %s",
- ret.description().c_str());
- }
-}
-
-void ThermalServiceDaemon::thermalCallbackStartup() {
- // HIDL IThermalCallback startup
- // Need at least 2 threads in thread pool since we wait for dead HAL
- // to come back on the binder death notification thread and we need
- // another thread for the incoming service now available call.
- configureRpcThreadpool(2, false /* callerWillJoin */);
- mThermalCallback = new ThermalCallback();
- // Lookup Thermal HAL and register our ThermalCallback.
- getThermalHal();
-}
-
-int main(int /*argc*/, char** /*argv*/) {
- gThermalServiceDaemon = new ThermalServiceDaemon();
- gThermalServiceDaemon->thermalCallbackStartup();
- gThermalServiceDaemon->thermalServiceStartup();
- /* NOTREACHED */
-}
diff --git a/services/thermalservice/thermalserviced.h b/services/thermalservice/thermalserviced.h
deleted file mode 100644
index 309e2fe..0000000
--- a/services/thermalservice/thermalserviced.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef ANDROID_THERMALSERVICE_THERMALSERVICED_H
-#define ANDROID_THERMALSERVICE_THERMALSERVICED_H
-
-#include "ThermalService.h"
-#include "libthermalcallback/ThermalCallback.h"
-
-using namespace android;
-using ::android::hardware::thermal::V1_0::Temperature;
-using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
-using ::android::os::ThermalService;
-
-class ThermalServiceDaemon {
- public:
- void thermalServiceStartup();
- void thermalCallbackStartup();
- void getThermalHal();
- ThermalServiceDaemon() {};
-
- private:
- sp<ThermalService> mThermalService;
- sp<ThermalCallback> mThermalCallback;
-};
-
-#endif // ANDROID_THERMALSERVICE_THERMALSERVICED_H
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index c35ddd4..b5e6bb4 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -15,6 +15,7 @@
sharedLibraries = [
"libbase",
"libbinder",
+ "libbufferhubservice",
"libcutils",
"libgtest_prod",
"libgui",
@@ -29,9 +30,9 @@
name: "libbufferhubd",
srcs: [
"buffer_channel.cpp",
+ "buffer_client.cpp",
"buffer_hub.cpp",
"buffer_hub_binder.cpp",
- "buffer_node.cpp",
"consumer_channel.cpp",
"consumer_queue_channel.cpp",
"IBufferHub.cpp",
@@ -44,7 +45,10 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
export_include_dirs: ["include"],
- header_libs: ["libdvr_headers"],
+ header_libs: [
+ "libdvr_headers",
+ "libnativewindow_headers",
+ ],
shared_libs: sharedLibraries,
static_libs: [
"libbufferhub",
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
index 2f39e41..022a9cc 100644
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -13,6 +13,8 @@
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) override;
+
+ status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
};
IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
@@ -20,6 +22,7 @@
// Transaction code
enum {
CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ IMPORT_BUFFER,
};
sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
@@ -50,6 +53,27 @@
}
}
+status_t BpBufferHub::importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) {
+ Parcel data, reply;
+ status_t ret = NO_ERROR;
+ ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
+ ret |= data.writeUint64(token);
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferHub::importBuffer: failed to write into parcel");
+ return ret;
+ }
+
+ ret = remote()->transact(IMPORT_BUFFER, data, &reply);
+ if (ret == NO_ERROR) {
+ *outClient = interface_cast<IBufferClient>(reply.readStrongBinder());
+ return NO_ERROR;
+ } else {
+ ALOGE("BpBufferHub::importBuffer: failed to transact; errno=%d", ret);
+ return ret;
+ }
+}
+
status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
@@ -64,7 +88,18 @@
sp<IBufferClient> ret = createBuffer(width, height, layer_count, format,
usage, user_metadata_size);
return reply->writeStrongBinder(IInterface::asBinder(ret));
- } break;
+ }
+ case IMPORT_BUFFER: {
+ CHECK_INTERFACE(IBufferHub, data, reply);
+ uint64_t token = data.readUint64();
+ sp<IBufferClient> client;
+ status_t ret = importBuffer(token, &client);
+ if (ret == NO_ERROR) {
+ return reply->writeStrongBinder(IInterface::asBinder(client));
+ } else {
+ return ret;
+ }
+ }
default:
// Should not reach except binder defined transactions such as dumpsys
return BBinder::onTransact(code, data, reply, flags);
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index ee85746..589b31a 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -13,22 +13,17 @@
namespace dvr {
BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
- int channel_id, IonBuffer buffer,
- size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_node_(
- std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)) {
- buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
-}
-
-BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
uint64_t usage, size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
- buffer_node_(std::make_shared<BufferNode>(
- width, height, layer_count, format, usage, user_metadata_size)) {
- buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
+ : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType) {
+ buffer_node_ = std::make_shared<BufferNode>(
+ width, height, layer_count, format, usage, user_metadata_size);
+ if (!buffer_node_->IsValid()) {
+ ALOGE("BufferChannel::BufferChannel: Failed to create BufferNode.");
+ return;
+ }
+ client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
}
BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
@@ -36,8 +31,8 @@
std::shared_ptr<BufferNode> buffer_node)
: BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
buffer_node_(buffer_node) {
- buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
- if (buffer_state_bit_ == 0ULL) {
+ client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
+ if (client_state_mask_ == 0ULL) {
ALOGE("BufferChannel::BufferChannel: %s", strerror(errno));
buffer_node_ = nullptr;
}
@@ -46,17 +41,17 @@
BufferChannel::~BufferChannel() {
ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
channel_id(), buffer_id());
- if (buffer_state_bit_ != 0ULL) {
- buffer_node_->RemoveClientsBitFromMask(buffer_state_bit_);
+ if (client_state_mask_ != 0ULL) {
+ buffer_node_->RemoveClientsBitFromMask(client_state_mask_);
}
Hangup();
}
BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
return BufferInfo(
- buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
- buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
- buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+ buffer_id(), /*consumer_count=*/0, buffer_node_->buffer_desc().width,
+ buffer_node_->buffer_desc().height, buffer_node_->buffer_desc().layers,
+ buffer_node_->buffer_desc().format, buffer_node_->buffer_desc().usage,
/*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
/*index=*/0);
}
@@ -90,17 +85,17 @@
// TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
return BufferTraits<BorrowedHandle>{
- /*buffer_handle=*/buffer_node_->buffer().handle(),
+ /*buffer_handle=*/buffer_node_->buffer_handle(),
/*metadata_handle=*/buffer_node_->metadata().ashmem_handle().Borrow(),
/*id=*/buffer_id(),
- /*buffer_state_bit=*/buffer_state_bit_,
+ /*client_state_mask=*/client_state_mask_,
/*metadata_size=*/buffer_node_->metadata().metadata_size(),
- /*width=*/buffer_node_->buffer().width(),
- /*height=*/buffer_node_->buffer().height(),
- /*layer_count=*/buffer_node_->buffer().layer_count(),
- /*format=*/buffer_node_->buffer().format(),
- /*usage=*/buffer_node_->buffer().usage(),
- /*stride=*/buffer_node_->buffer().stride(),
+ /*width=*/buffer_node_->buffer_desc().width,
+ /*height=*/buffer_node_->buffer_desc().height,
+ /*layer_count=*/buffer_node_->buffer_desc().layers,
+ /*format=*/buffer_node_->buffer_desc().format,
+ /*usage=*/buffer_node_->buffer_desc().usage,
+ /*stride=*/buffer_node_->buffer_desc().stride,
/*acquire_fence_fd=*/BorrowedHandle{},
/*released_fence_fd=*/BorrowedHandle{}};
}
diff --git a/services/vr/bufferhubd/buffer_client.cpp b/services/vr/bufferhubd/buffer_client.cpp
new file mode 100644
index 0000000..f14faf7
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_client.cpp
@@ -0,0 +1,18 @@
+#include <private/dvr/buffer_client.h>
+#include <private/dvr/buffer_hub_binder.h>
+
+namespace android {
+namespace dvr {
+
+status_t BufferClient::duplicate(uint64_t* outToken) {
+ if (!buffer_node_) {
+ // Should never happen
+ ALOGE("BufferClient::duplicate: node is missing.");
+ return UNEXPECTED_NULL;
+ }
+ return service_->registerToken(std::weak_ptr<BufferNode>(buffer_node_),
+ outToken);
+}
+
+} // namespace dvr
+} // namespace android
\ No newline at end of file
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 6421a0b..b73c47d 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -256,15 +256,6 @@
*this, &BufferHubService::OnCreateProducerQueue, message);
return {};
- case BufferHubRPC::ProducerBufferDetach::Opcode:
- // In addition to the message handler in the ProducerChannel's
- // HandleMessage method, we also need to invalid the producer channel (and
- // all associated consumer channels). Note that this has to be done after
- // HandleMessage returns to make sure the IPC request has went back to the
- // client first.
- SetChannel(channel->channel_id(), nullptr);
- return {};
-
default:
return DefaultHandleMessage(message);
}
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index 7da1532..afd34aa 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -46,8 +46,14 @@
"Input arguments are ignored.\n");
}
- // TODO(b/116526156): output real data in this class once we have it
+ fprintf(out, "Binder service:\n");
+ // Active buffers
+ fprintf(out, "Active BufferClients: %zu\n", client_list_.size());
+ // TODO(b/117790952): print buffer information after BufferNode has it
+ // TODO(b/116526156): print more information once we have them
+
if (pdx_service_) {
+ fprintf(out, "\nPDX service:\n");
// BufferHubService::Dumpstate(size_t) is not actually using the param
// So just using 0 as the length
fprintf(out, "%s", pdx_service_->DumpState(0).c_str());
@@ -59,23 +65,14 @@
return NO_ERROR;
}
-sp<IBufferHub> BufferHubBinderService::getServiceProxy() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> service = sm->checkService(String16(getServiceName()));
+status_t BufferHubBinderService::registerToken(
+ const std::weak_ptr<BufferNode> node, uint64_t* outToken) {
+ do {
+ *outToken = token_engine_();
+ } while (token_map_.find(*outToken) != token_map_.end());
- if (service == nullptr) {
- ALOGE("getServiceProxy(): %s binder service not found!", getServiceName());
- return nullptr;
- }
-
- sp<IBufferHub> ret = interface_cast<IBufferHub>(service);
- if (ret == nullptr) {
- ALOGE("getServiceProxy(): %s binder service type casting error!",
- getServiceName());
- return nullptr;
- }
-
- return ret;
+ token_map_.emplace(*outToken, node);
+ return NO_ERROR;
}
sp<IBufferClient> BufferHubBinderService::createBuffer(
@@ -84,12 +81,49 @@
std::shared_ptr<BufferNode> node = std::make_shared<BufferNode>(
width, height, layer_count, format, usage, user_metadata_size);
- sp<BufferClient> client = new BufferClient(node);
+ sp<BufferClient> client = new BufferClient(node, this);
// Add it to list for bookkeeping and dumpsys.
client_list_.push_back(client);
return client;
}
+status_t BufferHubBinderService::importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) {
+ auto iter = token_map_.find(token);
+
+ if (iter == token_map_.end()) { // Not found
+ ALOGE("BufferHubBinderService::importBuffer: token %" PRIu64
+ "does not exist.",
+ token);
+ return PERMISSION_DENIED;
+ }
+
+ if (iter->second.expired()) { // Gone
+ ALOGW(
+ "BufferHubBinderService::importBuffer: the original node of token "
+ "%" PRIu64 "has gone.",
+ token);
+ token_map_.erase(iter);
+ return DEAD_OBJECT;
+ }
+
+ // Promote the weak_ptr
+ std::shared_ptr<BufferNode> node(iter->second);
+ if (!node) {
+ ALOGE("BufferHubBinderService::importBuffer: promote weak_ptr failed.");
+ token_map_.erase(iter);
+ return DEAD_OBJECT;
+ }
+
+ sp<BufferClient> client = new BufferClient(node, this);
+ *outClient = client;
+
+ token_map_.erase(iter);
+ client_list_.push_back(client);
+
+ return NO_ERROR;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
deleted file mode 100644
index bedec6f..0000000
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <errno.h>
-#include <private/dvr/buffer_hub_defs.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-void BufferNode::InitializeMetadata() {
- // Using placement new here to reuse shared memory instead of new allocation
- // Initialize the atomic variables to zero.
- BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
- buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint64_t>(0);
- fence_state_ = new (&metadata_header->fence_state) std::atomic<uint64_t>(0);
- active_clients_bit_mask_ =
- new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
-}
-
-BufferNode::BufferNode(IonBuffer buffer, size_t user_metadata_size)
- : buffer_(std::move(buffer)) {
- metadata_ = BufferHubMetadata::Create(user_metadata_size);
- InitializeMetadata();
-}
-
-// Allocates a new BufferNode.
-BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size) {
- if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "buffer: %s",
- strerror(-ret));
- return;
- }
-
- metadata_ = BufferHubMetadata::Create(user_metadata_size);
- InitializeMetadata();
-}
-
-uint64_t BufferNode::GetActiveClientsBitMask() const {
- return active_clients_bit_mask_->load(std::memory_order_acquire);
-}
-
-uint64_t BufferNode::AddNewActiveClientsBitToMask() {
- uint64_t current_active_clients_bit_mask = GetActiveClientsBitMask();
- uint64_t buffer_state_bit = 0ULL;
- uint64_t updated_active_clients_bit_mask = 0ULL;
- do {
- buffer_state_bit =
- BufferHubDefs::FindNextClearedBit(current_active_clients_bit_mask);
- if (buffer_state_bit == 0ULL) {
- ALOGE(
- "BufferNode::AddNewActiveClientsBitToMask: reached the maximum "
- "mumber of channels per buffer node: 32.");
- errno = E2BIG;
- return 0ULL;
- }
- updated_active_clients_bit_mask =
- current_active_clients_bit_mask | buffer_state_bit;
- } while (!(active_clients_bit_mask_->compare_exchange_weak(
- current_active_clients_bit_mask, updated_active_clients_bit_mask,
- std::memory_order_acq_rel, std::memory_order_acquire)));
- return buffer_state_bit;
-}
-
-void BufferNode::RemoveClientsBitFromMask(const uint64_t& value) {
- active_clients_bit_mask_->fetch_and(~value);
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 4ff7adf..98ef917 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -17,10 +17,10 @@
namespace dvr {
ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id,
- int channel_id, uint64_t consumer_state_bit,
+ int channel_id, uint64_t client_state_mask,
const std::shared_ptr<Channel> producer)
: BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
- consumer_state_bit_(consumer_state_bit),
+ client_state_mask_(client_state_mask),
producer_(producer) {
GetProducer()->AddConsumer(this);
}
@@ -41,7 +41,7 @@
// If producer has not hung up, copy most buffer info from the producer.
info = producer->GetBufferInfo();
} else {
- info.signaled_mask = consumer_state_bit();
+ info.signaled_mask = client_state_mask();
}
info.id = buffer_id();
return info;
@@ -100,7 +100,7 @@
ATRACE_NAME("ConsumerChannel::OnGetBuffer");
ALOGD_IF(TRACE, "ConsumerChannel::OnGetBuffer: buffer=%d", buffer_id());
if (auto producer = GetProducer()) {
- return {producer->GetBuffer(consumer_state_bit_)};
+ return {producer->GetBuffer(client_state_mask_)};
} else {
return ErrorStatus(EPIPE);
}
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index 74b549d..5d7d4e9 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -80,27 +80,35 @@
}
void ConsumerQueueChannel::RegisterNewBuffer(
- const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) {
- ALOGD_IF(TRACE,
- "ConsumerQueueChannel::RegisterNewBuffer: queue_id=%d buffer_id=%d "
- "slot=%zu silent=%d",
- buffer_id(), producer_channel->buffer_id(), slot, silent_);
+ const std::shared_ptr<ProducerChannel>& producer_channel,
+ size_t producer_slot) {
+ ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu silent=%d",
+ __FUNCTION__, buffer_id(), producer_channel->buffer_id(),
+ producer_slot, silent_);
// Only register buffers if the queue is not silent.
- if (!silent_) {
- pending_buffer_slots_.emplace(producer_channel, slot);
-
- // Signal the client that there is new buffer available.
- SignalAvailable();
+ if (silent_) {
+ return;
}
+
+ auto status = producer_channel->CreateConsumerStateMask();
+ if (!status.ok()) {
+ ALOGE("%s: Failed to create consumer state mask: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
+ return;
+ }
+ uint64_t consumer_state_mask = status.get();
+
+ pending_buffer_slots_.emplace(producer_channel, producer_slot,
+ consumer_state_mask);
+ // Signal the client that there is new buffer available.
+ SignalAvailable();
}
Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) {
std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles;
- ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers");
- ALOGD_IF(TRACE,
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: "
- "pending_buffer_slots=%zu",
+ ATRACE_NAME(__FUNCTION__);
+ ALOGD_IF(TRACE, "%s: pending_buffer_slots=%zu", __FUNCTION__,
pending_buffer_slots_.size());
// Indicate this is a silent queue that will not import buffers.
@@ -108,30 +116,30 @@
return ErrorStatus(EBADR);
while (!pending_buffer_slots_.empty()) {
- auto producer_channel = pending_buffer_slots_.front().first.lock();
- size_t producer_slot = pending_buffer_slots_.front().second;
+ auto producer_channel =
+ pending_buffer_slots_.front().producer_channel.lock();
+ size_t producer_slot = pending_buffer_slots_.front().producer_slot;
+ uint64_t consumer_state_mask =
+ pending_buffer_slots_.front().consumer_state_mask;
pending_buffer_slots_.pop();
// It's possible that the producer channel has expired. When this occurs,
// ignore the producer channel.
if (producer_channel == nullptr) {
- ALOGW(
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: producer "
- "channel has already been expired.");
+ ALOGW("%s: producer channel has already been expired.", __FUNCTION__);
continue;
}
- auto status = producer_channel->CreateConsumer(message);
+ auto status =
+ producer_channel->CreateConsumer(message, consumer_state_mask);
// If no buffers are imported successfully, clear available and return an
// error. Otherwise, return all consumer handles already imported
// successfully, but keep available bits on, so that the client can retry
// importing remaining consumer buffers.
if (!status) {
- ALOGE(
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: Failed create "
- "consumer: %s",
- status.GetErrorMessage().c_str());
+ ALOGE("%s: Failed create consumer: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
if (buffer_handles.empty()) {
ClearAvailable();
return status.error_status();
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index 0442881..502c6d6 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -12,10 +12,14 @@
public:
DECLARE_META_INTERFACE(BufferHub);
+ static const char* getServiceName() { return "bufferhubd"; }
virtual sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) = 0;
+
+ virtual status_t importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) = 0;
};
class BnBufferHub : public BnInterface<IBufferHub> {
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
index e9bdb37..744c095 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
@@ -33,9 +33,6 @@
void HandleImpulse(pdx::Message& message) override;
private:
- // Creates a detached buffer from existing IonBuffers.
- BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
- IonBuffer buffer, size_t user_metadata_size);
// Allocates a new detached buffer.
BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
@@ -55,7 +52,7 @@
std::shared_ptr<BufferNode> buffer_node_ = nullptr;
// The state bit of this buffer. Must be one the lower 63 bits.
- uint64_t buffer_state_bit_ = 0ULL;
+ uint64_t client_state_mask_ = 0ULL;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
index 20d51ee..d79ec0a 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_client.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
@@ -7,19 +7,31 @@
namespace android {
namespace dvr {
+// Forward declaration to avoid circular dependency
+class BufferHubBinderService;
+
class BufferClient : public BnBufferClient {
public:
// Creates a server-side buffer client from an existing BufferNode. Note that
// this funciton takes ownership of the shared_ptr.
- explicit BufferClient(std::shared_ptr<BufferNode> node)
- : buffer_node_(std::move(node)){};
+ explicit BufferClient(std::shared_ptr<BufferNode> node,
+ BufferHubBinderService* service)
+ : service_(service), buffer_node_(std::move(node)){};
// Binder IPC functions
bool isValid() override {
return buffer_node_ ? buffer_node_->IsValid() : false;
};
+ status_t duplicate(uint64_t* outToken) override;
+
private:
+ // Hold a pointer to the service to bypass binder interface, as BufferClient
+ // and the service will be in the same process. Also, since service owns
+ // Client, if service dead the clients will be destroyed, so this pointer is
+ // guaranteed to be valid.
+ BufferHubBinderService* service_;
+
std::shared_ptr<BufferNode> buffer_node_;
};
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index 11272ae..cf6124b 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -1,12 +1,15 @@
#ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H
#define ANDROID_DVR_BUFFER_HUB_BINDER_H
+#include <random>
+#include <unordered_map>
#include <vector>
#include <binder/BinderService.h>
#include <private/dvr/IBufferHub.h>
#include <private/dvr/buffer_client.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/buffer_node.h>
namespace android {
namespace dvr {
@@ -15,13 +18,14 @@
public BnBufferHub {
public:
static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
- static const char* getServiceName() { return "bufferhubd"; }
- // Dump bufferhub related information to given fd (usually stdout)
+ // Dumps bufferhub related information to given fd (usually stdout)
// usage: adb shell dumpsys bufferhubd
virtual status_t dump(int fd, const Vector<String16>& args) override;
- // Helper function to get the BpReference to this service
- static sp<IBufferHub> getServiceProxy();
+ // Marks a BufferNode to be duplicated.
+ // TODO(b/116681016): add importToken(int64_t)
+ status_t registerToken(const std::weak_ptr<BufferNode> node,
+ uint64_t* outToken);
// Binder IPC functions
sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
@@ -29,10 +33,18 @@
uint64_t usage,
uint64_t user_metadata_size) override;
+ status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
+
private:
std::shared_ptr<BufferHubService> pdx_service_;
std::vector<sp<BufferClient>> client_list_;
+
+ // TODO(b/118180214): use a more secure implementation
+ std::mt19937_64 token_engine_;
+ // The mapping from token to a specific node. This is a many-to-one mapping.
+ // One node could be refered by 0 to multiple tokens.
+ std::unordered_map<uint64_t, std::weak_ptr<BufferNode>> token_map_;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
index e1e8057..997aeda 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
@@ -1,77 +1,14 @@
#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+// TODO(b/118891412) Remove this file
-#include <private/dvr/ion_buffer.h>
-#include <ui/BufferHubMetadata.h>
+#include <bufferhub/BufferNode.h>
namespace android {
namespace dvr {
-class BufferNode {
- public:
- // Creates a BufferNode from existing IonBuffers, i.e. creating from an
- // existing ProducerChannel. Allocate a new BufferHubMetadata.
- BufferNode(IonBuffer buffer, size_t user_metadata_size);
-
- // Allocates a new BufferNode.
- BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage, size_t user_metadata_size);
-
- // Returns whether the object holds a valid graphic buffer.
- bool IsValid() const { return buffer_.IsValid() && metadata_.IsValid(); }
-
- size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
-
- // Accessors of the IonBuffer.
- IonBuffer& buffer() { return buffer_; }
- const IonBuffer& buffer() const { return buffer_; }
-
- // Accessors of metadata.
- const BufferHubMetadata& metadata() const { return metadata_; }
-
- // Gets the current value of active_clients_bit_mask in metadata_ with
- // std::memory_order_acquire, so that all previous releases of
- // active_clients_bit_mask from all threads will be returned here.
- uint64_t GetActiveClientsBitMask() const;
-
- // Find and add a new buffer_state_bit to active_clients_bit_mask in
- // metadata_.
- // Return the new buffer_state_bit that is added to active_clients_bit_mask.
- // Return 0ULL if there are already 32 bp clients of the buffer.
- uint64_t AddNewActiveClientsBitToMask();
-
- // Removes the value from active_clients_bit_mask in metadata_ with
- // std::memory_order_release, so that the change will be visible to any
- // acquire of active_clients_bit_mask_ in any threads after the succeed of
- // this operation.
- void RemoveClientsBitFromMask(const uint64_t& value);
-
- private:
- // Helper method for constructors to initialize atomic metadata header
- // variables in shared memory.
- void InitializeMetadata();
-
- // Gralloc buffer handles.
- IonBuffer buffer_;
-
- // Metadata in shared memory.
- BufferHubMetadata metadata_;
-
- // The following variables are atomic variables in metadata_ that are visible
- // to Bn object and Bp objects. Please find more info in
- // BufferHubDefs::MetadataHeader.
-
- // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
- // four states: gained, posted, acquired, released.
- std::atomic<uint64_t>* buffer_state_ = nullptr;
-
- // TODO(b/112012161): add comments to fence_state_.
- std::atomic<uint64_t>* fence_state_ = nullptr;
-
- // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
- // union of all buffer_state_bit of all bp clients.
- std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
-};
+typedef android::frameworks::bufferhub::V1_0::implementation::BufferNode
+ BufferNode;
} // namespace dvr
} // namespace android
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
index 84f664d..3298529 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
@@ -16,14 +16,14 @@
using Message = pdx::Message;
ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id,
- uint64_t consumer_state_bit,
+ uint64_t client_state_mask,
const std::shared_ptr<Channel> producer);
~ConsumerChannel() override;
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
- uint64_t consumer_state_bit() const { return consumer_state_bit_; }
+ uint64_t client_state_mask() const { return client_state_mask_; }
BufferInfo GetBufferInfo() const override;
bool OnProducerPosted();
@@ -38,7 +38,7 @@
pdx::Status<void> OnConsumerRelease(Message& message,
LocalFence release_fence);
- uint64_t consumer_state_bit_{0};
+ uint64_t client_state_mask_{0};
bool acquired_{false};
bool released_{true};
std::weak_ptr<Channel> producer_;
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
index d98dbbc..3a81b03 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
@@ -3,8 +3,8 @@
#include <queue>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_queue_channel.h>
@@ -28,7 +28,8 @@
// Called by ProdcuerQueueChannel to notify consumer queue that a new
// buffer has been allocated.
void RegisterNewBuffer(
- const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot);
+ const std::shared_ptr<ProducerChannel>& producer_channel,
+ size_t producer_slot);
// Called after clients been signaled by service that new buffer has been
// allocated. Clients uses kOpConsumerQueueImportBuffers to import new
@@ -40,14 +41,29 @@
void OnProducerClosed();
private:
+ // Data structure to store relavant info of a newly allocated producer buffer
+ // so that consumer channel and buffer can be created later.
+ struct PendingBuffer {
+ PendingBuffer(std::shared_ptr<ProducerChannel> channel, size_t slot,
+ uint64_t mask) {
+ producer_channel = channel;
+ producer_slot = slot;
+ consumer_state_mask = mask;
+ }
+ PendingBuffer() = delete;
+
+ std::weak_ptr<ProducerChannel> producer_channel;
+ size_t producer_slot;
+ uint64_t consumer_state_mask;
+ };
+
std::shared_ptr<ProducerQueueChannel> GetProducer() const;
- // Pointer to the prodcuer channel
+ // Pointer to the producer channel.
std::weak_ptr<Channel> producer_;
// Tracks newly allocated buffer producers along with it's slot number.
- std::queue<std::pair<std::weak_ptr<ProducerChannel>, size_t>>
- pending_buffer_slots_;
+ std::queue<PendingBuffer> pending_buffer_slots_;
// Tracks how many buffers have this queue imported.
size_t capacity_;
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 18bb7bf..3ad9c70 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -42,16 +42,20 @@
~ProducerChannel() override;
- uint64_t buffer_state() const { return buffer_state_->load(); }
+ uint64_t buffer_state() const {
+ return buffer_state_->load(std::memory_order_acquire);
+ }
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
BufferInfo GetBufferInfo() const override;
- BufferDescription<BorrowedHandle> GetBuffer(uint64_t buffer_state_bit);
+ BufferDescription<BorrowedHandle> GetBuffer(uint64_t client_state_mask);
- pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message);
+ pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message,
+ uint64_t consumer_state_mask);
+ pdx::Status<uint64_t> CreateConsumerStateMask();
pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message);
pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
@@ -91,7 +95,7 @@
LocalFence post_fence_;
LocalFence returned_fence_;
size_t user_metadata_size_; // size of user requested buffer buffer size.
- size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
+ size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
pdx::LocalHandle acquire_fence_fd_;
pdx::LocalHandle release_fence_fd_;
@@ -108,7 +112,10 @@
pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
pdx::Status<LocalFence> OnProducerGain(Message& message);
- pdx::Status<RemoteChannelHandle> OnProducerDetach(Message& message);
+
+ // Remove consumer from atomics in shared memory based on consumer_state_mask.
+ // This function is used for clean up for failures in CreateConsumer method.
+ void RemoveConsumerClientMask(uint64_t consumer_state_mask);
ProducerChannel(const ProducerChannel&) = delete;
void operator=(const ProducerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 581390f..c6e8ea9 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -100,6 +100,12 @@
active_clients_bit_mask_ =
new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
+ // Producer channel is never created after consumer channel, and one buffer
+ // only have one fixed producer for now. Thus, it is correct to assume
+ // producer state bit is kFirstClientBitMask for now.
+ active_clients_bit_mask_->store(BufferHubDefs::kFirstClientBitMask,
+ std::memory_order_release);
+
acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
if (!acquire_fence_fd_ || !release_fence_fd_) {
@@ -161,7 +167,8 @@
ALOGD_IF(TRACE,
"ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
"state=%" PRIx64 ".",
- channel_id(), buffer_id(), buffer_state_->load());
+ channel_id(), buffer_id(),
+ buffer_state_->load(std::memory_order_acquire));
for (auto consumer : consumer_channels_) {
consumer->OnProducerClosed();
}
@@ -170,14 +177,15 @@
BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
// Derive the mask of signaled buffers in this producer / consumer set.
- uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
+ uint64_t signaled_mask = signaled() ? BufferHubDefs::kFirstClientBitMask : 0;
for (const ConsumerChannel* consumer : consumer_channels_) {
- signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
+ signaled_mask |= consumer->signaled() ? consumer->client_state_mask() : 0;
}
return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
buffer_.height(), buffer_.layer_count(), buffer_.format(),
- buffer_.usage(), pending_consumers_, buffer_state_->load(),
+ buffer_.usage(), pending_consumers_,
+ buffer_state_->load(std::memory_order_acquire),
signaled_mask, metadata_header_->queue_index);
}
@@ -216,23 +224,18 @@
*this, &ProducerChannel::OnProducerGain, message);
return true;
- case BufferHubRPC::ProducerBufferDetach::Opcode:
- DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
- *this, &ProducerChannel::OnProducerDetach, message);
- return true;
-
default:
return false;
}
}
BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
- uint64_t buffer_state_bit) {
+ uint64_t client_state_mask) {
return {buffer_,
metadata_buffer_,
buffer_id(),
channel_id(),
- buffer_state_bit,
+ client_state_mask,
acquire_fence_fd_.Borrow(),
release_fence_fd_.Borrow()};
}
@@ -241,11 +244,73 @@
Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGetBuffer");
ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
- buffer_id(), buffer_state_->load());
- return {GetBuffer(BufferHubDefs::kProducerStateBit)};
+ buffer_id(), buffer_state_->load(std::memory_order_acquire));
+ return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
}
-Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
+Status<uint64_t> ProducerChannel::CreateConsumerStateMask() {
+ // Try find the next consumer state bit which has not been claimed by any
+ // consumer yet.
+ // memory_order_acquire is chosen here because all writes in other threads
+ // that release active_clients_bit_mask_ need to be visible here.
+ uint64_t current_active_clients_bit_mask =
+ active_clients_bit_mask_->load(std::memory_order_acquire);
+ uint64_t client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+ current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
+ if (client_state_mask == 0ULL) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+ "consumers per producer: 63.");
+ return ErrorStatus(E2BIG);
+ }
+ uint64_t updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | client_state_mask;
+ // Set the updated value only if the current value stays the same as what was
+ // read before. If the comparison succeeds, update the value without
+ // reordering anything before or after this read-modify-write in the current
+ // thread, and the modification will be visible in other threads that acquire
+ // active_clients_bit_mask_. If the comparison fails, load the result of
+ // all writes from all threads to updated_active_clients_bit_mask.
+ // Keep on finding the next available slient state mask until succeed or out
+ // of memory.
+ while (!active_clients_bit_mask_->compare_exchange_weak(
+ current_active_clients_bit_mask, updated_active_clients_bit_mask,
+ std::memory_order_acq_rel, std::memory_order_acquire)) {
+ ALOGE("Current active clients bit mask is changed to %" PRIx64
+ ", which was expected to be %" PRIx64
+ ". Trying to generate a new client state mask to resolve race "
+ "condition.",
+ updated_active_clients_bit_mask, current_active_clients_bit_mask);
+ client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+ current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
+ if (client_state_mask == 0ULL) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+ "consumers per producer: 63.");
+ return ErrorStatus(E2BIG);
+ }
+ updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | client_state_mask;
+ }
+
+ return {client_state_mask};
+}
+
+void ProducerChannel::RemoveConsumerClientMask(uint64_t consumer_state_mask) {
+ // Clear up the buffer state and fence state in case there is already
+ // something there due to possible race condition between producer post and
+ // consumer failed to create channel.
+ buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+ fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+
+ // Restore the consumer state bit and make it visible in other threads that
+ // acquire the active_clients_bit_mask_.
+ active_clients_bit_mask_->fetch_and(~consumer_state_mask,
+ std::memory_order_release);
+}
+
+Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(
+ Message& message, uint64_t consumer_state_mask) {
ATRACE_NAME("ProducerChannel::CreateConsumer");
ALOGD_IF(TRACE,
"ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
@@ -257,60 +322,28 @@
ALOGE(
"ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
status.GetErrorMessage().c_str());
+ RemoveConsumerClientMask(consumer_state_mask);
return ErrorStatus(ENOMEM);
}
- // Try find the next consumer state bit which has not been claimed by any
- // consumer yet.
- // memory_order_acquire is chosen here because all writes in other threads
- // that release active_clients_bit_mask_ need to be visible here.
- uint64_t current_active_clients_bit_mask =
- active_clients_bit_mask_->load(std::memory_order_acquire);
- uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
- current_active_clients_bit_mask | orphaned_consumer_bit_mask_ |
- BufferHubDefs::kProducerStateBit);
- if (consumer_state_bit == 0ULL) {
- ALOGE(
- "ProducerChannel::CreateConsumer: reached the maximum mumber of "
- "consumers per producer: 63.");
- return ErrorStatus(E2BIG);
- }
-
- uint64_t updated_active_clients_bit_mask =
- current_active_clients_bit_mask | consumer_state_bit;
- // Set the updated value only if the current value stays the same as what was
- // read before. If the comparison succeeds, update the value without
- // reordering anything before or after this read-modify-write in the current
- // thread, and the modification will be visible in other threads that acquire
- // active_clients_bit_mask_. If the comparison fails, load the result of
- // all writes from all threads to updated_active_clients_bit_mask.
- if (!active_clients_bit_mask_->compare_exchange_weak(
- current_active_clients_bit_mask, updated_active_clients_bit_mask,
- std::memory_order_acq_rel, std::memory_order_acquire)) {
- ALOGE("Current active clients bit mask is changed to %" PRIu64
- ", which was expected to be %" PRIu64 ".",
- updated_active_clients_bit_mask, current_active_clients_bit_mask);
- return ErrorStatus(EBUSY);
- }
-
- auto consumer =
- std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
- consumer_state_bit, shared_from_this());
+ auto consumer = std::make_shared<ConsumerChannel>(
+ service(), buffer_id(), channel_id, consumer_state_mask,
+ shared_from_this());
const auto channel_status = service()->SetChannel(channel_id, consumer);
if (!channel_status) {
ALOGE(
"ProducerChannel::CreateConsumer: failed to set new consumer channel: "
"%s",
channel_status.GetErrorMessage().c_str());
- // Restore the consumer state bit and make it visible in other threads that
- // acquire the active_clients_bit_mask_.
- active_clients_bit_mask_->fetch_and(~consumer_state_bit,
- std::memory_order_release);
+ RemoveConsumerClientMask(consumer_state_mask);
return ErrorStatus(ENOMEM);
}
+ uint64_t current_buffer_state =
+ buffer_state_->load(std::memory_order_acquire);
if (!producer_owns_ &&
- !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
+ (BufferHubDefs::IsBufferPosted(current_buffer_state) ||
+ BufferHubDefs::IsBufferAcquired(current_buffer_state))) {
// Signal the new consumer when adding it to a posted producer.
if (consumer->OnProducerPosted())
pending_consumers_++;
@@ -322,7 +355,11 @@
Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
ATRACE_NAME("ProducerChannel::OnNewConsumer");
ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
- return CreateConsumer(message);
+ auto status = CreateConsumerStateMask();
+ if (!status.ok()) {
+ return status.error_status();
+ }
+ return CreateConsumer(message, /*consumer_state_mask=*/status.get());
}
Status<void> ProducerChannel::OnProducerPost(Message&,
@@ -403,13 +440,15 @@
return {std::move(returned_fence_)};
}
-Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
+// TODO(b/112338294) Keep here for reference. Remove it after new logic is
+// written.
+/* Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
Message& message) {
ATRACE_NAME("ProducerChannel::OnProducerDetach");
ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
buffer_id());
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
// Can only detach a BufferProducer when it's in gained state.
ALOGW(
@@ -455,7 +494,7 @@
}
return status;
-}
+} */
Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
@@ -505,11 +544,11 @@
// has to done by BufferHub as it requries synchronization among all
// consumers.
BufferHubDefs::ModifyBufferState(buffer_state_,
- BufferHubDefs::kProducerStateBit, 0ULL);
+ BufferHubDefs::kFirstClientBitMask, 0ULL);
ALOGD_IF(TRACE,
"ProducerChannel::OnConsumerRelease: releasing last consumer: "
"buffer_id=%d state=%" PRIx64 ".",
- buffer_id(), buffer_state_->load());
+ buffer_id(), buffer_state_->load(std::memory_order_acquire));
if (orphaned_consumer_bit_mask_) {
ALOGW(
@@ -524,11 +563,12 @@
SignalAvailable();
}
- ALOGE_IF(pending_consumers_ &&
- BufferHubDefs::IsBufferReleased(buffer_state_->load()),
- "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
- "pending_consumers=%d, buffer buffer is in releaed state.",
- pending_consumers_);
+ ALOGE_IF(
+ pending_consumers_ && BufferHubDefs::IsBufferReleased(
+ buffer_state_->load(std::memory_order_acquire)),
+ "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
+ "pending_consumers=%d, buffer buffer is in releaed state.",
+ pending_consumers_);
return {};
}
@@ -549,25 +589,26 @@
// Ignore the orphaned consumer.
DecrementPendingConsumers();
- const uint64_t consumer_state_bit = channel->consumer_state_bit();
- ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
+ const uint64_t client_state_mask = channel->client_state_mask();
+ ALOGE_IF(orphaned_consumer_bit_mask_ & client_state_mask,
"ProducerChannel::OnConsumerOrphaned: Consumer "
- "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
- consumer_state_bit);
- orphaned_consumer_bit_mask_ |= consumer_state_bit;
+ "(client_state_mask=%" PRIx64 ") is already orphaned.",
+ client_state_mask);
+ orphaned_consumer_bit_mask_ |= client_state_mask;
// Atomically clear the fence state bit as an orphaned consumer will never
// signal a release fence. Also clear the buffer state as it won't be released
// as well.
- fence_state_->fetch_and(~consumer_state_bit);
- BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
+ fence_state_->fetch_and(~client_state_mask);
+ BufferHubDefs::ModifyBufferState(buffer_state_, client_state_mask, 0ULL);
ALOGW(
"ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
- "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
+ "buffer_id=%d client_state_mask=%" PRIx64 " queue_index=%" PRIu64
" buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
- buffer_id(), consumer_state_bit, metadata_header_->queue_index,
- buffer_state_->load(), fence_state_->load());
+ buffer_id(), client_state_mask, metadata_header_->queue_index,
+ buffer_state_->load(std::memory_order_acquire),
+ fence_state_->load(std::memory_order_acquire));
}
void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
@@ -579,10 +620,10 @@
std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
// Restore the consumer state bit and make it visible in other threads that
// acquire the active_clients_bit_mask_.
- active_clients_bit_mask_->fetch_and(~channel->consumer_state_bit(),
+ active_clients_bit_mask_->fetch_and(~channel->client_state_mask(),
std::memory_order_release);
- const uint64_t buffer_state = buffer_state_->load();
+ const uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (BufferHubDefs::IsBufferPosted(buffer_state) ||
BufferHubDefs::IsBufferAcquired(buffer_state)) {
// The consumer client is being destoryed without releasing. This could
@@ -595,10 +636,11 @@
BufferHubDefs::IsBufferGained(buffer_state)) {
// The consumer is being close while it is suppose to signal a release
// fence. Signal the dummy fence here.
- if (fence_state_->load() & channel->consumer_state_bit()) {
+ if (fence_state_->load(std::memory_order_acquire) &
+ channel->client_state_mask()) {
epoll_event event;
event.events = EPOLLIN;
- event.data.u64 = channel->consumer_state_bit();
+ event.data.u64 = channel->client_state_mask();
if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
dummy_fence_fd_.Get(), &event) < 0) {
ALOGE(
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index a80691f..a611268 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -24,30 +24,3 @@
// TODO(b/117568153): Temporarily opt out using libcrt.
no_libcrt: true,
}
-
-cc_test {
- name: "buffer_node-test",
- srcs: ["buffer_node-test.cpp"],
- cflags: [
- "-DLOG_TAG=\"buffer_node-test\"",
- "-DTRACE=0",
- "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
- ],
- header_libs: ["libdvr_headers"],
- static_libs: [
- "libbufferhub",
- "libbufferhubd",
- "libgmock",
- ],
- shared_libs: [
- "libbase",
- "libbinder",
- "liblog",
- "libpdx_default_transport",
- "libui",
- "libutils",
- ],
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
-}
-
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index c4703f1..7c00fa6 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -1,7 +1,8 @@
+#include <binder/IServiceManager.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <private/dvr/IBufferClient.h>
-#include <private/dvr/buffer_hub_binder.h>
+#include <private/dvr/IBufferHub.h>
#include <ui/PixelFormat.h>
namespace android {
@@ -9,7 +10,7 @@
namespace {
-using testing::Ne;
+using testing::IsNull;
using testing::NotNull;
const int kWidth = 640;
@@ -22,8 +23,10 @@
class BufferHubBinderServiceTest : public ::testing::Test {
protected:
void SetUp() override {
- service = BufferHubBinderService::getServiceProxy();
- ASSERT_THAT(service, Ne(nullptr));
+ status_t ret = getService<IBufferHub>(
+ String16(IBufferHub::getServiceName()), &service);
+ ASSERT_EQ(ret, OK);
+ ASSERT_THAT(service, NotNull());
}
sp<IBufferHub> service;
@@ -36,6 +39,46 @@
EXPECT_TRUE(bufferClient->isValid());
}
+TEST_F(BufferHubBinderServiceTest, TestDuplicateAndImportBuffer) {
+ sp<IBufferClient> bufferClient = service->createBuffer(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ ASSERT_THAT(bufferClient, NotNull());
+ EXPECT_TRUE(bufferClient->isValid());
+
+ uint64_t token1 = 0ULL;
+ status_t ret = bufferClient->duplicate(&token1);
+ EXPECT_EQ(ret, NO_ERROR);
+
+ // Tokens should be unique even corresponding to the same buffer
+ uint64_t token2 = 0ULL;
+ ret = bufferClient->duplicate(&token2);
+ EXPECT_EQ(ret, NO_ERROR);
+ EXPECT_NE(token2, token1);
+
+ sp<IBufferClient> bufferClient1;
+ ret = service->importBuffer(token1, &bufferClient1);
+ EXPECT_EQ(ret, NO_ERROR);
+ ASSERT_THAT(bufferClient1, NotNull());
+ EXPECT_TRUE(bufferClient1->isValid());
+
+ // Consumes the token to keep the service clean
+ sp<IBufferClient> bufferClient2;
+ ret = service->importBuffer(token2, &bufferClient2);
+ EXPECT_EQ(ret, NO_ERROR);
+ ASSERT_THAT(bufferClient2, NotNull());
+ EXPECT_TRUE(bufferClient2->isValid());
+}
+
+TEST_F(BufferHubBinderServiceTest, TestImportUnexistingToken) {
+ // There is very little chance that this test fails if there is a token = 0
+ // in the service.
+ uint64_t unexistingToken = 0ULL;
+ sp<IBufferClient> bufferClient;
+ status_t ret = service->importBuffer(unexistingToken, &bufferClient);
+ EXPECT_EQ(ret, PERMISSION_DENIED);
+ EXPECT_THAT(bufferClient, IsNull());
+}
+
} // namespace
} // namespace dvr
diff --git a/services/vr/bufferhubd/tests/buffer_node-test.cpp b/services/vr/bufferhubd/tests/buffer_node-test.cpp
deleted file mode 100644
index c2526fe..0000000
--- a/services/vr/bufferhubd/tests/buffer_node-test.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include <errno.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-const uint32_t kWidth = 640;
-const uint32_t kHeight = 480;
-const uint32_t kLayerCount = 1;
-const uint32_t kFormat = 1;
-const uint64_t kUsage = 0;
-const size_t kUserMetadataSize = 0;
-
-class BufferNodeTest : public ::testing::Test {
- protected:
- void SetUp() override {
- buffer_node = new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage,
- kUserMetadataSize);
- ASSERT_TRUE(buffer_node->IsValid());
- }
-
- void TearDown() override {
- if (buffer_node != nullptr) {
- delete buffer_node;
- }
- }
-
- BufferNode* buffer_node = nullptr;
-};
-
-TEST_F(BufferNodeTest, TestCreateBufferNode) {
- EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
-}
-
-TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
- uint64_t new_buffer_state_bit_1 = buffer_node->AddNewActiveClientsBitToMask();
- EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_buffer_state_bit_1);
-
- // Request and add a new buffer_state_bit again.
- // Active clients bit mask should be the union of the two new
- // buffer_state_bits.
- uint64_t new_buffer_state_bit_2 = buffer_node->AddNewActiveClientsBitToMask();
- EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
- new_buffer_state_bit_1 | new_buffer_state_bit_2);
-}
-
-TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
- uint64_t new_buffer_state_bit = 0ULL;
- uint64_t current_mask = 0ULL;
- uint64_t expected_mask = 0ULL;
-
- for (int i = 0; i < 64; ++i) {
- new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
- EXPECT_NE(new_buffer_state_bit, 0);
- EXPECT_FALSE(new_buffer_state_bit & current_mask);
- expected_mask = current_mask | new_buffer_state_bit;
- current_mask = buffer_node->GetActiveClientsBitMask();
- EXPECT_EQ(current_mask, expected_mask);
- }
-
- // Method should fail upon requesting for more than maximum allowable clients.
- new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
- EXPECT_EQ(new_buffer_state_bit, 0ULL);
- EXPECT_EQ(errno, E2BIG);
-}
-
-TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
- buffer_node->AddNewActiveClientsBitToMask();
- uint64_t current_mask = buffer_node->GetActiveClientsBitMask();
- uint64_t new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
- EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);
-
- buffer_node->RemoveClientsBitFromMask(new_buffer_state_bit);
- EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
-
- // Remove the test_mask again to the active client bit mask should not modify
- // the value of active clients bit mask.
- buffer_node->RemoveClientsBitFromMask(new_buffer_state_bit);
- EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
-}
-
-} // namespace
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 003775b..258b45b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -55,7 +55,6 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
"-Wall",
"-Werror",
- // mVrClient unused in vr_composer_client.cpp
"-Wno-error=unused-private-field",
// Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
"-Wno-sign-compare",
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 4b90031..786d5fa 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -19,6 +19,8 @@
#include <hardware/gralloc1.h>
#include <log/log.h>
+#include <memory>
+
#include "impl/vr_hwc.h"
#include "impl/vr_composer_client.h"
@@ -39,11 +41,11 @@
std::unique_ptr<ComposerCommandEngine>
VrComposerClient::createCommandEngine() {
- return std::unique_ptr<VrCommandEngine>(new VrCommandEngine(*this));
+ return std::make_unique<VrCommandEngine>(*this);
}
VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
- : ComposerCommandEngine(client.mHal, client.mResources.get()), mVrClient(client),
+ : ComposerCommandEngine(client.mHal, client.mResources.get()),
mVrHal(client.mVrHal) {}
VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 76b1c4f..de22640 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -54,7 +54,6 @@
IVrComposerClient::BufferMetadata readBufferMetadata();
- VrComposerClient& mVrClient;
android::dvr::VrHwc& mVrHal;
VrCommandEngine(const VrCommandEngine&) = delete;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 4065785..a24c889 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -12,16 +12,16 @@
#include <thread>
#include <utility>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include "stdio_filebuf.h"
-#include "string_trim.h"
#include "unique_file.h"
-using android::dvr::Trim;
+using android::base::Trim;
using android::dvr::UniqueFile;
using android::dvr::stdio_filebuf;
diff --git a/services/vr/performanced/string_trim.h b/services/vr/performanced/string_trim.h
deleted file mode 100644
index 7094e9f..0000000
--- a/services/vr/performanced/string_trim.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-#define ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-
-#include <functional>
-#include <locale>
-#include <string>
-
-namespace android {
-namespace dvr {
-
-// Trims whitespace from the left side of |subject| and returns the result as a
-// new string.
-inline std::string LeftTrim(std::string subject) {
- subject.erase(subject.begin(),
- std::find_if(subject.begin(), subject.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
- return subject;
-}
-
-// Trims whitespace from the right side of |subject| and returns the result as a
-// new string.
-inline std::string RightTrim(std::string subject) {
- subject.erase(std::find_if(subject.rbegin(), subject.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace)))
- .base(),
- subject.end());
- return subject;
-}
-
-// Trims whitespace from the both sides of |subject| and returns the result as a
-// new string.
-inline std::string Trim(std::string subject) {
- subject.erase(subject.begin(),
- std::find_if(subject.begin(), subject.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
- subject.erase(std::find_if(subject.rbegin(), subject.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace)))
- .base(),
- subject.end());
- return subject;
-}
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index bda1682..2fc96bf 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -10,10 +10,10 @@
#include <memory>
#include <sstream>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include "stdio_filebuf.h"
-#include "string_trim.h"
namespace {
@@ -102,7 +102,7 @@
// The status file has lines with the format <field>:<value>. Extract the
// value after the colon.
- return Trim(line.substr(offset + field.size() + 1));
+ return android::base::Trim(line.substr(offset + field.size() + 1));
}
}
@@ -123,7 +123,7 @@
}
std::string key = line.substr(0, offset);
- std::string value = Trim(line.substr(offset + 1));
+ std::string value = android::base::Trim(line.substr(offset + 1));
ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"",
key.c_str(), value.c_str());
@@ -156,7 +156,7 @@
std::string line = "";
std::getline(file_stream, line);
- return Trim(line);
+ return android::base::Trim(line);
} else {
return "";
}
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
index 41f398d..a7c4c30 100644
--- a/vulkan/api/platform.api
+++ b/vulkan/api/platform.api
@@ -56,3 +56,6 @@
// VK_USE_PLATFORM_XLIB_XRANDR_EXT
@internal type u64 RROutput
+
+// VK_USE_PLATFORM_FUCHSIA
+@internal type u32 zx_handle_t
\ No newline at end of file
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 5722810..8f76606 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
// API version (major.minor.patch)
define VERSION_MAJOR 1
define VERSION_MINOR 1
-define VERSION_PATCH 86
+define VERSION_PATCH 91
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -85,9 +85,7 @@
@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME "VK_KHR_wayland_surface"
-// 8
-@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_SPEC_VERSION 4
-@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_NAME "VK_KHR_mir_surface"
+// 8 - VK_KHR_mir_surface removed
// 9
@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
@@ -149,6 +147,10 @@
@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1
@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
+// 29
+@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1
+@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback"
+
// 34
@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
@@ -501,6 +503,10 @@
@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_SPEC_VERSION 1
@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_EXTENSION_NAME "VK_KHR_bind_memory2"
+// 159
+@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1
+@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier"
+
// 161
@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
@@ -518,8 +524,8 @@
@extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image"
// 166
-@extension("VK_NVX_raytracing") define VK_NVX_RAYTRACING_SPEC_VERSION 1
-@extension("VK_NVX_raytracing") define VK_NVX_RAYTRACING_EXTENSION_NAME "VK_NVX_raytracing"
+@extension("VK_NV_raytracing") define VK_NV_RAYTRACING_SPEC_VERSION 2
+@extension("VK_NV_raytracing") define VK_NV_RAYTRACING_EXTENSION_NAME "VK_NV_raytracing"
// 167
@extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1
@@ -557,6 +563,10 @@
@extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
@extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
+// 190
+@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1
+@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior"
+
// 191
@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
@@ -597,6 +607,22 @@
@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
+// 213
+@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 1
+@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_EXENSION_NAME "VK_EXT_pci_bus_info"
+
+// 215
+@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1
+@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface"
+
+// 224
+@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 0
+@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1"
+
+// 225
+@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 0
+@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string"
+
/////////////
// Types //
/////////////
@@ -669,7 +695,7 @@
@extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT
// 166
-@extension("VK_NVX_raytracing") @nonDispatchHandle type u64 VkAccelerationStructureNVX
+@extension("VK_NV_raytracing") @nonDispatchHandle type u64 VkAccelerationStructureNV
/////////////
// Enums //
@@ -724,6 +750,9 @@
enum VkImageTiling {
VK_IMAGE_TILING_OPTIMAL = 0x00000000,
VK_IMAGE_TILING_LINEAR = 0x00000001,
+
+ //@extension("VK_EXT_image_drm_format_modifier") // 159
+ VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000,
}
enum VkImageViewType {
@@ -767,8 +796,8 @@
//@extension("VK_EXT_inline_uniform_block") // 139
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000,
- //@extension("VK_NVX_raytracing") // 166
- VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000,
+ //@extension("VK_NV_raytracing") // 166
+ VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
}
enum VkQueryType {
@@ -776,8 +805,11 @@
VK_QUERY_TYPE_PIPELINE_STATISTICS = 0x00000001, /// Optional
VK_QUERY_TYPE_TIMESTAMP = 0x00000002,
- //@extension("VK_NVX_raytracing") // 166
- VK_QUERY_TYPE_COMPACTED_SIZE_NVX = 1000165000,
+ //@extension("VK_EXT_transform_feedback") // 29
+ VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004,
+
+ //@extension("VK_NV_raytracing") // 166
+ VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000,
}
enum VkBorderColor {
@@ -793,8 +825,8 @@
VK_PIPELINE_BIND_POINT_GRAPHICS = 0x00000000,
VK_PIPELINE_BIND_POINT_COMPUTE = 0x00000001,
- //@extension("VK_NVX_raytracing") // 166
- VK_PIPELINE_BIND_POINT_RAYTRACING_NVX = 1000165000,
+ //@extension("VK_NV_raytracing") // 166
+ VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000,
}
enum VkPrimitiveTopology {
@@ -819,6 +851,9 @@
enum VkIndexType {
VK_INDEX_TYPE_UINT16 = 0x00000000,
VK_INDEX_TYPE_UINT32 = 0x00000001,
+
+ //@extension("VK_NV_raytracing") // 166
+ VK_INDEX_TYPE_NONE_NV = 1000165000,
}
enum VkFilter {
@@ -1417,9 +1452,6 @@
//@extension("VK_KHR_wayland_surface") // 7
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
- //@extension("VK_KHR_mir_surface") // 8
- VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
-
//@extension("VK_KHR_android_surface") // 9
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
@@ -1447,6 +1479,11 @@
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
+ //@extension("VK_EXT_transform_feedback") // 29
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001,
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002,
+
//@extension("VK_AMD_texture_gather_bias_lod") // 42
VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
@@ -1722,6 +1759,14 @@
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004,
VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = 1000156005,
+ //@extension("VK_EXT_image_drm_format_modifier") // 159
+ VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000,
+ VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002,
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003,
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004,
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005,
+
//@extension("VK_KHR_bind_memory2") // 158
VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = 1000157000,
VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = 1000157001,
@@ -1743,18 +1788,18 @@
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002,
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005,
- //@extension("VK_NVX_raytracing") // 166
- VK_STRUCTURE_TYPE_RAYTRACING_PIPELINE_CREATE_INFO_NVX = 1000165000,
- VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NVX = 1000165001,
- VK_STRUCTURE_TYPE_GEOMETRY_INSTANCE_NVX = 1000165002,
- VK_STRUCTURE_TYPE_GEOMETRY_NVX = 1000165003,
- VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NVX = 1000165004,
- VK_STRUCTURE_TYPE_GEOMETRY_AABB_NVX = 1000165005,
- VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NVX = 1000165006,
- VK_STRUCTURE_TYPE_DESCRIPTOR_ACCELERATION_STRUCTURE_INFO_NVX = 1000165007,
- VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NVX = 1000165008,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAYTRACING_PROPERTIES_NVX = 1000165009,
- VK_STRUCTURE_TYPE_HIT_SHADER_MODULE_CREATE_INFO_NVX = 1000165010,
+ //@extension("VK_NV_raytracing") // 166
+ VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000,
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001,
+ VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003,
+ VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004,
+ VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005,
+ VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006,
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007,
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009,
+ VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011,
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012,
//@extension("VK_NV_representative_fragment_test") // 167
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000,
@@ -1778,12 +1823,18 @@
//@extension("VK_KHR_shader_atomic_int64") // 181
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
+ //@extension("VK_EXT_calibrated_timestamps") // 185
+ VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000,
+
//@extension("VK_KHR_driver_properties") // 197
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000,
//@extension("VK_AMD_shader_core_properties") // 186
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
+ //@extension("VK_AMD_memory_overallocation_behavior") // 190
+ VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000,
+
//@extension("VK_EXT_vertex_attribute_divisor") // 191
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
@@ -1795,6 +1846,12 @@
//@extension("VK_KHR_vulkan_memory_model") // 212
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
+
+ //@extension("VK_EXT_pci_bus_info") // 213
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000,
+
+ //@extension("VK_FUCHSIA_imagepipe_surface") // 215
+ VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000,
}
enum VkSubpassContents {
@@ -1857,14 +1914,17 @@
//@extension("VK_KHR_maintenance1") // 70
VK_ERROR_OUT_OF_POOL_MEMORY_KHR = 0xC4642878, // -1000069000
- //@extension("VK_EXT_global_priority") // 175
- VK_ERROR_NOT_PERMITTED_EXT = 0xC4628E4F, // -1000174001
-
//@extension("VK_KHR_external_memory") // 73
VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = 0xC4641CBD, // -1000072003
+ //@extension("VK_EXT_image_drm_format_modifier") // 159
+ VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = 0xC462CCD0, // -1000158000
+
//@extension("VK_EXT_descriptor_indexing") // 162
VK_ERROR_FRAGMENTATION_EXT = 0xc462c118, // -1000161000
+
+ //@extension("VK_EXT_global_priority") // 175
+ VK_ERROR_NOT_PERMITTED_EXT = 0xC4628E4F, // -1000174001
}
enum VkDynamicState {
@@ -1956,8 +2016,8 @@
//@extension("VK_EXT_validation_cache") // 161
VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
- //@extension("VK_NVX_raytracing") // 166
- VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000,
+ //@extension("VK_NV_raytracing") // 166
+ VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
}
@@ -2080,8 +2140,8 @@
//@extension("VK_KHR_sampler_ycbcr_conversion") // 157
VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000,
- //@extension("VK_NVX_raytracing") // 166
- VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT = 1000165000,
+ //@extension("VK_NV_raytracing") // 166
+ VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000,
}
@extension("VK_AMD_rasterization_order") // 19
@@ -2256,22 +2316,36 @@
VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3,
}
-@extension("VK_NVX_raytracing") // 166
-enum VkGeometryTypeNVX {
- VK_GEOMETRY_TYPE_TRIANGLES_NVX = 0,
- VK_GEOMETRY_TYPE_AABBS_NVX = 1,
+@extension("VK_NV_raytracing") // 166
+enum VkRayTracingShaderGroupTypeNV {
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0,
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1,
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2,
}
-@extension("VK_NVX_raytracing") // 166
-enum VkAccelerationStructureTypeNVX {
- VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX = 0,
- VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX = 1,
+@extension("VK_NV_raytracing") // 166
+enum VkGeometryTypeNV {
+ VK_GEOMETRY_TYPE_TRIANGLES_NV = 0,
+ VK_GEOMETRY_TYPE_AABBS_NV = 1,
}
-@extension("VK_NVX_raytracing") // 166
-enum VkCopyAccelerationStructureModeNVX {
- VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX = 0,
- VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX = 1,
+@extension("VK_NV_raytracing") // 166
+enum VkAccelerationStructureTypeNV {
+ VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0,
+ VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1,
+}
+
+@extension("VK_NV_raytracing") // 166
+enum VkCopyAccelerationStructureModeNV {
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0,
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1,
+}
+
+@extension("VK_NV_raytracing") // 166
+enum VkAccelerationStructureMemoryRequirementsTypeNV {
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0,
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1,
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2,
}
@extension("VK_EXT_global_priority") // 175
@@ -2282,6 +2356,21 @@
VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024,
}
+@extension("VK_EXT_calibrated_timestamps") // 185
+enum VkTimeDomainEXT {
+ VK_TIME_DOMAIN_DEVICE_EXT = 0,
+ VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1,
+ VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2,
+ VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3,
+}
+
+@extension("VK_AMD_memory_overallocation_behavior") // 190
+enum VkMemoryOverallocationBehaviorAMD {
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0,
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1,
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2,
+}
+
@extension("VK_KHR_driver_properties") // 197
enum VkDriverIdKHR {
VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1,
@@ -2370,9 +2459,14 @@
//@extension("VK_NV_shading_rate_image") // 165
VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000,
- //@extension("VK_NVX_raytracing") // 166
- VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX = 0x00200000,
- VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX = 0x00400000,
+ //@extension("VK_NV_raytracing") // 166
+ VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000,
+ VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000,
+
+ //@extension("VK_EXT_transform_feedback") // 29
+ VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000,
+ VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000,
+ VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000,
}
/// Buffer usage flags
@@ -2391,8 +2485,12 @@
//@extension("VK_EXT_conditional_rendering") // 82
VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200,
- //@extension("VK_NVX_raytracing") // 166
- VK_BUFFER_USAGE_RAYTRACING_BIT_NVX = 0x00000400,
+ //@extension("VK_NV_raytracing") // 166
+ VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400,
+
+ //@extension("VK_EXT_transform_feedback") // 29
+ VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800,
+ VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000,
}
/// Buffer creation flags
@@ -2419,13 +2517,13 @@
VK_SHADER_STAGE_ALL = 0x7FFFFFFF,
- //@extension("VK_NVX_raytracing") // 166
- VK_SHADER_STAGE_RAYGEN_BIT_NVX = 0x00000100,
- VK_SHADER_STAGE_ANY_HIT_BIT_NVX = 0x00000200,
- VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX = 0x00000400,
- VK_SHADER_STAGE_MISS_BIT_NVX = 0x00000800,
- VK_SHADER_STAGE_INTERSECTION_BIT_NVX = 0x00001000,
- VK_SHADER_STAGE_CALLABLE_BIT_NVX = 0x00002000,
+ //@extension("VK_NV_raytracing") // 166
+ VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100,
+ VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200,
+ VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400,
+ VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800,
+ VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000,
+ VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000,
//@extension("VK_NV_mesh_shader") // 203
VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040,
@@ -2523,8 +2621,8 @@
VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008,
VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = 0x00000010,
- //@extension("VK_NVX_raytracing") // 166
- VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NVX = 0x00000020,
+ //@extension("VK_NV_raytracing") // 166
+ VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020,
}
/// Color component flags
@@ -2666,6 +2764,12 @@
VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = 0x00000010,
VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = 0x00000020,
VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = 0x00000040,
+
+ //@extension("VK_EXT_transform_feedback") // 29
+ VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080,
+ VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100,
+ VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200,
+ VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400,
}
/// Sparse memory bind flags
@@ -2713,12 +2817,16 @@
//@extension("VK_NV_shading_rate_image") // 165
VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000,
- //@extension("VK_NVX_raytracing") // 166
- VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX = 0x00200000,
+ //@extension("VK_NV_raytracing") // 166
+ VK_PIPELINE_STAGE_RAY_TRACING_BIT_NV = 0x00200000,
+ VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000,
//@extension("VK_NV_mesh_shader") // 203
VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000,
VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000,
+
+ //@extension("VK_EXT_transform_feedback") // 29
+ VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000,
}
/// Render pass attachment description flags
@@ -3113,12 +3221,6 @@
//bitfield VkWaylandSurfaceCreateFlagBitsKHR {
//}
-@extension("VK_KHR_mir_surface") // 8
-type VkFlags VkMirSurfaceCreateFlagsKHR
-//@extension("VK_KHR_mir_surface") // 8
-//bitfield VkMirSurfaceCreateFlagBitsKHR {
-//}
-
@extension("VK_KHR_android_surface") // 9
type VkFlags VkAndroidSurfaceCreateFlagsKHR
//@extension("VK_KHR_android_surface") // 9
@@ -3149,6 +3251,12 @@
VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
}
+@extension("VK_EXT_transform_feedback") // 29
+type VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT
+//@extension("VK_EXT_transform_feedback") // 29
+//bitfield VkPipelineRasterizationStateStreamCreateFlagBitsEXT {
+//}
+
@extension("VK_NV_external_memory_capabilities") // 56
type VkFlags VkExternalMemoryHandleTypeFlagsNV
@extension("VK_NV_external_memory_capabilities") // 56
@@ -3397,35 +3505,41 @@
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = 0x00000008,
}
-@extension("VK_NVX_raytracing") // 166
-type VkFlags VkGeometryFlagsNVX
-@extension("VK_NVX_raytracing") // 166
-bitfield VkGeometryFlagBitsNVX {
- VK_GEOMETRY_OPAQUE_BIT_NVX = 0x00000001,
- VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NVX = 0x00000002,
+@extension("VK_NV_raytracing") // 166
+type VkFlags VkGeometryFlagsNV
+@extension("VK_NV_raytracing") // 166
+bitfield VkGeometryFlagBitsNV {
+ VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001,
+ VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002,
}
-@extension("VK_NVX_raytracing") // 166
-type VkFlags VkGeometryInstanceFlagsNVX
-@extension("VK_NVX_raytracing") // 166
-bitfield VkGeometryInstanceFlagBitsNVX {
- VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NVX = 0x00000001,
- VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_FLIP_WINDING_BIT_NVX = 0x00000002,
- VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NVX = 0x00000004,
- VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NVX = 0x00000008,
+@extension("VK_NV_raytracing") // 166
+type VkFlags VkGeometryInstanceFlagsNV
+@extension("VK_NV_raytracing") // 166
+bitfield VkGeometryInstanceFlagBitsNV {
+ VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001,
+ VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002,
+ VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004,
+ VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008,
}
-@extension("VK_NVX_raytracing") // 166
-type VkFlags VkBuildAccelerationStructureFlagsNVX
-@extension("VK_NVX_raytracing") // 166
-bitfield VkBuildAccelerationStructureFlagBitsNVX {
- VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NVX = 0x00000001,
- VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NVX = 0x00000002,
- VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NVX = 0x00000004,
- VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NVX = 0x00000008,
- VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NVX = 0x00000010,
+@extension("VK_NV_raytracing") // 166
+type VkFlags VkBuildAccelerationStructureFlagsNV
+@extension("VK_NV_raytracing") // 166
+bitfield VkBuildAccelerationStructureFlagBitsNV {
+ VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001,
+ VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002,
+ VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004,
+ VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008,
+ VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010,
}
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+type VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA
+//@extension("VK_FUCHSIA_imagepipe_surface") // 215
+//bitfield VkImagePipeSurfaceCreateFlagBitsFUCHSIA {
+//}
+
//////////////////
// Structures //
//////////////////
@@ -5237,15 +5351,6 @@
platform.wl_surface* surface
}
-@extension("VK_KHR_mir_surface") // 8
-class VkMirSurfaceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkMirSurfaceCreateFlagsKHR flags
- platform.MirConnection* connection
- platform.MirSurface* mirSurface
-}
-
@extension("VK_KHR_android_surface") // 9
class VkAndroidSurfaceCreateInfoKHR {
VkStructureType sType
@@ -5360,6 +5465,38 @@
VkBuffer buffer
}
+@extension("VK_EXT_transform_feedback") // 29
+class VkPhysicalDeviceTransformFeedbackFeaturesEXT {
+ VkStructureType sType
+ void* pNext
+ VkBool32 transformFeedback
+ VkBool32 geometryStreams
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+class VkPhysicalDeviceTransformFeedbackPropertiesEXT {
+ VkStructureType sType
+ void* pNext
+ u32 maxTransformFeedbackStreams
+ u32 maxTransformFeedbackBuffers
+ VkDeviceSize maxTransformFeedbackBufferSize
+ u32 maxTransformFeedbackStreamDataSize
+ u32 maxTransformFeedbackBufferDataSize
+ u32 maxTransformFeedbackBufferDataStride
+ VkBool32 transformFeedbackQueries
+ VkBool32 transformFeedbackStreamsLinesTriangles
+ VkBool32 transformFeedbackRasterizationStreamSelect
+ VkBool32 transformFeedbackDraw
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+class VkPipelineRasterizationStateStreamCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkPipelineRasterizationStateStreamCreateFlagsEXT flags
+ u32 rasterizationStream
+}
+
@extension("VK_AMD_texture_gather_bias_lod") // 42
class VkTextureLODGatherFormatPropertiesAMD {
VkStructureType sType
@@ -6599,7 +6736,7 @@
const void* pNext
VkDebugUtilsMessengerCreateFlagsEXT flags
VkDebugUtilsMessageSeverityFlagsEXT messageSeverity
- VkDebugUtilsMessageTypeFlagsEXT messageType
+ VkDebugUtilsMessageTypeFlagsEXT messageTypes
PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback
void* pUserData
}
@@ -6925,6 +7062,55 @@
VkDeviceSize memoryOffset
}
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkDrmFormatModifierPropertiesEXT {
+ u64 drmFormatModifier
+ u32 drmFormatModifierPlaneCount
+ VkFormatFeatureFlags drmFormatModifierTilingFeatures
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkDrmFormatModifierPropertiesListEXT {
+ VkStructureType sType
+ void* pNext
+ u32 drmFormatModifierCount
+ VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkPhysicalDeviceImageDrmFormatModifierInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ u64 drmFormatModifier
+ VkSharingMode sharingMode
+ u32 queueFamilyIndexCount
+ const u32* pQueueFamilyIndices
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierListCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ u32 drmFormatModifierCount
+ const u64* pDrmFormatModifiers
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierExplicitCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ u64 drmFormatModifier
+ u32 drmFormatModifierPlaneCount
+ const VkSubresourceLayout* pPlaneLayouts
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierPropertiesEXT {
+ VkStructureType sType
+ void* pNext
+ u64 drmFormatModifier
+}
+
@extension("VK_EXT_validation_cache") // 161
class VkValidationCacheCreateInfoEXT {
VkStructureType sType
@@ -7075,22 +7261,34 @@
const VkCoarseSampleOrderCustomNV* pCustomSampleOrders
}
-@extension("VK_NVX_raytracing") // 166
-class VkRaytracingPipelineCreateInfoNVX {
- VkStructureType sType
- const void* pNext
- VkPipelineCreateFlags flags
- u32 stageCount
- const VkPipelineShaderStageCreateInfo* pStages
- const u32* pGroupNumbers
- u32 maxRecursionDepth
- VkPipelineLayout layout
- VkPipeline basePipelineHandle
- s32 basePipelineIndex
+@extension("VK_NV_raytracing") // 166
+class VkRayTracingShaderGroupCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkRayTracingShaderGroupTypeNV type
+ u32 generalShader
+ u32 closestHitShader
+ u32 anyHitShader
+ u32 intersectionShader
}
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryTrianglesNVX {
+@extension("VK_NV_raytracing") // 166
+class VkRayTracingPipelineCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkPipelineCreateFlags flags
+ u32 stageCount
+ const VkPipelineShaderStageCreateInfo* pStages
+ u32 groupCount
+ const VkRayTracingShaderGroupCreateInfoNV* pGroups
+ u32 maxRecursionDepth
+ VkPipelineLayout layout
+ VkPipeline basePipelineHandle
+ s32 basePipelineIndex
+}
+
+@extension("VK_NV_raytracing") // 166
+class VkGeometryTrianglesNV {
VkStructureType sType
const void* pNext
VkBuffer vertexData
@@ -7106,8 +7304,8 @@
VkDeviceSize transformOffset
}
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryAABBNVX {
+@extension("VK_NV_raytracing") // 166
+class VkGeometryAABBNV {
VkStructureType sType
const void* pNext
VkBuffer aabbData
@@ -7116,66 +7314,79 @@
VkDeviceSize offset
}
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryDataNVX {
- VkGeometryTrianglesNVX triangles
- VkGeometryAABBNVX aabbs
+@extension("VK_NV_raytracing") // 166
+class VkGeometryDataNV {
+ VkGeometryTrianglesNV triangles
+ VkGeometryAABBNV aabbs
}
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryNVX {
+@extension("VK_NV_raytracing") // 166
+class VkGeometryNV {
VkStructureType sType
const void* pNext
- VkGeometryTypeNVX geometryType
- VkGeometryDataNVX geometry
- VkGeometryFlagsNVX flags
+ VkGeometryTypeNV geometryType
+ VkGeometryDataNV geometry
+ VkGeometryFlagsNV flags
}
-@extension("VK_NVX_raytracing") // 166
-class VkAccelerationStructureCreateInfoNVX {
+@extension("VK_NV_raytracing") // 166
+class VkAccelerationStructureInfoNV {
VkStructureType sType
const void* pNext
- VkAccelerationStructureTypeNVX type
- VkBuildAccelerationStructureFlagsNVX flags
- VkDeviceSize compactedSize
+ VkAccelerationStructureTypeNV type
+ VkBuildAccelerationStructureFlagsNV flags
u32 instanceCount
u32 geometryCount
- const VkGeometryNVX* pGeometries
+ const VkGeometryNV* pGeometries
}
-@extension("VK_NVX_raytracing") // 166
-class VkBindAccelerationStructureMemoryInfoNVX {
+@extension("VK_NV_raytracing") // 166
+class VkAccelerationStructureCreateInfoNV {
VkStructureType sType
const void* pNext
- VkAccelerationStructureNVX accelerationStructure
+ VkDeviceSize compactedSize
+ VkAccelerationStructureInfoNV info
+}
+
+@extension("VK_NV_raytracing") // 166
+class VkBindAccelerationStructureMemoryInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkAccelerationStructureNV accelerationStructure
VkDeviceMemory memory
VkDeviceSize memoryOffset
u32 deviceIndexCount
const u32* pDeviceIndices
}
-@extension("VK_NVX_raytracing") // 166
-class VkDescriptorAccelerationStructureInfoNVX {
+@extension("VK_NV_raytracing") // 166
+class VkDescriptorAccelerationStructureInfoNV {
VkStructureType sType
const void* pNext
u32 accelerationStructureCount
- const VkAccelerationStructureNVX* pAccelerationStructures
+ const VkAccelerationStructureNV* pAccelerationStructures
}
-@extension("VK_NVX_raytracing") // 166
-class VkAccelerationStructureMemoryRequirementsInfoNVX {
+@extension("VK_NV_raytracing") // 166
+class VkAccelerationStructureMemoryRequirementsInfoNV {
VkStructureType sType
const void* pNext
- VkAccelerationStructureNVX accelerationStructure
+ VkAccelerationStructureMemoryRequirementsTypeNV type
+ VkAccelerationStructureNV accelerationStructure
}
-@extension("VK_NVX_raytracing") // 166
-class VkPhysicalDeviceRaytracingPropertiesNVX {
+@extension("VK_NV_raytracing") // 166
+class VkPhysicalDeviceRaytracingPropertiesNV {
VkStructureType sType
void* pNext
- u32 shaderHeaderSize
+ u32 shaderGroupHandleSize
u32 maxRecursionDepth
- u32 maxGeometryCount
+ u32 maxShaderGroupStride
+ u32 shaderGroupBaseAlignment
+ u64 maxGeometryCount
+ u64 maxInstanceCount
+ u64 maxTriangleCount
+ u32 maxDescriptorSetAccelerationStructures
}
@extension("VK_NV_representative_fragment_test") // 167
@@ -7253,6 +7464,13 @@
VkBool32 shaderSharedInt64Atomics
}
+@extension("VK_EXT_calibrated_timestamps") // 185
+class VkCalibratedTimestampInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkTimeDomainEXT timeDomain
+}
+
@extension("VK_AMD_shader_core_properties") // 186
class VkPhysicalDeviceShaderCorePropertiesAMD {
VkStructureType sType
@@ -7273,6 +7491,13 @@
u32 vgprAllocationGranularity
}
+@extension("VK_AMD_memory_overallocation_behavior") // 190
+class VkDeviceMemoryOverallocationCreateInfoAMD {
+ VkStructureType sType
+ const void* pNext
+ VkMemoryOverallocationBehaviorAMD overallocationBehavior
+}
+
@extension("VK_EXT_vertex_attribute_divisor") // 191
class VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT {
VkStructureType sType
@@ -7314,7 +7539,7 @@
class VkPhysicalDeviceDriverPropertiesKHR {
VkStructureType sType
void* pNext
- u32 driverID
+ VkDriverIdKHR driverID
char[VK_MAX_DRIVER_NAME_SIZE_KHR] driverName
char[VK_MAX_DRIVER_INFO_SIZE_KHR] driverInfo
VkConformanceVersionKHR conformanceVersion
@@ -7413,6 +7638,24 @@
VkBool32 vulkanMemoryModelDeviceScope
}
+@extension("VK_EXT_pci_bus_info") // 213
+class VkPhysicalDevicePCIBusInfoPropertiesEXT {
+ VkStructureType sType
+ void* pNext
+ u16 pciDomain
+ u8 pciBus
+ u8 pciDevice
+ u8 pciFunction
+}
+
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+class VkImagePipeSurfaceCreateInfoFUCHSIA {
+ VkStructureType sType
+ const void* pNext
+ VkImagePipeSurfaceCreateFlagsFUCHSIA flags
+ platform.zx_handle_t imagePipeHandle
+}
+
////////////////
// Commands //
@@ -10171,25 +10414,6 @@
return ?
}
-@extension("VK_KHR_mir_surface") // 8
-cmd VkResult vkCreateMirSurfaceKHR(
- VkInstance instance,
- const VkMirSurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- instanceObject := GetInstance(instance)
- return ?
-}
-
-@extension("VK_KHR_mir_surface") // 8
-cmd VkBool32 vkGetPhysicalDeviceMirPresentationSupportKHR(
- VkPhysicalDevice physicalDevice,
- u32 queueFamilyIndex,
- platform.MirConnection* connection) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
@extension("VK_KHR_android_surface") // 9
cmd VkResult vkCreateAndroidSurfaceKHR(
VkInstance instance,
@@ -10334,6 +10558,62 @@
const VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
}
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBindTransformFeedbackBuffersEXT(
+ VkCommandBuffer commandBuffer,
+ u32 firstBinding,
+ u32 bindingCount,
+ const VkBuffer* pBuffers,
+ const VkDeviceSize* pOffsets,
+ const VkDeviceSize* pSizes) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBeginTransformFeedbackEXT(
+ VkCommandBuffer commandBuffer,
+ u32 firstCounterBuffer,
+ u32 counterBufferCount,
+ const VkBuffer* pCounterBuffers,
+ const VkDeviceSize* pCounterBufferOffsets) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdEndTransformFeedbackEXT(
+ VkCommandBuffer commandBuffer,
+ u32 firstCounterBuffer,
+ u32 counterBufferCount,
+ const VkBuffer* pCounterBuffers,
+ const VkDeviceSize* pCounterBufferOffsets) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBeginQueryIndexedEXT(
+ VkCommandBuffer commandBuffer,
+ VkQueryPool queryPool,
+ u32 query,
+ VkQueryControlFlags flags,
+ u32 index) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdEndQueryIndexedEXT(
+ VkCommandBuffer commandBuffer,
+ VkQueryPool queryPool,
+ u32 query,
+ u32 index) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdDrawIndirectByteCountEXT(
+ VkCommandBuffer commandBuffer,
+ u32 instanceCount,
+ u32 firstInstance,
+ VkBuffer counterBuffer,
+ VkDeviceSize counterBufferOffset,
+ u32 counterOffset,
+ u32 vertexStride) {
+}
+
@extension("VK_AMD_draw_indirect_count") // 34
cmd void vkCmdDrawIndirectCountAMD(
VkCommandBuffer commandBuffer,
@@ -11128,6 +11408,14 @@
return ?
}
+@extension("VK_EXT_image_drm_format_modifier") // 159
+cmd VkResult vkGetImageDrmFormatModifierPropertiesEXT(
+ VkDevice device,
+ VkImage image,
+ VkImageDrmFormatModifierPropertiesEXT* pProperties) {
+ return ?
+}
+
@extension("VK_EXT_validation_cache") // 161
cmd VkResult vkCreateValidationCacheEXT(
VkDevice device,
@@ -11185,71 +11473,60 @@
const VkCoarseSampleOrderCustomNV* pCustomSampleOrders) {
}
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkCreateAccelerationStructureNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkCreateAccelerationStructureNV(
VkDevice device,
- const VkAccelerationStructureCreateInfoNVX* pCreateInfo,
+ const VkAccelerationStructureCreateInfoNV* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
- VkAccelerationStructureNVX* pAccelerationStructure) {
+ VkAccelerationStructureNV* pAccelerationStructure) {
return ?
}
-@extension("VK_NVX_raytracing") // 166
-cmd void vkDestroyAccelerationStructureNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkDestroyAccelerationStructureNV(
VkDevice device,
- VkAccelerationStructureNVX accelerationStructure,
+ VkAccelerationStructureNV accelerationStructure,
const VkAllocationCallbacks* pAllocator) {
}
-@extension("VK_NVX_raytracing") // 166
-cmd void vkGetAccelerationStructureMemoryRequirementsNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkGetAccelerationStructureMemoryRequirementsNV(
VkDevice device,
- const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
+ const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo,
VkMemoryRequirements2KHR* pMemoryRequirements) {
}
-@extension("VK_NVX_raytracing") // 166
-cmd void vkGetAccelerationStructureScratchMemoryRequirementsNVX(
- VkDevice device,
- const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
- VkMemoryRequirements2KHR* pMemoryRequirements) {
-}
-
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkBindAccelerationStructureMemoryNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkBindAccelerationStructureMemoryNV(
VkDevice device,
u32 bindInfoCount,
- const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos) {
+ const VkBindAccelerationStructureMemoryInfoNV* pBindInfos) {
return ?
}
-@extension("VK_NVX_raytracing") // 166
-cmd void vkCmdBuildAccelerationStructureNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkCmdBuildAccelerationStructureNV(
VkCommandBuffer commandBuffer,
- VkAccelerationStructureTypeNVX type,
- u32 instanceCount,
+ const VkAccelerationStructureInfoNV* pInfo,
VkBuffer instanceData,
VkDeviceSize instanceOffset,
- u32 geometryCount,
- const VkGeometryNVX* pGeometries,
- VkBuildAccelerationStructureFlagsNVX flags,
VkBool32 update,
- VkAccelerationStructureNVX dst,
- VkAccelerationStructureNVX src,
+ VkAccelerationStructureNV dst,
+ VkAccelerationStructureNV src,
VkBuffer scratch,
VkDeviceSize scratchOffset) {
}
-@extension("VK_NVX_raytracing") // 166
-cmd void vkCmdCopyAccelerationStructureNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkCmdCopyAccelerationStructureNV(
VkCommandBuffer commandBuffer,
- VkAccelerationStructureNVX dst,
- VkAccelerationStructureNVX src,
- VkCopyAccelerationStructureModeNVX mode) {
+ VkAccelerationStructureNV dst,
+ VkAccelerationStructureNV src,
+ VkCopyAccelerationStructureModeNV mode) {
}
-@extension("VK_NVX_raytracing") // 166
-cmd void vkCmdTraceRaysNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkCmdTraceRaysNV(
VkCommandBuffer commandBuffer,
VkBuffer raygenShaderBindingTableBuffer,
VkDeviceSize raygenShaderBindingOffset,
@@ -11259,23 +11536,27 @@
VkBuffer hitShaderBindingTableBuffer,
VkDeviceSize hitShaderBindingOffset,
VkDeviceSize hitShaderBindingStride,
+ VkBuffer callableShaderBindingTableBuffer,
+ VkDeviceSize callableShaderBindingOffset,
+ VkDeviceSize callableShaderBindingStride,
u32 width,
- u32 height) {
+ u32 height,
+ u32 depth) {
}
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkCreateRaytracingPipelinesNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkCreateRaytracingPipelinesNV(
VkDevice device,
VkPipelineCache pipelineCache,
u32 createInfoCount,
- const VkRaytracingPipelineCreateInfoNVX* pCreateInfos,
+ const VkRayTracingPipelineCreateInfoNV* pCreateInfos,
const VkAllocationCallbacks* pAllocator,
VkPipeline* pPipelines) {
return ?
}
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkGetRaytracingShaderHandlesNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkGetRaytracingShaderHandlesNV(
VkDevice device,
VkPipeline pipeline,
u32 firstGroup,
@@ -11285,26 +11566,27 @@
return ?
}
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkGetAccelerationStructureHandleNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkGetAccelerationStructureHandleNV(
VkDevice device,
- VkAccelerationStructureNVX accelerationStructure,
+ VkAccelerationStructureNV accelerationStructure,
platform.size_t dataSize,
void* pData) {
return ?
}
-@extension("VK_NVX_raytracing") // 166
-cmd void vkCmdWriteAccelerationStructurePropertiesNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkCmdWriteAccelerationStructurePropertiesNV(
VkCommandBuffer commandBuffer,
- VkAccelerationStructureNVX accelerationStructure,
+ u32 accelerationStructureCount,
+ const VkAccelerationStructureNV* pAccelerationStructures,
VkQueryType queryType,
VkQueryPool queryPool,
- u32 query) {
+ u32 firstQuery) {
}
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkCompileDeferredNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkCompileDeferredNV(
VkDevice device,
VkPipeline pipeline,
u32 shader) {
@@ -11358,6 +11640,24 @@
u32 marker) {
}
+@extension("VK_EXT_calibrated_timestamps") // 185
+cmd VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(
+ VkPhysicalDevice physicalDevice,
+ u32* pTimeDomainCount,
+ VkTimeDomainEXT* pTimeDomains) {
+ return ?
+}
+
+@extension("VK_EXT_calibrated_timestamps") // 185
+cmd VkResult vkGetCalibratedTimestampsEXT(
+ VkDevice device,
+ u32 timestampCount,
+ const VkCalibratedTimestampInfoEXT* pTimestampInfos,
+ u64* pTimestamps,
+ u64* pMaxDeviation) {
+ return ?
+}
+
@extension("VK_NV_mesh_shader") // 203
cmd void vkCmdDrawMeshTasksNV(
VkCommandBuffer commandBuffer,
@@ -11406,6 +11706,15 @@
VkCheckpointDataNV* pCheckpointData) {
}
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+cmd VkResult vkCreateImagePipeSurfaceFUCHSIA(
+ VkInstance instance,
+ const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface) {
+ return ?
+}
+
////////////////
// Validation //
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index d05c849..77da637 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -24,6 +24,10 @@
#include "vulkan_android.h"
#endif
+#ifdef VK_USE_PLATFORM_FUCHSIA
+#include <zircon/types.h>
+#include "vulkan_fuchsia.h"
+#endif
#ifdef VK_USE_PLATFORM_IOS_MVK
#include "vulkan_ios.h"
@@ -35,12 +39,6 @@
#endif
-#ifdef VK_USE_PLATFORM_MIR_KHR
-#include <mir_toolkit/client_types.h>
-#include "vulkan_mir.h"
-#endif
-
-
#ifdef VK_USE_PLATFORM_VI_NN
#include "vulkan_vi.h"
#endif
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index 39f4dc6..4cd8ed5 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,11 +43,10 @@
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
// Version of this file
-#define VK_HEADER_VERSION 86
+#define VK_HEADER_VERSION 91
#define VK_NULL_HANDLE 0
-
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
@@ -60,7 +59,6 @@
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
#endif
#endif
-
typedef uint32_t VkFlags;
@@ -147,6 +145,7 @@
VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
VK_ERROR_INVALID_SHADER_NV = -1000012000,
+ VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000,
VK_ERROR_FRAGMENTATION_EXT = -1000161000,
VK_ERROR_NOT_PERMITTED_EXT = -1000174001,
VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY,
@@ -286,7 +285,6 @@
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
- VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
@@ -297,6 +295,9 @@
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001,
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002,
VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000,
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
@@ -398,6 +399,12 @@
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002,
VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
+ VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000,
+ VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002,
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003,
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004,
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005,
VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000,
VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001,
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000,
@@ -409,17 +416,17 @@
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002,
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005,
- VK_STRUCTURE_TYPE_RAYTRACING_PIPELINE_CREATE_INFO_NVX = 1000165000,
- VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NVX = 1000165001,
- VK_STRUCTURE_TYPE_GEOMETRY_INSTANCE_NVX = 1000165002,
- VK_STRUCTURE_TYPE_GEOMETRY_NVX = 1000165003,
- VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NVX = 1000165004,
- VK_STRUCTURE_TYPE_GEOMETRY_AABB_NVX = 1000165005,
- VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NVX = 1000165006,
- VK_STRUCTURE_TYPE_DESCRIPTOR_ACCELERATION_STRUCTURE_INFO_NVX = 1000165007,
- VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NVX = 1000165008,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAYTRACING_PROPERTIES_NVX = 1000165009,
- VK_STRUCTURE_TYPE_HIT_SHADER_MODULE_CREATE_INFO_NVX = 1000165010,
+ VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000,
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001,
+ VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003,
+ VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004,
+ VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005,
+ VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006,
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007,
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009,
+ VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011,
+ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000,
VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001,
VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000,
@@ -428,7 +435,9 @@
VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
+ VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
+ VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
@@ -443,6 +452,8 @@
VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000,
VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000,
+ VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000,
VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
@@ -811,6 +822,7 @@
typedef enum VkImageTiling {
VK_IMAGE_TILING_OPTIMAL = 0,
VK_IMAGE_TILING_LINEAR = 1,
+ VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000,
VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR,
VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1),
@@ -833,7 +845,8 @@
VK_QUERY_TYPE_OCCLUSION = 0,
VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,
VK_QUERY_TYPE_TIMESTAMP = 2,
- VK_QUERY_TYPE_COMPACTED_SIZE_NVX = 1000165000,
+ VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004,
+ VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000,
VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION,
VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP,
VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1),
@@ -1163,7 +1176,7 @@
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000,
- VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000,
+ VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1),
@@ -1192,7 +1205,7 @@
typedef enum VkPipelineBindPoint {
VK_PIPELINE_BIND_POINT_GRAPHICS = 0,
VK_PIPELINE_BIND_POINT_COMPUTE = 1,
- VK_PIPELINE_BIND_POINT_RAYTRACING_NVX = 1000165000,
+ VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000,
VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS,
VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE,
VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1),
@@ -1211,6 +1224,7 @@
typedef enum VkIndexType {
VK_INDEX_TYPE_UINT16 = 0,
VK_INDEX_TYPE_UINT32 = 1,
+ VK_INDEX_TYPE_NONE_NV = 1000165000,
VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16,
VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32,
VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1),
@@ -1264,7 +1278,7 @@
VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000,
VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
- VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000,
+ VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE,
VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION,
VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,
@@ -1428,10 +1442,12 @@
VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000,
+ VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000,
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000,
VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,
VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000,
- VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX = 0x00200000,
+ VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = 0x00200000,
+ VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000,
VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000,
VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000,
VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1447,6 +1463,10 @@
VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010,
VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020,
VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040,
+ VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080,
+ VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100,
+ VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200,
+ VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400,
VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT,
VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT,
VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT,
@@ -1521,8 +1541,10 @@
VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100,
+ VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800,
+ VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000,
VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200,
- VK_BUFFER_USAGE_RAYTRACING_BIT_NVX = 0x00000400,
+ VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400,
VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkBufferUsageFlagBits;
typedef VkFlags VkBufferUsageFlags;
@@ -1537,7 +1559,7 @@
VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008,
VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010,
- VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NVX = 0x00000020,
+ VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020,
VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT,
VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE,
VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1554,12 +1576,12 @@
VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020,
VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F,
VK_SHADER_STAGE_ALL = 0x7FFFFFFF,
- VK_SHADER_STAGE_RAYGEN_BIT_NVX = 0x00000100,
- VK_SHADER_STAGE_ANY_HIT_BIT_NVX = 0x00000200,
- VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX = 0x00000400,
- VK_SHADER_STAGE_MISS_BIT_NVX = 0x00000800,
- VK_SHADER_STAGE_INTERSECTION_BIT_NVX = 0x00001000,
- VK_SHADER_STAGE_CALLABLE_BIT_NVX = 0x00002000,
+ VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100,
+ VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200,
+ VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400,
+ VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800,
+ VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000,
+ VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000,
VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040,
VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080,
VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1643,13 +1665,16 @@
VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
+ VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000,
+ VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000,
+ VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000,
VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000,
VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000,
- VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX = 0x00200000,
- VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX = 0x00400000,
+ VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000,
+ VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000,
VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkAccessFlagBits;
typedef VkFlags VkAccessFlags;
@@ -6092,7 +6117,7 @@
typedef struct VkPhysicalDeviceDriverPropertiesKHR {
VkStructureType sType;
void* pNext;
- uint32_t driverID;
+ VkDriverIdKHR driverID;
char driverName[VK_MAX_DRIVER_NAME_SIZE_KHR];
char driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR];
VkConformanceVersionKHR conformanceVersion;
@@ -6157,7 +6182,7 @@
VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33,
VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000,
VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000,
- VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT = 1000165000,
+ VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000,
VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT,
VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT,
VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT,
@@ -6359,6 +6384,95 @@
+#define VK_EXT_transform_feedback 1
+#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1
+#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback"
+
+typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT;
+
+typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 transformFeedback;
+ VkBool32 geometryStreams;
+} VkPhysicalDeviceTransformFeedbackFeaturesEXT;
+
+typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t maxTransformFeedbackStreams;
+ uint32_t maxTransformFeedbackBuffers;
+ VkDeviceSize maxTransformFeedbackBufferSize;
+ uint32_t maxTransformFeedbackStreamDataSize;
+ uint32_t maxTransformFeedbackBufferDataSize;
+ uint32_t maxTransformFeedbackBufferDataStride;
+ VkBool32 transformFeedbackQueries;
+ VkBool32 transformFeedbackStreamsLinesTriangles;
+ VkBool32 transformFeedbackRasterizationStreamSelect;
+ VkBool32 transformFeedbackDraw;
+} VkPhysicalDeviceTransformFeedbackPropertiesEXT;
+
+typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkPipelineRasterizationStateStreamCreateFlagsEXT flags;
+ uint32_t rasterizationStream;
+} VkPipelineRasterizationStateStreamCreateInfoEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets);
+typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index);
+typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT(
+ VkCommandBuffer commandBuffer,
+ uint32_t firstBinding,
+ uint32_t bindingCount,
+ const VkBuffer* pBuffers,
+ const VkDeviceSize* pOffsets,
+ const VkDeviceSize* pSizes);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT(
+ VkCommandBuffer commandBuffer,
+ uint32_t firstCounterBuffer,
+ uint32_t counterBufferCount,
+ const VkBuffer* pCounterBuffers,
+ const VkDeviceSize* pCounterBufferOffsets);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT(
+ VkCommandBuffer commandBuffer,
+ uint32_t firstCounterBuffer,
+ uint32_t counterBufferCount,
+ const VkBuffer* pCounterBuffers,
+ const VkDeviceSize* pCounterBufferOffsets);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT(
+ VkCommandBuffer commandBuffer,
+ VkQueryPool queryPool,
+ uint32_t query,
+ VkQueryControlFlags flags,
+ uint32_t index);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT(
+ VkCommandBuffer commandBuffer,
+ VkQueryPool queryPool,
+ uint32_t query,
+ uint32_t index);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT(
+ VkCommandBuffer commandBuffer,
+ uint32_t instanceCount,
+ uint32_t firstInstance,
+ VkBuffer counterBuffer,
+ VkDeviceSize counterBufferOffset,
+ uint32_t counterOffset,
+ uint32_t vertexStride);
+#endif
+
#define VK_AMD_draw_indirect_count 1
#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
@@ -7341,7 +7455,7 @@
typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
- VkDebugUtilsMessageTypeFlagsEXT messageType,
+ VkDebugUtilsMessageTypeFlagsEXT messageTypes,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData);
@@ -7676,6 +7790,65 @@
#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage"
+#define VK_EXT_image_drm_format_modifier 1
+#define VK_EXT_EXTENSION_159_SPEC_VERSION 0
+#define VK_EXT_EXTENSION_159_EXTENSION_NAME "VK_EXT_extension_159"
+#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1
+#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier"
+
+typedef struct VkDrmFormatModifierPropertiesEXT {
+ uint64_t drmFormatModifier;
+ uint32_t drmFormatModifierPlaneCount;
+ VkFormatFeatureFlags drmFormatModifierTilingFeatures;
+} VkDrmFormatModifierPropertiesEXT;
+
+typedef struct VkDrmFormatModifierPropertiesListEXT {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t drmFormatModifierCount;
+ VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties;
+} VkDrmFormatModifierPropertiesListEXT;
+
+typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ uint64_t drmFormatModifier;
+ VkSharingMode sharingMode;
+ uint32_t queueFamilyIndexCount;
+ const uint32_t* pQueueFamilyIndices;
+} VkPhysicalDeviceImageDrmFormatModifierInfoEXT;
+
+typedef struct VkImageDrmFormatModifierListCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t drmFormatModifierCount;
+ const uint64_t* pDrmFormatModifiers;
+} VkImageDrmFormatModifierListCreateInfoEXT;
+
+typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ uint64_t drmFormatModifier;
+ uint32_t drmFormatModifierPlaneCount;
+ const VkSubresourceLayout* pPlaneLayouts;
+} VkImageDrmFormatModifierExplicitCreateInfoEXT;
+
+typedef struct VkImageDrmFormatModifierPropertiesEXT {
+ VkStructureType sType;
+ void* pNext;
+ uint64_t drmFormatModifier;
+} VkImageDrmFormatModifierPropertiesEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT(
+ VkDevice device,
+ VkImage image,
+ VkImageDrmFormatModifierPropertiesEXT* pProperties);
+#endif
+
#define VK_EXT_validation_cache 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT)
@@ -7940,81 +8113,113 @@
const VkCoarseSampleOrderCustomNV* pCustomSampleOrders);
#endif
-#define VK_NVX_raytracing 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNVX)
+#define VK_NV_ray_tracing 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV)
-#define VK_NVX_RAYTRACING_SPEC_VERSION 1
-#define VK_NVX_RAYTRACING_EXTENSION_NAME "VK_NVX_raytracing"
+#define VK_NV_RAY_TRACING_SPEC_VERSION 2
+#define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing"
+#define VK_SHADER_UNUSED_NV (~0U)
-typedef enum VkGeometryTypeNVX {
- VK_GEOMETRY_TYPE_TRIANGLES_NVX = 0,
- VK_GEOMETRY_TYPE_AABBS_NVX = 1,
- VK_GEOMETRY_TYPE_BEGIN_RANGE_NVX = VK_GEOMETRY_TYPE_TRIANGLES_NVX,
- VK_GEOMETRY_TYPE_END_RANGE_NVX = VK_GEOMETRY_TYPE_AABBS_NVX,
- VK_GEOMETRY_TYPE_RANGE_SIZE_NVX = (VK_GEOMETRY_TYPE_AABBS_NVX - VK_GEOMETRY_TYPE_TRIANGLES_NVX + 1),
- VK_GEOMETRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryTypeNVX;
+typedef enum VkRayTracingShaderGroupTypeNV {
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0,
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1,
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2,
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_BEGIN_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV,
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_END_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV,
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_RANGE_SIZE_NV = (VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV + 1),
+ VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkRayTracingShaderGroupTypeNV;
-typedef enum VkAccelerationStructureTypeNVX {
- VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX = 0,
- VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX = 1,
- VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NVX = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX,
- VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NVX = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX,
- VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NVX = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX + 1),
- VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkAccelerationStructureTypeNVX;
+typedef enum VkGeometryTypeNV {
+ VK_GEOMETRY_TYPE_TRIANGLES_NV = 0,
+ VK_GEOMETRY_TYPE_AABBS_NV = 1,
+ VK_GEOMETRY_TYPE_BEGIN_RANGE_NV = VK_GEOMETRY_TYPE_TRIANGLES_NV,
+ VK_GEOMETRY_TYPE_END_RANGE_NV = VK_GEOMETRY_TYPE_AABBS_NV,
+ VK_GEOMETRY_TYPE_RANGE_SIZE_NV = (VK_GEOMETRY_TYPE_AABBS_NV - VK_GEOMETRY_TYPE_TRIANGLES_NV + 1),
+ VK_GEOMETRY_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryTypeNV;
-typedef enum VkCopyAccelerationStructureModeNVX {
- VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX = 0,
- VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX = 1,
- VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NVX = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX,
- VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NVX = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX,
- VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NVX = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX + 1),
- VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkCopyAccelerationStructureModeNVX;
+typedef enum VkAccelerationStructureTypeNV {
+ VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0,
+ VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1,
+ VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV,
+ VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV,
+ VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1),
+ VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkAccelerationStructureTypeNV;
+
+typedef enum VkCopyAccelerationStructureModeNV {
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0,
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1,
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV,
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV,
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NV = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV + 1),
+ VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkCopyAccelerationStructureModeNV;
+
+typedef enum VkAccelerationStructureMemoryRequirementsTypeNV {
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0,
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1,
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2,
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV,
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV,
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV + 1),
+ VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkAccelerationStructureMemoryRequirementsTypeNV;
-typedef enum VkGeometryFlagBitsNVX {
- VK_GEOMETRY_OPAQUE_BIT_NVX = 0x00000001,
- VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NVX = 0x00000002,
- VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryFlagBitsNVX;
-typedef VkFlags VkGeometryFlagsNVX;
+typedef enum VkGeometryFlagBitsNV {
+ VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001,
+ VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002,
+ VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryFlagBitsNV;
+typedef VkFlags VkGeometryFlagsNV;
-typedef enum VkGeometryInstanceFlagBitsNVX {
- VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NVX = 0x00000001,
- VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_FLIP_WINDING_BIT_NVX = 0x00000002,
- VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NVX = 0x00000004,
- VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NVX = 0x00000008,
- VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryInstanceFlagBitsNVX;
-typedef VkFlags VkGeometryInstanceFlagsNVX;
+typedef enum VkGeometryInstanceFlagBitsNV {
+ VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001,
+ VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002,
+ VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004,
+ VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008,
+ VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryInstanceFlagBitsNV;
+typedef VkFlags VkGeometryInstanceFlagsNV;
-typedef enum VkBuildAccelerationStructureFlagBitsNVX {
- VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NVX = 0x00000001,
- VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NVX = 0x00000002,
- VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NVX = 0x00000004,
- VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NVX = 0x00000008,
- VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NVX = 0x00000010,
- VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkBuildAccelerationStructureFlagBitsNVX;
-typedef VkFlags VkBuildAccelerationStructureFlagsNVX;
+typedef enum VkBuildAccelerationStructureFlagBitsNV {
+ VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001,
+ VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002,
+ VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004,
+ VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008,
+ VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010,
+ VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkBuildAccelerationStructureFlagBitsNV;
+typedef VkFlags VkBuildAccelerationStructureFlagsNV;
-typedef struct VkRaytracingPipelineCreateInfoNVX {
- VkStructureType sType;
- const void* pNext;
- VkPipelineCreateFlags flags;
- uint32_t stageCount;
- const VkPipelineShaderStageCreateInfo* pStages;
- const uint32_t* pGroupNumbers;
- uint32_t maxRecursionDepth;
- VkPipelineLayout layout;
- VkPipeline basePipelineHandle;
- int32_t basePipelineIndex;
-} VkRaytracingPipelineCreateInfoNVX;
+typedef struct VkRayTracingShaderGroupCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkRayTracingShaderGroupTypeNV type;
+ uint32_t generalShader;
+ uint32_t closestHitShader;
+ uint32_t anyHitShader;
+ uint32_t intersectionShader;
+} VkRayTracingShaderGroupCreateInfoNV;
-typedef struct VkGeometryTrianglesNVX {
+typedef struct VkRayTracingPipelineCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkPipelineCreateFlags flags;
+ uint32_t stageCount;
+ const VkPipelineShaderStageCreateInfo* pStages;
+ uint32_t groupCount;
+ const VkRayTracingShaderGroupCreateInfoNV* pGroups;
+ uint32_t maxRecursionDepth;
+ VkPipelineLayout layout;
+ VkPipeline basePipelineHandle;
+ int32_t basePipelineIndex;
+} VkRayTracingPipelineCreateInfoNV;
+
+typedef struct VkGeometryTrianglesNV {
VkStructureType sType;
const void* pNext;
VkBuffer vertexData;
@@ -8028,136 +8233,138 @@
VkIndexType indexType;
VkBuffer transformData;
VkDeviceSize transformOffset;
-} VkGeometryTrianglesNVX;
+} VkGeometryTrianglesNV;
-typedef struct VkGeometryAABBNVX {
+typedef struct VkGeometryAABBNV {
VkStructureType sType;
const void* pNext;
VkBuffer aabbData;
uint32_t numAABBs;
uint32_t stride;
VkDeviceSize offset;
-} VkGeometryAABBNVX;
+} VkGeometryAABBNV;
-typedef struct VkGeometryDataNVX {
- VkGeometryTrianglesNVX triangles;
- VkGeometryAABBNVX aabbs;
-} VkGeometryDataNVX;
+typedef struct VkGeometryDataNV {
+ VkGeometryTrianglesNV triangles;
+ VkGeometryAABBNV aabbs;
+} VkGeometryDataNV;
-typedef struct VkGeometryNVX {
- VkStructureType sType;
- const void* pNext;
- VkGeometryTypeNVX geometryType;
- VkGeometryDataNVX geometry;
- VkGeometryFlagsNVX flags;
-} VkGeometryNVX;
+typedef struct VkGeometryNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkGeometryTypeNV geometryType;
+ VkGeometryDataNV geometry;
+ VkGeometryFlagsNV flags;
+} VkGeometryNV;
-typedef struct VkAccelerationStructureCreateInfoNVX {
- VkStructureType sType;
- const void* pNext;
- VkAccelerationStructureTypeNVX type;
- VkBuildAccelerationStructureFlagsNVX flags;
- VkDeviceSize compactedSize;
- uint32_t instanceCount;
- uint32_t geometryCount;
- const VkGeometryNVX* pGeometries;
-} VkAccelerationStructureCreateInfoNVX;
+typedef struct VkAccelerationStructureInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkAccelerationStructureTypeNV type;
+ VkBuildAccelerationStructureFlagsNV flags;
+ uint32_t instanceCount;
+ uint32_t geometryCount;
+ const VkGeometryNV* pGeometries;
+} VkAccelerationStructureInfoNV;
-typedef struct VkBindAccelerationStructureMemoryInfoNVX {
- VkStructureType sType;
- const void* pNext;
- VkAccelerationStructureNVX accelerationStructure;
- VkDeviceMemory memory;
- VkDeviceSize memoryOffset;
- uint32_t deviceIndexCount;
- const uint32_t* pDeviceIndices;
-} VkBindAccelerationStructureMemoryInfoNVX;
+typedef struct VkAccelerationStructureCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkDeviceSize compactedSize;
+ VkAccelerationStructureInfoNV info;
+} VkAccelerationStructureCreateInfoNV;
-typedef struct VkDescriptorAccelerationStructureInfoNVX {
- VkStructureType sType;
- const void* pNext;
- uint32_t accelerationStructureCount;
- const VkAccelerationStructureNVX* pAccelerationStructures;
-} VkDescriptorAccelerationStructureInfoNVX;
+typedef struct VkBindAccelerationStructureMemoryInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkAccelerationStructureNV accelerationStructure;
+ VkDeviceMemory memory;
+ VkDeviceSize memoryOffset;
+ uint32_t deviceIndexCount;
+ const uint32_t* pDeviceIndices;
+} VkBindAccelerationStructureMemoryInfoNV;
-typedef struct VkAccelerationStructureMemoryRequirementsInfoNVX {
- VkStructureType sType;
- const void* pNext;
- VkAccelerationStructureNVX accelerationStructure;
-} VkAccelerationStructureMemoryRequirementsInfoNVX;
+typedef struct VkWriteDescriptorSetAccelerationStructureNV {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t accelerationStructureCount;
+ const VkAccelerationStructureNV* pAccelerationStructures;
+} VkWriteDescriptorSetAccelerationStructureNV;
-typedef struct VkPhysicalDeviceRaytracingPropertiesNVX {
+typedef struct VkAccelerationStructureMemoryRequirementsInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkAccelerationStructureMemoryRequirementsTypeNV type;
+ VkAccelerationStructureNV accelerationStructure;
+} VkAccelerationStructureMemoryRequirementsInfoNV;
+
+typedef struct VkPhysicalDeviceRayTracingPropertiesNV {
VkStructureType sType;
void* pNext;
- uint32_t shaderHeaderSize;
+ uint32_t shaderGroupHandleSize;
uint32_t maxRecursionDepth;
- uint32_t maxGeometryCount;
-} VkPhysicalDeviceRaytracingPropertiesNVX;
+ uint32_t maxShaderGroupStride;
+ uint32_t shaderGroupBaseAlignment;
+ uint64_t maxGeometryCount;
+ uint64_t maxInstanceCount;
+ uint64_t maxTriangleCount;
+ uint32_t maxDescriptorSetAccelerationStructures;
+} VkPhysicalDeviceRayTracingPropertiesNV;
-typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNVX)(VkDevice device, const VkAccelerationStructureCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNVX* pAccelerationStructure);
-typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
-typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureScratchMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
-typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNVX)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
-typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
-typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateRaytracingPipelinesNVX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
-typedef VkResult (VKAPI_PTR *PFN_vkGetRaytracingShaderHandlesNVX)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
-typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, size_t dataSize, void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
-typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNVX)(VkDevice device, VkPipeline pipeline, uint32_t shader);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure);
+typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
+typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos);
+typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode);
+typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
+typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
+typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData);
+typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery);
+typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader);
#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV(
VkDevice device,
- const VkAccelerationStructureCreateInfoNVX* pCreateInfo,
+ const VkAccelerationStructureCreateInfoNV* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
- VkAccelerationStructureNVX* pAccelerationStructure);
+ VkAccelerationStructureNV* pAccelerationStructure);
-VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV(
VkDevice device,
- VkAccelerationStructureNVX accelerationStructure,
+ VkAccelerationStructureNV accelerationStructure,
const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNVX(
+VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV(
VkDevice device,
- const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
+ const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo,
VkMemoryRequirements2KHR* pMemoryRequirements);
-VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureScratchMemoryRequirementsNVX(
- VkDevice device,
- const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
- VkMemoryRequirements2KHR* pMemoryRequirements);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV(
VkDevice device,
uint32_t bindInfoCount,
- const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
+ const VkBindAccelerationStructureMemoryInfoNV* pBindInfos);
-VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV(
VkCommandBuffer commandBuffer,
- VkAccelerationStructureTypeNVX type,
- uint32_t instanceCount,
+ const VkAccelerationStructureInfoNV* pInfo,
VkBuffer instanceData,
VkDeviceSize instanceOffset,
- uint32_t geometryCount,
- const VkGeometryNVX* pGeometries,
- VkBuildAccelerationStructureFlagsNVX flags,
VkBool32 update,
- VkAccelerationStructureNVX dst,
- VkAccelerationStructureNVX src,
+ VkAccelerationStructureNV dst,
+ VkAccelerationStructureNV src,
VkBuffer scratch,
VkDeviceSize scratchOffset);
-VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV(
VkCommandBuffer commandBuffer,
- VkAccelerationStructureNVX dst,
- VkAccelerationStructureNVX src,
- VkCopyAccelerationStructureModeNVX mode);
+ VkAccelerationStructureNV dst,
+ VkAccelerationStructureNV src,
+ VkCopyAccelerationStructureModeNV mode);
-VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV(
VkCommandBuffer commandBuffer,
VkBuffer raygenShaderBindingTableBuffer,
VkDeviceSize raygenShaderBindingOffset,
@@ -8167,18 +8374,22 @@
VkBuffer hitShaderBindingTableBuffer,
VkDeviceSize hitShaderBindingOffset,
VkDeviceSize hitShaderBindingStride,
+ VkBuffer callableShaderBindingTableBuffer,
+ VkDeviceSize callableShaderBindingOffset,
+ VkDeviceSize callableShaderBindingStride,
uint32_t width,
- uint32_t height);
+ uint32_t height,
+ uint32_t depth);
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateRaytracingPipelinesNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV(
VkDevice device,
VkPipelineCache pipelineCache,
uint32_t createInfoCount,
- const VkRaytracingPipelineCreateInfoNVX* pCreateInfos,
+ const VkRayTracingPipelineCreateInfoNV* pCreateInfos,
const VkAllocationCallbacks* pAllocator,
VkPipeline* pPipelines);
-VKAPI_ATTR VkResult VKAPI_CALL vkGetRaytracingShaderHandlesNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV(
VkDevice device,
VkPipeline pipeline,
uint32_t firstGroup,
@@ -8186,20 +8397,21 @@
size_t dataSize,
void* pData);
-VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV(
VkDevice device,
- VkAccelerationStructureNVX accelerationStructure,
+ VkAccelerationStructureNV accelerationStructure,
size_t dataSize,
void* pData);
-VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructurePropertiesNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV(
VkCommandBuffer commandBuffer,
- VkAccelerationStructureNVX accelerationStructure,
+ uint32_t accelerationStructureCount,
+ const VkAccelerationStructureNV* pAccelerationStructures,
VkQueryType queryType,
VkQueryPool queryPool,
- uint32_t query);
+ uint32_t firstQuery);
-VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV(
VkDevice device,
VkPipeline pipeline,
uint32_t shader);
@@ -8296,6 +8508,46 @@
uint32_t marker);
#endif
+#define VK_EXT_calibrated_timestamps 1
+#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1
+#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps"
+
+
+typedef enum VkTimeDomainEXT {
+ VK_TIME_DOMAIN_DEVICE_EXT = 0,
+ VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1,
+ VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2,
+ VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3,
+ VK_TIME_DOMAIN_BEGIN_RANGE_EXT = VK_TIME_DOMAIN_DEVICE_EXT,
+ VK_TIME_DOMAIN_END_RANGE_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT,
+ VK_TIME_DOMAIN_RANGE_SIZE_EXT = (VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT - VK_TIME_DOMAIN_DEVICE_EXT + 1),
+ VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkTimeDomainEXT;
+
+typedef struct VkCalibratedTimestampInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkTimeDomainEXT timeDomain;
+} VkCalibratedTimestampInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains);
+typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(
+ VkPhysicalDevice physicalDevice,
+ uint32_t* pTimeDomainCount,
+ VkTimeDomainEXT* pTimeDomains);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT(
+ VkDevice device,
+ uint32_t timestampCount,
+ const VkCalibratedTimestampInfoEXT* pTimestampInfos,
+ uint64_t* pTimestamps,
+ uint64_t* pMaxDeviation);
+#endif
+
#define VK_AMD_shader_core_properties 1
#define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
#define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
@@ -8321,6 +8573,29 @@
+#define VK_AMD_memory_overallocation_behavior 1
+#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1
+#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior"
+
+
+typedef enum VkMemoryOverallocationBehaviorAMD {
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0,
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1,
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2,
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_BEGIN_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD,
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_END_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD,
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_RANGE_SIZE_AMD = (VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD + 1),
+ VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF
+} VkMemoryOverallocationBehaviorAMD;
+
+typedef struct VkDeviceMemoryOverallocationCreateInfoAMD {
+ VkStructureType sType;
+ const void* pNext;
+ VkMemoryOverallocationBehaviorAMD overallocationBehavior;
+} VkDeviceMemoryOverallocationCreateInfoAMD;
+
+
+
#define VK_EXT_vertex_attribute_divisor 1
#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3
#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
@@ -8516,6 +8791,31 @@
VkCheckpointDataNV* pCheckpointData);
#endif
+#define VK_EXT_pci_bus_info 1
+#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 1
+#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info"
+
+typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT {
+ VkStructureType sType;
+ void* pNext;
+ uint16_t pciDomain;
+ uint8_t pciBus;
+ uint8_t pciDevice;
+ uint8_t pciFunction;
+} VkPhysicalDevicePCIBusInfoPropertiesEXT;
+
+
+
+#define VK_GOOGLE_hlsl_functionality1 1
+#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 0
+#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1"
+
+
+#define VK_GOOGLE_decorate_string 1
+#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 0
+#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string"
+
+
#ifdef __cplusplus
}
#endif
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 629ebb1..df86af0 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -556,6 +556,7 @@
"vkGetDisplayModeProperties2KHR",
"vkGetDisplayPlaneCapabilities2KHR",
"vkGetInstanceProcAddr",
+ "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT",
"vkGetPhysicalDeviceDisplayPlaneProperties2KHR",
"vkGetPhysicalDeviceDisplayProperties2KHR",
"vkGetPhysicalDeviceExternalBufferProperties",
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 1f4df1e..f04eb03 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -1149,6 +1149,7 @@
{{else if eq $ext "VK_EXT_direct_mode_display"}}true
{{else if eq $ext "VK_EXT_display_surface_counter"}}true
{{else if eq $ext "VK_EXT_display_control"}}true
+ {{else if eq $ext "VK_FUCHSIA_imagepipe_surface"}}true
{{else if eq $ext "VK_MVK_ios_surface"}}true
{{else if eq $ext "VK_MVK_macos_surface"}}true
{{else if eq $ext "VK_NN_vi_surface"}}true
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 57668a8..3da4336 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -325,6 +325,13 @@
}
};
+template <>
+struct EnumTraits<VkDriverIdKHR> {
+ static uint32_t min() { return VK_DRIVER_ID_BEGIN_RANGE_KHR; }
+ static uint32_t max() { return VK_DRIVER_ID_END_RANGE_KHR; }
+ static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+};
+
// VkSparseImageFormatProperties
template <typename Visitor>