Merge "installd: Implement support for userdata snapshot and restore."
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 9b12a02..99f3739 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -140,6 +140,12 @@
chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
+ # filemap events for iorapd
+ chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+ chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+
# Tracing disabled by default
write /sys/kernel/debug/tracing/tracing_on 0
write /sys/kernel/tracing/tracing_on 0
@@ -165,7 +171,7 @@
chmod 0666 /sys/kernel/tracing/per_cpu/cpu5/trace
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu6/trace
- chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu7/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu7/trace
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu8/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu8/trace
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 6596fa2..ba9a967 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -43,7 +43,6 @@
static void* callAndNotify(void* data) {
Dumpstate& ds = *static_cast<Dumpstate*>(data);
- // TODO(111441001): Return status on listener.
ds.Run();
MYLOGE("Finished Run()\n");
return nullptr;
@@ -98,10 +97,16 @@
return binder::Status::ok();
}
-binder::Status DumpstateService::startBugreport(const android::base::unique_fd& bugreport_fd,
+// TODO(b/111441001): Hook up to consent service & copy final br only if user approves.
+binder::Status DumpstateService::startBugreport(int32_t /* calling_uid */,
+ const std::string& /* calling_package */,
+ const android::base::unique_fd& bugreport_fd,
const android::base::unique_fd& screenshot_fd,
int bugreport_mode,
const sp<IDumpstateListener>& listener) {
+ // TODO(b/111441001):
+ // 1. check DUMP permission (again)?
+ // 2. check if primary user? If non primary user the consent service will reject anyway.
MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
@@ -139,6 +144,9 @@
}
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
+ std::string destination = ds_.options_->bugreport_fd.get() != -1
+ ? StringPrintf("[fd:%d]", ds_.options_->bugreport_fd.get())
+ : ds_.bugreport_internal_dir_.c_str();
dprintf(fd, "id: %d\n", ds_.id_);
dprintf(fd, "pid: %d\n", ds_.pid_);
dprintf(fd, "update_progress: %s\n", ds_.options_->do_progress_updates ? "true" : "false");
@@ -149,8 +157,7 @@
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, "bugreport_internal_dir_: %s\n", ds_.bugreport_internal_dir_.c_str());
+ dprintf(fd, "bugreport_dir: %s\n", destination.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());
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 1705317..b6ba32d 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -42,7 +42,8 @@
bool getSectionDetails,
sp<IDumpstateToken>* returned_token) override;
- binder::Status startBugreport(const android::base::unique_fd& bugreport_fd,
+ binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
+ const android::base::unique_fd& bugreport_fd,
const android::base::unique_fd& screenshot_fd, int bugreport_mode,
const sp<IDumpstateListener>& listener) override;
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 6ac17d8..273a5a6 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -49,7 +49,7 @@
Then run:
```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test
```
And to run just one test (for example, `DumpstateTest.RunCommandNoArgs`):
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index d24c953..2635157 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -59,14 +59,24 @@
// Default mode.
const int BUGREPORT_MODE_DEFAULT = 6;
+ // TODO(b/111441001): Should the args be for the consuming application rather than triggering?
/*
* Starts a bugreport in the background.
*
+ *<p>Shows the user a dialog to get consent for sharing the bugreport with the calling
+ * application. If they deny {@link IDumpstateListener#onError} will be called. If they
+ * consent and bugreport generation is successful artifacts will be copied to the given fds and
+ * {@link IDumpstateListener#onFinished} will be called. If there
+ * are errors in bugreport generation {@link IDumpstateListener#onError} will be called.
+ *
+ * @param callingUid UID of the original application that requested the report.
+ * @param callingPackage package of the original application that requested the report.
* @param bugreportFd the file to which the zipped bugreport should be written
* @param screenshotFd the file to which screenshot should be written; optional
* @param bugreportMode the mode that specifies other run time options; must be one of above
* @param listener callback for updates; optional
*/
- void startBugreport(FileDescriptor bugreportFd, FileDescriptor screenshotFd, int bugreportMode,
- IDumpstateListener listener);
+ void startBugreport(int callingUid, @utf8InCpp String callingPackage,
+ FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+ int bugreportMode, IDumpstateListener listener);
}
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 2966c86..bcd0cb7 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -35,6 +35,9 @@
/* Bugreport encountered a runtime error */
const int BUGREPORT_ERROR_RUNTIME_ERROR = 2;
+ /* User denied consent to share the bugreport with the specified app */
+ const int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3;
+
/**
* Called on an error condition with one of the error codes listed above.
*/
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4e5d68d..4634ecd 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -135,10 +135,6 @@
return fd;
}
-static int OpenForWrite(std::string path) {
- return Open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-}
static int OpenForRead(std::string path) {
return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
@@ -169,17 +165,6 @@
return false;
}
-static bool CopyFileToFile(const std::string& input_file, const std::string& output_file) {
- if (input_file == output_file) {
- MYLOGD("Skipping copying bugreport file since the destination is the same (%s)\n",
- output_file.c_str());
- return false;
- }
-
- MYLOGD("Going to copy bugreport file (%s) to %s\n", input_file.c_str(), output_file.c_str());
- android::base::unique_fd out_fd(OpenForWrite(output_file));
- return CopyFileToFd(input_file, out_fd.get());
-}
} // namespace
} // namespace os
@@ -475,47 +460,6 @@
return false;
}
-static void dump_systrace() {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
- return;
- }
- std::string systrace_path = ds.GetPath("-systrace.txt");
- if (systrace_path.empty()) {
- MYLOGE("Not dumping systrace because path is empty\n");
- return;
- }
- const char* path = "/sys/kernel/debug/tracing/tracing_on";
- long int is_tracing;
- if (read_file_as_long(path, &is_tracing)) {
- return; // error already logged
- }
- if (is_tracing <= 0) {
- MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
- return;
- }
-
- MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
- systrace_path.c_str());
- if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
- CommandOptions::WithTimeout(120).Build())) {
- MYLOGE("systrace timed out, its zip entry will be incomplete\n");
- // TODO: RunCommand tries to kill the process, but atrace doesn't die
- // peacefully; ideally, we should call strace to stop itself, but there is no such option
- // yet (just a --async_stop, which stops and dump
- // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
- // MYLOGE("could not stop systrace ");
- // }
- }
- if (!ds.AddZipEntry("systrace.txt", systrace_path)) {
- MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
- } else {
- if (remove(systrace_path.c_str())) {
- MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
- }
- }
-}
-
static bool skip_not_stat(const char *path) {
static const char stat[] = "/stat";
size_t len = strlen(path);
@@ -1446,12 +1390,8 @@
/* Dumps state for the default case. Returns true if everything went fine. */
static bool DumpstateDefault() {
- // Dumps systrace right away, otherwise it will be filled with unnecessary events.
- // First try to dump anrd trace if the daemon is running. Otherwise, dump
- // the raw trace.
- if (!dump_anrd_trace()) {
- dump_systrace();
- }
+ // Try to dump anrd trace if the daemon is running.
+ dump_anrd_trace();
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
@@ -1851,16 +1791,9 @@
static void PrepareToWriteToFile() {
MaybeResolveSymlink(&ds.bugreport_internal_dir_);
- std::string base_name_part1 = "bugreport";
- if (!ds.options_->use_outfile.empty()) {
- ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
- base_name_part1 = basename(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_ =
- StringPrintf("%s-%s-%s", base_name_part1.c_str(), device_name.c_str(), build_id.c_str());
+ ds.base_name_ = StringPrintf("bugreport-%s-%s", 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_));
@@ -1883,17 +1816,16 @@
std::string destination = ds.options_->bugreport_fd.get() != -1
? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
- : ds.bugreport_dir_.c_str();
+ : ds.bugreport_internal_dir_.c_str();
MYLOGD(
"Bugreport dir: %s\n"
- "Internal Bugreport dir: %s\n"
"Base name: %s\n"
"Suffix: %s\n"
"Log path: %s\n"
"Temporary path: %s\n"
"Screenshot path: %s\n",
- destination.c_str(), ds.bugreport_internal_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());
+ destination.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 (ds.options_->do_zip_file) {
ds.path_ = ds.GetPath(".zip");
@@ -1960,18 +1892,13 @@
}
}
// The zip file lives in an internal directory. Copy it over to output.
- bool copy_succeeded = false;
if (ds.options_->bugreport_fd.get() != -1) {
- copy_succeeded = android::os::CopyFileToFd(ds.path_, ds.options_->bugreport_fd.get());
- } else {
- ds.final_path_ = ds.GetPath(ds.bugreport_dir_, ".zip");
- copy_succeeded = android::os::CopyFileToFile(ds.path_, ds.final_path_);
- }
- if (copy_succeeded) {
- if (remove(ds.path_.c_str())) {
+ bool copy_succeeded =
+ android::os::CopyFileToFd(ds.path_, ds.options_->bugreport_fd.get());
+ if (!copy_succeeded && remove(ds.path_.c_str())) {
MYLOGE("remove(%s): %s", ds.path_.c_str(), strerror(errno));
}
- }
+ } // else - the file just remains in the internal directory.
}
}
if (do_text_file) {
@@ -1997,8 +1924,8 @@
/* Broadcasts that we are done with the bugreport */
static void SendBugreportFinishedBroadcast() {
// TODO(b/111441001): use callback instead of broadcast.
- if (!ds.final_path_.empty()) {
- MYLOGI("Final bugreport path: %s\n", ds.final_path_.c_str());
+ if (!ds.path_.empty()) {
+ MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
// clang-format off
std::vector<std::string> am_args = {
@@ -2006,7 +1933,7 @@
"--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.BUGREPORT", ds.final_path_,
+ "--es", "android.intent.extra.BUGREPORT", ds.path_,
"--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
};
// clang-format on
@@ -2028,7 +1955,7 @@
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.final_path_));
+ am_args.push_back(SHA256_file_hash(ds.path_));
SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
} else {
SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
@@ -2166,7 +2093,6 @@
MYLOGI("wifi_only: %d\n", options.wifi_only);
MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
MYLOGI("fd: %d\n", options.bugreport_fd.get());
- MYLOGI("use_outfile: %s\n", options.use_outfile.c_str());
MYLOGI("extra_options: %s\n", options.extra_options.c_str());
MYLOGI("args: %s\n", options.args.c_str());
MYLOGI("notification_title: %s\n", options.notification_title.c_str());
@@ -2197,7 +2123,9 @@
// clang-format off
case 'd': do_add_date = true; break;
case 'z': do_zip_file = true; break;
- case 'o': use_outfile = optarg; break;
+ // o=use_outfile not supported anymore.
+ // TODO(b/111441001): Remove when all callers have migrated.
+ case 'o': break;
case 's': use_socket = true; break;
case 'S': use_control_socket = true; break;
case 'v': show_header_only = true; break;
@@ -2238,9 +2166,7 @@
return false;
}
- bool has_out_file_options = !use_outfile.empty() || bugreport_fd.get() != -1;
- if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) &&
- !has_out_file_options) {
+ if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
return false;
}
@@ -2262,6 +2188,28 @@
options_ = std::move(options);
}
+Dumpstate::RunStatus Dumpstate::Run() {
+ Dumpstate::RunStatus status = RunInternal();
+ if (listener_ != nullptr) {
+ switch (status) {
+ case Dumpstate::RunStatus::OK:
+ // TODO(b/111441001): duration argument does not make sense. Remove.
+ listener_->onFinished(0 /* duration */, options_->notification_title,
+ options_->notification_description);
+ break;
+ case Dumpstate::RunStatus::HELP:
+ break;
+ case Dumpstate::RunStatus::INVALID_INPUT:
+ listener_->onError(android::os::IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+ break;
+ case Dumpstate::RunStatus::ERROR:
+ listener_->onError(android::os::IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
+ break;
+ }
+ }
+ return status;
+}
+
/*
* Dumps relevant information to a bugreport based on the given options.
*
@@ -2280,10 +2228,10 @@
* If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
* gets added to the archive.
*
- * Bugreports are first generated in a local directory and later copied to the caller's fd or
- * directory.
+ * Bugreports are first generated in a local directory and later copied to the caller's fd if
+ * supplied.
*/
-Dumpstate::RunStatus Dumpstate::Run() {
+Dumpstate::RunStatus Dumpstate::RunInternal() {
LogDumpOptions(*options_);
if (!options_->ValidateOptions()) {
MYLOGE("Invalid options specified\n");
@@ -2322,7 +2270,7 @@
}
// Redirect output if needed
- bool is_redirecting = !options_->use_socket && !options_->use_outfile.empty();
+ bool is_redirecting = options_->OutputToFile();
// TODO: temporarily set progress until it's part of the Dumpstate constructor
std::string stats_path =
@@ -2473,7 +2421,7 @@
}
/* rename or zip the (now complete) .tmp file to its final location */
- if (!options_->use_outfile.empty()) {
+ if (options_->OutputToFile()) {
FinalizeFile();
}
@@ -2488,6 +2436,7 @@
/* tell activity manager we're done */
if (options_->do_broadcast) {
SendBugreportFinishedBroadcast();
+ // Note that listener_ is notified in Run();
}
MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 529111e..3dfe4e9 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -331,6 +331,7 @@
bool do_add_date = false;
bool do_zip_file = false;
bool do_vibrate = true;
+ // Writes bugreport content to a socket; only flatfile format is supported.
bool use_socket = false;
bool use_control_socket = false;
bool do_fb = false;
@@ -342,13 +343,11 @@
bool wifi_only = false;
// Whether progress updates should be published.
bool do_progress_updates = false;
- // File descriptor to output zip file. Takes precedence over use_outfile.
+ // File descriptor to output zip file.
android::base::unique_fd bugreport_fd;
// File descriptor to screenshot file.
// TODO(b/111441001): Use this fd.
android::base::unique_fd screenshot_fd;
- // Partial path to output file.
- std::string use_outfile;
// TODO: rename to MODE.
// Extra options passed as system property.
std::string extra_options;
@@ -367,6 +366,13 @@
/* Returns true if the options set so far are consistent. */
bool ValidateOptions() const;
+
+ /* Returns if options specified require writing bugreport to a file */
+ bool OutputToFile() const {
+ // If we are not writing to socket, we will write to a file. If bugreport_fd is
+ // specified, it is preferred. If not bugreport is written to /bugreports.
+ return !use_socket;
+ }
};
// TODO: initialize fields on constructor
@@ -424,13 +430,6 @@
// Full path of the temporary file containing the screenshot (when requested).
std::string screenshot_path_;
- // TODO(b/111441001): remove when obsolete.
- // Full path of the final zip file inside the caller-specified directory, if available.
- std::string final_path_;
-
- // The caller-specified directory, if available.
- std::string bugreport_dir_;
-
// Pointer to the zipped file.
std::unique_ptr<FILE, int (*)(FILE*)> zip_file{nullptr, fclose};
@@ -449,6 +448,8 @@
std::vector<DumpData> anr_data_;
private:
+ RunStatus RunInternal();
+
// Used by GetInstance() only.
explicit Dumpstate(const std::string& version = VERSION_CURRENT);
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 98ee1b0..0302c46 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -173,7 +173,6 @@
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);
@@ -191,7 +190,6 @@
const_cast<char*>("-S"),
const_cast<char*>("-d"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -201,7 +199,6 @@
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.use_control_socket);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -228,7 +225,6 @@
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_EQ("", options_.use_outfile);
EXPECT_FALSE(options_.do_add_date);
EXPECT_FALSE(options_.do_zip_file);
EXPECT_FALSE(options_.use_control_socket);
@@ -247,7 +243,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
property_set("dumpstate.options", "bugreportfull");
@@ -259,7 +254,6 @@
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_broadcast);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -279,7 +273,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -294,7 +287,6 @@
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_start_service);
EXPECT_FALSE(options_.do_fb);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -312,7 +304,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -327,7 +318,6 @@
EXPECT_TRUE(options_.is_remote_mode);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_FALSE(options_.do_fb);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_FALSE(options_.use_control_socket);
@@ -344,7 +334,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -359,7 +348,6 @@
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_start_service);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -377,7 +365,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -391,7 +378,6 @@
EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.telephony_only);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -410,7 +396,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -424,7 +409,6 @@
EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.wifi_only);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -444,7 +428,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -457,7 +440,6 @@
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_broadcast);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -475,7 +457,6 @@
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"),
@@ -488,7 +469,6 @@
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);
@@ -527,7 +507,6 @@
// 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);
}
@@ -562,15 +541,21 @@
TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
options_.do_zip_file = true;
+ // Writing to socket = !writing to file.
+ options_.use_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.use_outfile = "a/b/c";
+
+ options_.use_socket = false;
EXPECT_TRUE(options_.ValidateOptions());
}
TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
options_.do_broadcast = true;
+ // Writing to socket = !writing to file.
+ options_.use_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.use_outfile = "a/b/c";
+
+ options_.use_socket = false;
EXPECT_TRUE(options_.ValidateOptions());
}
@@ -579,13 +564,11 @@
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;
@@ -599,7 +582,6 @@
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());
}
@@ -656,8 +638,9 @@
}
if (update_progress) {
- message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
- listener_name.c_str(), progress, max);
+ message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
+ listener_name.c_str(), progress, max,
+ (100 * progress / max));
}
return message;
@@ -816,12 +799,14 @@
SetProgress(0, 30);
EXPECT_CALL(*listener, onProgressUpdated(20));
+ EXPECT_CALL(*listener, onProgress(66)); // 20/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
EXPECT_CALL(*listener, onProgressUpdated(30));
+ EXPECT_CALL(*listener, onProgress(100)); // 35/35 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -830,6 +815,7 @@
// Run a command that will increase maximum timeout.
EXPECT_CALL(*listener, onProgressUpdated(31));
EXPECT_CALL(*listener, onMaxProgressUpdated(37));
+ EXPECT_CALL(*listener, onProgress(83)); // 31/37 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -838,6 +824,7 @@
// Make sure command ran while in dry_run is counted.
SetDryRun(true);
EXPECT_CALL(*listener, onProgressUpdated(35));
+ EXPECT_CALL(*listener, onProgress(94)); // 35/37 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
EXPECT_THAT(out, IsEmpty());
@@ -854,6 +841,7 @@
// First update should always be sent.
EXPECT_CALL(*listener, onProgressUpdated(1));
+ EXPECT_CALL(*listener, onProgress(12)); // 1/12 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -866,6 +854,7 @@
// Third update should be sent because it reaches threshold (6 - 1 = 5).
EXPECT_CALL(*listener, onProgressUpdated(6));
+ EXPECT_CALL(*listener, onProgress(75)); // 6/8 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -1105,6 +1094,7 @@
SetProgress(0, 30);
EXPECT_CALL(*listener, onProgressUpdated(5));
+ EXPECT_CALL(*listener, onProgress(16)); // 5/30 %
EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
std::string progress_message =
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 990fd43..528e43d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -949,16 +949,22 @@
fsync(control_socket_fd_);
}
+ int percent = 100 * progress / max;
if (listener_ != nullptr) {
- if (progress % 100 == 0) {
- // We don't want to spam logcat, so only log multiples of 100.
- MYLOGD("Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+ if (percent % 5 == 0) {
+ // We don't want to spam logcat, so only log multiples of 5.
+ MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
+ percent);
} else {
// stderr is ignored on normal invocations, but useful when calling
// /system/bin/dumpstate directly for debuggging.
- fprintf(stderr, "Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+ fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
+ progress, max, percent);
}
+ // TODO(b/111441001): Remove in favor of onProgress
listener_->onProgressUpdated(progress);
+
+ listener_->onProgress(percent);
}
}
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 2e9701f..a6f77aa 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -18,6 +18,7 @@
"dexopt.cpp",
"globals.cpp",
"utils.cpp",
+ "view_compiler.cpp",
":installd_aidl",
],
header_libs: [
@@ -30,6 +31,7 @@
"libcutils",
"liblog",
"liblogwrap",
+ "libprocessgroup",
"libselinux",
"libutils",
],
@@ -168,6 +170,7 @@
"libbase",
"libcutils",
"liblog",
+ "libprocessgroup",
"libutils",
],
}
@@ -188,6 +191,7 @@
"globals.cpp",
"otapreopt.cpp",
"utils.cpp",
+ "view_compiler.cpp",
],
header_libs: ["dex2oat_headers"],
@@ -204,6 +208,7 @@
"libcutils",
"liblog",
"liblogwrap",
+ "libprocessgroup",
"libselinux",
"libutils",
],
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index d817370..51f30da 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -61,6 +61,7 @@
#include "installd_deps.h"
#include "otapreopt_utils.h"
#include "utils.h"
+#include "view_compiler.h"
#include "CacheTracker.h"
#include "MatchExtensionGen.h"
@@ -1999,6 +2000,17 @@
return res ? error(res, error_msg) : ok();
}
+binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath,
+ const std::string& packageName,
+ const std ::string& outDexFile, int uid,
+ bool* _aidl_return) {
+ const char* apk_path = apkPath.c_str();
+ const char* package_name = packageName.c_str();
+ const char* out_dex_file = outDexFile.c_str();
+ *_aidl_return = android::installd::view_compiler(apk_path, package_name, out_dex_file, uid);
+ return *_aidl_return ? ok() : error("viewcompiler failed");
+}
+
binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
std::lock_guard<std::recursive_mutex> lock(mLock);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 123859a..098a0c2 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -95,6 +95,9 @@
const std::unique_ptr<std::string>& dexMetadataPath,
const std::unique_ptr<std::string>& compilationReason);
+ binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName,
+ const std::string& outDexFile, int uid, bool* _aidl_return);
+
binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 8489b7a..3d093b8 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -55,6 +55,8 @@
@nullable @utf8InCpp String profileName,
@nullable @utf8InCpp String dexMetadataPath,
@nullable @utf8InCpp String compilationReason);
+ boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName,
+ @utf8InCpp String outDexFile, int uid);
void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 32c1313..e3a35c7 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -43,6 +43,7 @@
#include <log/log.h> // TODO: Move everything to base/logging.
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
+#include <processgroup/sched_policy.h>
#include <selinux/android.h>
#include <system/thread_defs.h>
@@ -627,27 +628,6 @@
}
}
-static void drop_capabilities(uid_t uid) {
- if (setgid(uid) != 0) {
- PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
- exit(DexoptReturnCodes::kSetGid);
- }
- if (setuid(uid) != 0) {
- PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
- exit(DexoptReturnCodes::kSetUid);
- }
- // drop capabilities
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- if (capset(&capheader, &capdata[0]) < 0) {
- PLOG(ERROR) << "capset failed";
- exit(DexoptReturnCodes::kCapSet);
- }
-}
-
static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0;
static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1;
static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2;
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 739f33f..9c9db0f 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -28,6 +28,7 @@
"libbinder",
"libcrypto",
"libcutils",
+ "libprocessgroup",
"libselinux",
"libutils",
],
@@ -50,6 +51,7 @@
"libbinder",
"libcrypto",
"libcutils",
+ "libprocessgroup",
"libselinux",
"libutils",
],
@@ -72,6 +74,7 @@
"libbinder",
"libcrypto",
"libcutils",
+ "libprocessgroup",
"libselinux",
"libutils",
],
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 6582ba5..24f5eab 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -20,6 +20,7 @@
#include <fcntl.h>
#include <fts.h>
#include <stdlib.h>
+#include <sys/capability.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/xattr.h>
@@ -34,6 +35,7 @@
#include <log/log.h>
#include <private/android_filesystem_config.h>
+#include "dexopt_return_codes.h"
#include "globals.h" // extern variables.
#ifndef LOG_TAG
@@ -1084,5 +1086,26 @@
}
}
+void drop_capabilities(uid_t uid) {
+ if (setgid(uid) != 0) {
+ PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
+ exit(DexoptReturnCodes::kSetGid);
+ }
+ if (setuid(uid) != 0) {
+ PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
+ exit(DexoptReturnCodes::kSetUid);
+ }
+ // drop capabilities
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ if (capset(&capheader, &capdata[0]) < 0) {
+ PLOG(ERROR) << "capset failed";
+ exit(DexoptReturnCodes::kCapSet);
+ }
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index a36fce1..430f515 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -147,6 +147,8 @@
// It returns true if there were no errors at all, and false otherwise.
bool collect_profiles(std::vector<std::string>* profiles_paths);
+void drop_capabilities(uid_t uid);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp
new file mode 100644
index 0000000..f1ac717
--- /dev/null
+++ b/cmds/installd/view_compiler.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 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 "view_compiler.h"
+
+#include <string>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "android-base/unique_fd.h"
+
+namespace android {
+namespace installd {
+
+using base::unique_fd;
+
+bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
+ int uid) {
+ CHECK(apk_path != nullptr);
+ CHECK(package_name != nullptr);
+ CHECK(out_dex_file != nullptr);
+
+ // viewcompiler won't have permission to open anything, so we have to open the files first
+ // and pass file descriptors.
+
+ // Open input file
+ unique_fd infd{open(apk_path, 0)};
+ if (infd.get() < 0) {
+ PLOG(ERROR) << "Could not open input file: " << apk_path;
+ return false;
+ }
+
+ // Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so
+ // we close stdout and open it towards the right output.
+ unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY, 0644)};
+ if (outfd.get() < 0) {
+ PLOG(ERROR) << "Could not open output file: " << out_dex_file;
+ return false;
+ }
+ if (fchmod(outfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
+ PLOG(ERROR) << "Could not change output file permissions";
+ return false;
+ }
+ if (close(STDOUT_FILENO) != 0) {
+ PLOG(ERROR) << "Could not close stdout";
+ return false;
+ }
+ if (dup2(outfd, STDOUT_FILENO) < 0) {
+ PLOG(ERROR) << "Could not duplicate output file descriptor";
+ return false;
+ }
+
+ // Prepare command line arguments for viewcompiler
+ std::string args[] = {"/system/bin/viewcompiler",
+ "--apk",
+ "--infd",
+ android::base::StringPrintf("%d", infd.get()),
+ "--dex",
+ "--package",
+ package_name};
+ char* const argv[] = {const_cast<char*>(args[0].c_str()), const_cast<char*>(args[1].c_str()),
+ const_cast<char*>(args[2].c_str()), const_cast<char*>(args[3].c_str()),
+ const_cast<char*>(args[4].c_str()), const_cast<char*>(args[5].c_str()),
+ const_cast<char*>(args[6].c_str()), nullptr};
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ // Now that we've opened the files we need, drop privileges.
+ drop_capabilities(uid);
+ execv("/system/bin/viewcompiler", argv);
+ _exit(1);
+ }
+
+ return wait_child(pid) == 0;
+}
+
+} // namespace installd
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/cmds/installd/view_compiler.h
similarity index 66%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to cmds/installd/view_compiler.h
index e6ac6bf..f7c6e57 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/cmds/installd/view_compiler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#ifndef VIEW_COMPILER_H_
+#define VIEW_COMPILER_H_
namespace android {
-namespace mock {
+namespace installd {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
+ int uid);
-} // namespace mock
+} // namespace installd
} // namespace android
+
+#endif // VIEW_COMPILER_H_
\ No newline at end of file
diff --git a/cmds/surfacereplayer/OWNERS b/cmds/surfacereplayer/OWNERS
new file mode 100644
index 0000000..cc4c842
--- /dev/null
+++ b/cmds/surfacereplayer/OWNERS
@@ -0,0 +1,2 @@
+mathias@google.com
+racarr@google.com
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index 2ed1cca..0ce50f2 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -140,6 +140,8 @@
kHdcpV2_1,
// HDCP version 2.2 Type 1.
kHdcpV2_2,
+ // HDCP version 2.3 Type 1.
+ kHdcpV2_3,
// No digital output, implicitly secure
kHdcpNoOutput = 0x7fff
};
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index cfd2b40..214559d 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -774,7 +774,8 @@
AKEYCODE_THUMBS_UP = 286,
/** Thumbs down key. Apps can use this to let user downvote content. */
AKEYCODE_THUMBS_DOWN = 287,
- /** Consumed by system to switch current viewer profile. */
+ /** Used to switch current account that is consuming content.
+ * May be consumed by system to switch current viewer profile. */
AKEYCODE_PROFILE_SWITCH = 288
// NOTE: If you add a new keycode here you must also add it to several other files.
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 05d96ff..d31d1f1 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -112,15 +112,25 @@
#if __ANDROID_API__ >= 29
+/**
+ * Possible values of the flags argument to android_res_nsend and android_res_nquery.
+ * Values are ORed together.
+ */
enum ResNsendFlags : uint32_t {
- // Send a single request to a single resolver and fail on timeout or network errors
+ /**
+ * Send a single request to a single resolver and fail on timeout or network errors
+ */
ANDROID_RESOLV_NO_RETRY = 1 << 0,
- // Do not cache the result of the lookup. The lookup may return a result that is already
- // in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+ /**
+ * Do not cache the result of the lookup. The lookup may return a result that is already
+ * in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+ */
ANDROID_RESOLV_NO_CACHE_STORE = 1 << 1,
- // Don't lookup the request in cache, do not write back the response into the cache
+ /**
+ * Don't lookup the request in cache.
+ */
ANDROID_RESOLV_NO_CACHE_LOOKUP = 1 << 2,
};
@@ -136,8 +146,7 @@
* POSIX error code (see errno.h) if an immediate error occurs.
*/
int android_res_nquery(net_handle_t network,
- const char *dname, int ns_class, int ns_type,
- enum ResNsendFlags flags) __INTRODUCED_IN(29);
+ const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29);
/**
* Issue the query |msg| on the given |network|.
@@ -148,10 +157,11 @@
* POSIX error code (see errno.h) if an immediate error occurs.
*/
int android_res_nsend(net_handle_t network,
- const uint8_t *msg, size_t msglen, enum ResNsendFlags flags) __INTRODUCED_IN(29);
+ const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29);
/**
* Read a result for the query associated with the |fd| descriptor.
+ * Closes |fd| before returning.
*
* Returns:
* < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 005564d..1a1b010 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -64,6 +64,7 @@
#define ASENSOR_RESOLUTION_INVALID (nanf(""))
#define ASENSOR_FIFO_COUNT_INVALID (-1)
#define ASENSOR_DELAY_INVALID INT32_MIN
+#define ASENSOR_INVALID (-1)
/* (Keep in sync with hardware/sensors-base.h and Sensor.java.) */
@@ -208,6 +209,35 @@
*/
ASENSOR_TYPE_HEART_BEAT = 31,
/**
+ * This sensor type is for delivering additional sensor information aside
+ * from sensor event data.
+ *
+ * Additional information may include:
+ * - {@link ASENSOR_ADDITIONAL_INFO_INTERNAL_TEMPERATURE}
+ * - {@link ASENSOR_ADDITIONAL_INFO_SAMPLING}
+ * - {@link ASENSOR_ADDITIONAL_INFO_SENSOR_PLACEMENT}
+ * - {@link ASENSOR_ADDITIONAL_INFO_UNTRACKED_DELAY}
+ * - {@link ASENSOR_ADDITIONAL_INFO_VEC3_CALIBRATION}
+ *
+ * This type will never bind to a sensor. In other words, no sensor in the
+ * sensor list can have the type {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
+ *
+ * If a device supports the sensor additional information feature, it will
+ * report additional information events via {@link ASensorEvent} and will
+ * have {@link ASensorEvent#type} set to
+ * {@link ASENSOR_TYPE_ADDITIONAL_INFO} and {@link ASensorEvent#sensor} set
+ * to the handle of the reporting sensor.
+ *
+ * Additional information reports consist of multiple frames ordered by
+ * {@link ASensorEvent#timestamp}. The first frame in the report will have
+ * a {@link AAdditionalInfoEvent#type} of
+ * {@link ASENSOR_ADDITIONAL_INFO_BEGIN}, and the last frame in the report
+ * will have a {@link AAdditionalInfoEvent#type} of
+ * {@link ASENSOR_ADDITIONAL_INFO_END}.
+ *
+ */
+ ASENSOR_TYPE_ADDITIONAL_INFO = 33,
+ /**
* {@link ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT}
*/
ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT = 34,
@@ -273,6 +303,51 @@
ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER = 2
};
+/**
+ * Sensor Additional Info Types.
+ *
+ * Used to populate {@link AAdditionalInfoEvent#type}.
+ */
+enum {
+ /** Marks the beginning of additional information frames */
+ ASENSOR_ADDITIONAL_INFO_BEGIN = 0,
+
+ /** Marks the end of additional information frames */
+ ASENSOR_ADDITIONAL_INFO_END = 1,
+
+ /**
+ * Estimation of the delay that is not tracked by sensor timestamps. This
+ * includes delay introduced by sensor front-end filtering, data transport,
+ * etc.
+ * float[2]: delay in seconds, standard deviation of estimated value
+ */
+ ASENSOR_ADDITIONAL_INFO_UNTRACKED_DELAY = 0x10000,
+
+ /** float: Celsius temperature */
+ ASENSOR_ADDITIONAL_INFO_INTERNAL_TEMPERATURE,
+
+ /**
+ * First three rows of a homogeneous matrix, which represents calibration to
+ * a three-element vector raw sensor reading.
+ * float[12]: 3x4 matrix in row major order
+ */
+ ASENSOR_ADDITIONAL_INFO_VEC3_CALIBRATION,
+
+ /**
+ * Location and orientation of sensor element in the device frame: origin is
+ * the geometric center of the mobile device screen surface; the axis
+ * definition corresponds to Android sensor definitions.
+ * float[12]: 3x4 matrix in row major order
+ */
+ ASENSOR_ADDITIONAL_INFO_SENSOR_PLACEMENT,
+
+ /**
+ * float[2]: raw sample period in seconds,
+ * standard deviation of sampling period
+ */
+ ASENSOR_ADDITIONAL_INFO_SAMPLING,
+};
+
/*
* A few useful constants
*/
@@ -341,7 +416,7 @@
int32_t handle;
} ADynamicSensorEvent;
-typedef struct {
+typedef struct AAdditionalInfoEvent {
int32_t type;
int32_t serial;
union {
@@ -444,6 +519,7 @@
* - ASensor_getStringType()
* - ASensor_getReportingMode()
* - ASensor_isWakeUpSensor()
+ * - ASensor_getHandle()
*/
typedef struct ASensor ASensor;
/**
@@ -785,6 +861,24 @@
int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26);
#endif /* __ANDROID_API__ >= 26 */
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+/**
+ * Returns the sensor's handle.
+ *
+ * The handle identifies the sensor within the system and is included in the
+ * {@link ASensorEvent#sensor} field of sensor events, including those sent with type
+ * {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
+ *
+ * A sensor's handle is able to be used to map {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to the
+ * sensor that generated the event.
+ *
+ * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as
+ * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists
+ * between the values.
+ */
+int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(__ANDROID_API_Q__);
+#endif /* __ANDROID_API__ >= ANDROID_API_Q__ */
+
#ifdef __cplusplus
};
#endif
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
new file mode 100644
index 0000000..13b630b
--- /dev/null
+++ b/include/android/surface_control.h
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NativeActivity Native Activity
+ * @{
+ */
+
+/**
+ * @file surface_control.h
+ */
+
+#ifndef ANDROID_SURFACE_CONTROL_H
+#define ANDROID_SURFACE_CONTROL_H
+
+#include <sys/cdefs.h>
+
+#include <android/hardware_buffer.h>
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+struct ASurfaceControl;
+
+/**
+ * The SurfaceControl API can be used to provide a heirarchy of surfaces for
+ * composition to the system compositor. ASurfaceControl represents a content node in
+ * this heirarchy.
+ */
+typedef struct ASurfaceControl ASurfaceControl;
+
+/*
+ * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent.
+ * |debug_name| is a debug name associated with this surface. It can be used to
+ * identify this surface in the SurfaceFlinger's layer tree. It must not be
+ * null.
+ *
+ * The caller takes ownership of the ASurfaceControl returned and must release it
+ * using ASurfaceControl_release below.
+ */
+ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name)
+ __INTRODUCED_IN(29);
+
+ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name)
+ __INTRODUCED_IN(29);
+
+/**
+ * Destroys the |surface_control| object. After releasing the ASurfaceControl the caller no longer
+ * has ownership of the AsurfaceControl.
+ */
+void ASurfaceControl_destroy(ASurfaceControl* surface_control) __INTRODUCED_IN(29);
+
+struct ASurfaceTransaction;
+
+/**
+ * ASurfaceTransaction is a collection of updates to the surface tree that must
+ * be applied atomically.
+ */
+typedef struct ASurfaceTransaction ASurfaceTransaction;
+
+/**
+ * The caller takes ownership of the transaction and must release it using
+ * ASurfaceControl_delete below.
+ */
+ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29);
+
+/**
+ * Destroys the |transaction| object.
+ */
+void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+
+/**
+ * Applies the updates accumulated in |transaction|.
+ *
+ * Note that the transaction is guaranteed to be applied atomically. The
+ * transactions which are applied on the same thread are also guaranteed to be
+ * applied in order.
+ */
+void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+
+/**
+ * Since the transactions are applied asynchronously, the
+ * ASurfaceTransaction_OnComplete callback can be used to be notified when a frame
+ * including the updates in a transaction was presented.
+ *
+ * |context| is the optional context provided by the client that is passed into
+ * the callback.
+ * |present_fence| is the sync fence that signals when the transaction has been presented.
+ * The recipient of the callback takes ownership of the present_fence and is responsible for closing
+ * it.
+ *
+ * It is safe to assume that once the present fence singals, that reads for all buffers,
+ * submitted in previous transactions, which are not in the surface tree after a transaction is
+ * applied, are finished and the buffers may be reused.
+ *
+ * THREADING
+ * The transaction completed callback can be invoked on any thread.
+ */
+typedef void (*ASurfaceTransaction_OnComplete)(void* context, int32_t present_fence);
+
+/**
+ * Sets the callback that will be invoked when the updates from this transaction
+ * are presented. For details on the callback semantics and data, see the
+ * comments on the ASurfaceTransaction_OnComplete declaration above.
+ */
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context,
+ ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
+
+/* Parameter for ASurfaceTransaction_setVisibility */
+enum {
+ ASURFACE_TRANSACTION_VISIBILITY_HIDE = 0,
+ ASURFACE_TRANSACTION_VISIBILITY_SHOW = 1,
+};
+/**
+ * Updates the visibility of |surface_control|. If show is set to
+ * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will
+ * be hidden.
+ */
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, int8_t visibility)
+ __INTRODUCED_IN(29);
+
+/**
+ * Updates the z order index for |surface_control|. Note that the z order for a surface
+ * is relative to other surfaces which are siblings of this surface. The behavior of sibilings with
+ * the same z order is undefined.
+ *
+ * Z orders may be from MIN_INT32 to MAX_INT32. A layer's default z order index is 0.
+ */
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, int32_t z_order)
+ __INTRODUCED_IN(29);
+
+/**
+ * Updates the AHardwareBuffer displayed for |surface_control|. If not -1, the
+ * fence_fd should be a file descriptor that is signaled when all pending work
+ * for the buffer is complete and the buffer can be safely read.
+ *
+ * The frameworks takes ownership of the |fence_fd| passed and is responsible
+ * for closing it.
+ */
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, AHardwareBuffer* buffer,
+ int fence_fd = -1) __INTRODUCED_IN(29);
+
+/**
+ * |source| the sub-rect within the buffer's content to be rendered inside the surface's area
+ * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
+ * and height must be > 0.
+ *
+ * |destination| specifies the rect in the parent's space where this surface will be drawn. The post
+ * source rect bounds are scaled to fit the destination rect. The surface's destination rect is
+ * clipped by the bounds of its parent. The destination rect's width and height must be > 0.
+ *
+ * |transform| the transform applied after the source rect is applied to the buffer. This parameter
+ * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_*
+ * enum.
+ */
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, const ARect& source,
+ const ARect& destination, int32_t transform)
+ __INTRODUCED_IN(29);
+
+
+/* Parameter for ASurfaceTransaction_setBufferTransparency */
+enum {
+ ASURFACE_TRANSACTION_TRANSPARENCY_TRANSPARENT = 0,
+ ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT = 1,
+ ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE = 2,
+};
+/**
+ * Updates whether the content for the buffer associated with this surface is
+ * completely opaque. If true, every pixel of content inside the buffer must be
+ * opaque or visual errors can occur.
+ */
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, int8_t transparency)
+ __INTRODUCED_IN(29);
+
+/**
+ * Updates the region for the content on this surface updated in this
+ * transaction. If unspecified, the complete surface is assumed to be damaged.
+ */
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, const ARect rects[],
+ uint32_t count) __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/input/Input.h b/include/input/Input.h
index 2c4a511..805957a 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -241,6 +241,11 @@
DEEP_PRESS = 2,
};
+/**
+ * String representation of MotionClassification
+ */
+const char* motionClassificationToString(MotionClassification classification);
+
/*
* Pointer coordinate data.
*/
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index dddbfb0..63606e5 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -105,8 +105,9 @@
int32_t flags;
int32_t metaState;
int32_t buttonState;
+ MotionClassification classification; // base type: uint8_t
+ uint8_t empty2[3];
int32_t edgeFlags;
- uint32_t empty2;
nsecs_t downTime __attribute__((aligned(8)));
float xOffset;
float yOffset;
@@ -271,6 +272,7 @@
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
+ MotionClassification classification,
float xOffset,
float yOffset,
float xPrecision,
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index a20154f..ad8287c 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -25,4 +25,9 @@
host_supported: true,
vendor_available: true,
export_include_dirs: ["include"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index f6cc3af..96ee295 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -86,6 +86,10 @@
class BBinder::Extras
{
public:
+ // unlocked objects
+ bool mRequestingSid = false;
+
+ // for below objects
Mutex mLock;
BpBinder::ObjectManager mObjects;
};
@@ -163,19 +167,8 @@
const void* objectID, void* object, void* cleanupCookie,
object_cleanup_func func)
{
- Extras* e = mExtras.load(std::memory_order_acquire);
-
- if (!e) {
- e = new Extras;
- Extras* expected = nullptr;
- if (!mExtras.compare_exchange_strong(expected, e,
- std::memory_order_release,
- std::memory_order_acquire)) {
- delete e;
- e = expected; // Filled in by CAS
- }
- if (e == nullptr) return; // out of memory
- }
+ Extras* e = getOrCreateExtras();
+ if (!e) return; // out of memory
AutoMutex _l(e->mLock);
e->mObjects.attach(objectID, object, cleanupCookie, func);
@@ -204,6 +197,30 @@
return this;
}
+bool BBinder::isRequestingSid()
+{
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ return e && e->mRequestingSid;
+}
+
+void BBinder::setRequestingSid(bool requestingSid)
+{
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ if (!e) {
+ // default is false. Most things don't need sids, so avoiding allocations when possible.
+ if (!requestingSid) {
+ return;
+ }
+
+ e = getOrCreateExtras();
+ if (!e) return; // out of memory
+ }
+
+ e->mRequestingSid = true;
+}
+
BBinder::~BBinder()
{
Extras* e = mExtras.load(std::memory_order_relaxed);
@@ -267,6 +284,25 @@
}
}
+BBinder::Extras* BBinder::getOrCreateExtras()
+{
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ if (!e) {
+ e = new Extras;
+ Extras* expected = nullptr;
+ if (!mExtras.compare_exchange_strong(expected, e,
+ std::memory_order_release,
+ std::memory_order_acquire)) {
+ delete e;
+ e = expected; // Filled in by CAS
+ }
+ if (e == nullptr) return nullptr; // out of memory
+ }
+
+ return e;
+}
+
// ---------------------------------------------------------------------------
enum {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 1d4e234..9a561cb 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -88,7 +88,8 @@
"BR_FINISHED",
"BR_DEAD_BINDER",
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
- "BR_FAILED_REPLY"
+ "BR_FAILED_REPLY",
+ "BR_TRANSACTION_SEC_CTX",
};
static const char *kCommandStrings[] = {
@@ -365,6 +366,11 @@
return mCallingPid;
}
+const char* IPCThreadState::getCallingSid() const
+{
+ return mCallingSid;
+}
+
uid_t IPCThreadState::getCallingUid() const
{
return mCallingUid;
@@ -372,6 +378,7 @@
int64_t IPCThreadState::clearCallingIdentity()
{
+ // ignore mCallingSid for legacy reasons
int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
clearCaller();
return token;
@@ -442,12 +449,14 @@
void IPCThreadState::restoreCallingIdentity(int64_t token)
{
mCallingUid = (int)(token>>32);
+ mCallingSid = nullptr; // not enough data to restore
mCallingPid = (int)token;
}
void IPCThreadState::clearCaller()
{
mCallingPid = getpid();
+ mCallingSid = nullptr; // expensive to lookup
mCallingUid = getuid();
}
@@ -1135,10 +1144,19 @@
}
break;
+ case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
- binder_transaction_data tr;
- result = mIn.read(&tr, sizeof(tr));
+ binder_transaction_data_secctx tr_secctx;
+ binder_transaction_data& tr = tr_secctx.transaction_data;
+
+ if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
+ result = mIn.read(&tr_secctx, sizeof(tr_secctx));
+ } else {
+ result = mIn.read(&tr, sizeof(tr));
+ tr_secctx.secctx = 0;
+ }
+
ALOG_ASSERT(result == NO_ERROR,
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break;
@@ -1154,6 +1172,7 @@
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
const pid_t origPid = mCallingPid;
+ const char* origSid = mCallingSid;
const uid_t origUid = mCallingUid;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
@@ -1166,10 +1185,12 @@
clearPropagateWorkSource();
mCallingPid = tr.sender_pid;
+ mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
mCallingUid = tr.sender_euid;
mLastTransactionBinderFlags = tr.flags;
- //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
+ // ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,
+ // (mCallingSid ? mCallingSid : "<N/A>"), mCallingUid);
Parcel reply;
status_t error;
@@ -1201,8 +1222,8 @@
}
mIPCThreadStateBase->popCurrentState();
- //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
- // mCallingPid, origPid, origUid);
+ //ALOGI("<<<< TRANSACT from pid %d restore pid %d sid %s uid %d\n",
+ // mCallingPid, origPid, (origSid ? origSid : "<N/A>"), origUid);
if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
@@ -1213,6 +1234,7 @@
}
mCallingPid = origPid;
+ mCallingSid = origSid;
mCallingUid = origUid;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index d285030..f779d6e 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -220,7 +220,7 @@
}
if (binder != nullptr) {
- IBinder *local = binder->localBinder();
+ BBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == nullptr) {
@@ -232,6 +232,9 @@
obj.handle = handle;
obj.cookie = 0;
} else {
+ if (local->isRequestingSid()) {
+ obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
+ }
obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 3798b61..79db0cb 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -181,8 +181,20 @@
mBinderContextCheckFunc = checkFunc;
mBinderContextUserData = userData;
- int dummy = 0;
- status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+ flat_binder_object obj {
+ .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
+ };
+
+ status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);
+
+ // fallback to original method
+ if (result != 0) {
+ android_errorWriteLog(0x534e4554, "121035042");
+
+ int dummy = 0;
+ result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+ }
+
if (result == 0) {
mManagesContexts = true;
} else if (result == -1) {
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index c251468..cf3ef84 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -60,6 +60,10 @@
virtual BBinder* localBinder();
+ bool isRequestingSid();
+ // This must be called before the object is sent to another process. Not thread safe.
+ void setRequestingSid(bool requestSid);
+
protected:
virtual ~BBinder();
@@ -75,6 +79,8 @@
class Extras;
+ Extras* getOrCreateExtras();
+
std::atomic<Extras*> mExtras;
void* mReserved0;
};
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index a6b0f7e..614b0b3 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -42,6 +42,11 @@
status_t clearLastError();
pid_t getCallingPid() const;
+ // nullptr if unavailable
+ //
+ // this can't be restored once it's cleared, and it does not return the
+ // context of the current process when not in a binder call.
+ const char* getCallingSid() const;
uid_t getCallingUid() const;
void setStrictModePolicy(int32_t policy);
@@ -64,6 +69,7 @@
int32_t getLastTransactionBinderFlags() const;
int64_t clearCallingIdentity();
+ // Restores PID/UID (not SID)
void restoreCallingIdentity(int64_t token);
int setupPolling(int* fd);
@@ -174,6 +180,7 @@
Parcel mOut;
status_t mLastError;
pid_t mCallingPid;
+ const char* mCallingSid;
uid_t mCallingUid;
// The UID of the process who is responsible for this transaction.
// This is used for resource attribution.
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index cd151ee..240b708 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -27,8 +27,8 @@
#include <utils/String16.h>
#include <utils/Vector.h>
#include <utils/Flattenable.h>
-#include <linux/android/binder.h>
+#include <binder/binder_kernel.h>
#include <binder/IInterface.h>
#include <binder/Parcelable.h>
#include <binder/Map.h>
diff --git a/libs/binder/include/binder/binder_kernel.h b/libs/binder/include/binder/binder_kernel.h
new file mode 100644
index 0000000..c7f6b4b
--- /dev/null
+++ b/libs/binder/include/binder/binder_kernel.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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_BINDER_KERNEL_H
+#define ANDROID_BINDER_KERNEL_H
+
+#include <linux/android/binder.h>
+
+/**
+ * This file exists because the uapi kernel headers in bionic are built
+ * from upstream kernel headers only, and not all of the hwbinder kernel changes
+ * have made it upstream yet. Therefore, the modifications to the
+ * binder header are added locally in this file.
+ */
+
+enum {
+ FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
+};
+
+#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object)
+
+struct binder_transaction_data_secctx {
+ struct binder_transaction_data transaction_data;
+ binder_uintptr_t secctx;
+};
+
+enum {
+ BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
+ struct binder_transaction_data_secctx),
+};
+
+#endif // ANDROID_BINDER_KERNEL_H
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 37c24ef..429ce0e 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -24,7 +24,7 @@
namespace android {
-class NativeLoaderNamespace;
+struct NativeLoaderNamespace;
class GraphicsEnv {
public:
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index a481e81..ad2dc14 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -66,7 +66,8 @@
virtual void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
- const InputWindowCommands& commands) {
+ const InputWindowCommands& commands,
+ int64_t desiredPresentTime) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -83,6 +84,7 @@
data.writeUint32(flags);
data.writeStrongBinder(applyToken);
commands.write(data);
+ data.writeInt64(desiredPresentTime);
remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
@@ -681,6 +683,54 @@
result = reply.readUint64Vector(&outStats->component_3_sample);
return result;
}
+
+ virtual status_t getProtectedContentSupport(bool* outSupported) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply);
+ bool result;
+ status_t err = reply.readBool(&result);
+ if (err == NO_ERROR) {
+ *outSupported = result;
+ }
+ return err;
+ }
+
+ virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
+ int32_t* outBufferId) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+
+ data.writeStrongBinder(token);
+ if (buffer) {
+ data.writeBool(true);
+ data.write(*buffer);
+ } else {
+ data.writeBool(false);
+ }
+
+ status_t result = remote()->transact(BnSurfaceComposer::CACHE_BUFFER, data, &reply);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ int32_t id = -1;
+ result = reply.readInt32(&id);
+ if (result == NO_ERROR) {
+ *outBufferId = id;
+ }
+ return result;
+ }
+
+ virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+
+ data.writeStrongBinder(token);
+ data.writeInt32(bufferId);
+
+ return remote()->transact(BnSurfaceComposer::UNCACHE_BUFFER, data, &reply);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -736,7 +786,10 @@
sp<IBinder> applyToken = data.readStrongBinder();
InputWindowCommands inputWindowCommands;
inputWindowCommands.read(data);
- setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands);
+
+ int64_t desiredPresentTime = data.readInt64();
+ setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
+ desiredPresentTime);
return NO_ERROR;
}
case BOOT_FINISHED: {
@@ -1017,7 +1070,7 @@
reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
reply->writeInt32(static_cast<int32_t>(wideColorGamutPixelFormat));
}
- return NO_ERROR;
+ return error;
}
case GET_COLOR_MANAGEMENT: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1026,7 +1079,7 @@
if (error == NO_ERROR) {
reply->writeBool(result);
}
- return result;
+ return error;
}
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1110,6 +1163,57 @@
}
return result;
}
+ case GET_PROTECTED_CONTENT_SUPPORT: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ bool result;
+ status_t error = getProtectedContentSupport(&result);
+ if (error == NO_ERROR) {
+ reply->writeBool(result);
+ }
+ return error;
+ }
+ case CACHE_BUFFER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> token;
+ status_t result = data.readStrongBinder(&token);
+ if (result != NO_ERROR) {
+ ALOGE("cache buffer failure in reading token: %d", result);
+ return result;
+ }
+
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ if (data.readBool()) {
+ result = data.read(*buffer);
+ if (result != NO_ERROR) {
+ ALOGE("cache buffer failure in reading buffer: %d", result);
+ return result;
+ }
+ }
+ int32_t bufferId = -1;
+ status_t error = cacheBuffer(token, buffer, &bufferId);
+ if (error == NO_ERROR) {
+ reply->writeInt32(bufferId);
+ }
+ return error;
+ }
+ case UNCACHE_BUFFER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> token;
+ status_t result = data.readStrongBinder(&token);
+ if (result != NO_ERROR) {
+ ALOGE("uncache buffer failure in reading token: %d", result);
+ return result;
+ }
+
+ int32_t bufferId = -1;
+ result = data.readInt32(&bufferId);
+ if (result != NO_ERROR) {
+ ALOGE("uncache buffer failure in reading buffer id: %d", result);
+ return result;
+ }
+
+ return uncacheBuffer(token, bufferId);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 1be55e6..ce88d7b 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -39,7 +39,16 @@
if (err != NO_ERROR) {
return err;
}
- return output->writeBool(releasePreviousBuffer);
+ if (previousReleaseFence) {
+ err = output->writeBool(true);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->write(*previousReleaseFence);
+ } else {
+ err = output->writeBool(false);
+ }
+ return err;
}
status_t SurfaceStats::readFromParcel(const Parcel* input) {
@@ -51,7 +60,19 @@
if (err != NO_ERROR) {
return err;
}
- return input->readBool(&releasePreviousBuffer);
+ bool hasFence = false;
+ err = input->readBool(&hasFence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (hasFence) {
+ previousReleaseFence = new Fence();
+ err = input->read(*previousReleaseFence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+ return NO_ERROR;
}
status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e5170ab..40b55fa 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -94,6 +94,9 @@
}
}
+ output.writeStrongBinder(cachedBuffer.token);
+ output.writeInt32(cachedBuffer.bufferId);
+
return NO_ERROR;
}
@@ -164,6 +167,9 @@
listenerCallbacks.emplace_back(listener, callbackIds);
}
+ cachedBuffer.token = input.readStrongBinder();
+ cachedBuffer.bufferId = input.readInt32();
+
return NO_ERROR;
}
@@ -372,6 +378,10 @@
}
#endif
+ if (other.what & eCachedBufferChanged) {
+ what |= eCachedBufferChanged;
+ cachedBuffer = other.cachedBuffer;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index a7c7e79..73150dc 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,8 +1,7 @@
-brianderson@google.com
jessehall@google.com
jwcai@google.com
+lpy@google.com
+marissaw@google.com
mathias@google.com
-olv@google.com
-pceballos@google.com
racarr@google.com
stoza@google.com
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8b9e4d7..a82054b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -159,11 +159,12 @@
// ---------------------------------------------------------------------------
-SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
- mForceSynchronous(other.mForceSynchronous),
- mTransactionNestCount(other.mTransactionNestCount),
- mAnimation(other.mAnimation),
- mEarlyWakeup(other.mEarlyWakeup) {
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
+ : mForceSynchronous(other.mForceSynchronous),
+ mTransactionNestCount(other.mTransactionNestCount),
+ mAnimation(other.mAnimation),
+ mEarlyWakeup(other.mEarlyWakeup),
+ mDesiredPresentTime(other.mDesiredPresentTime) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
mInputWindowCommands = other.mInputWindowCommands;
@@ -218,7 +219,7 @@
s.state.parentHandleForChild = nullptr;
composerStates.add(s);
- sf->setTransactionState(composerStates, displayStates, 0, nullptr, {});
+ sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1);
}
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
@@ -284,7 +285,8 @@
mEarlyWakeup = false;
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
- sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands);
+ sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
+ mDesiredPresentTime);
mInputWindowCommands.clear();
mStatus = NO_ERROR;
return NO_ERROR;
@@ -658,6 +660,21 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachedBuffer(
+ const sp<SurfaceControl>& sc, int32_t bufferId) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eCachedBufferChanged;
+ s->cachedBuffer.token = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ s->cachedBuffer.bufferId = bufferId;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence(
const sp<SurfaceControl>& sc, const sp<Fence>& fence) {
layer_state_t* s = getLayerState(sc);
@@ -742,6 +759,12 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime(
+ nsecs_t desiredPresentTime) {
+ mDesiredPresentTime = desiredPresentTime;
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
@@ -1049,6 +1072,26 @@
// ----------------------------------------------------------------------------
+status_t SurfaceComposerClient::cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ if (buffer == nullptr || outBufferId == nullptr) {
+ return BAD_VALUE;
+ }
+ return sf->cacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
+ buffer, outBufferId);
+}
+
+status_t SurfaceComposerClient::uncacheBuffer(int32_t bufferId) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ if (bufferId < 0) {
+ return BAD_VALUE;
+ }
+ return sf->uncacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
+ bufferId);
+}
+
+// ----------------------------------------------------------------------------
+
status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
return sf->enableVSyncInjections(enable);
@@ -1118,6 +1161,12 @@
wideColorGamutDataspace, wideColorGamutPixelFormat);
}
+bool SurfaceComposerClient::getProtectedContentSupport() {
+ bool supported = false;
+ ComposerService::getComposerService()->getProtectedContentSupport(&supported);
+ return supported;
+}
+
status_t SurfaceComposerClient::clearAnimationFrameStats() {
return ComposerService::getComposerService()->clearAnimationFrameStats();
}
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 537c957..b377a41 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -40,13 +40,14 @@
#define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
-#define ATRACE_BUFFER_INDEX(index) \
- if (ATRACE_ENABLED()) { \
- char ___traceBuf[1024]; \
- snprintf(___traceBuf, 1024, "%s: %d", \
- mCore->mConsumerName.string(), (index)); \
- android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \
- }
+#define ATRACE_BUFFER_INDEX(index) \
+ do { \
+ if (ATRACE_ENABLED()) { \
+ char ___traceBuf[1024]; \
+ snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \
+ android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \
+ } \
+ } while (false)
namespace android {
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 1534fca..418d5fb 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -116,7 +116,8 @@
virtual void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands) = 0;
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) = 0;
/* signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
@@ -309,6 +310,17 @@
virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
uint64_t timestamp,
DisplayedFrameStats* outStats) const = 0;
+
+ /*
+ * Gets whether SurfaceFlinger can support protected content in GPU composition.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
+
+ virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
+ int32_t* outBufferId) = 0;
+
+ virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) = 0;
};
// ----------------------------------------------------------------------------
@@ -350,6 +362,9 @@
GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
+ GET_PROTECTED_CONTENT_SUPPORT,
+ CACHE_BUFFER,
+ UNCACHE_BUFFER,
};
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
index 8acfa7a..29ab026 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -52,12 +52,12 @@
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) {}
+ SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence)
+ : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
- bool releasePreviousBuffer = false;
+ sp<Fence> previousReleaseFence;
};
class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index e7564f5..af31420 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -84,6 +84,7 @@
eInputInfoChanged = 0x40000000,
eCornerRadiusChanged = 0x80000000,
eFrameChanged = 0x1'00000000,
+ eCachedBufferChanged = 0x2'00000000,
};
layer_state_t()
@@ -125,6 +126,10 @@
float dtdy{0};
float dsdy{0};
};
+ struct cached_buffer_t {
+ sp<IBinder> token = nullptr;
+ int32_t bufferId = -1;
+ };
sp<IBinder> surface;
uint64_t what;
float x;
@@ -173,6 +178,8 @@
#ifndef NO_INPUT
InputWindowInfo inputInfo;
#endif
+
+ cached_buffer_t cachedBuffer;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index f16f781..db315c2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -145,6 +145,12 @@
ui::Dataspace* wideColorGamutDataspace,
ui::PixelFormat* wideColorGamutPixelFormat);
+ /*
+ * Gets whether SurfaceFlinger can support protected content in GPU composition.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ static bool getProtectedContentSupport();
+
/**
* Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
* to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
@@ -152,6 +158,12 @@
static void doDropReferenceTransaction(const sp<IBinder>& handle,
const sp<ISurfaceComposerClient>& client);
+ // Caches a buffer with the ISurfaceComposer so the buffer does not need to be resent across
+ // processes
+ static status_t cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId);
+ // Uncaches a buffer set by cacheBuffer
+ static status_t uncacheBuffer(int32_t bufferId);
+
// ------------------------------------------------------------------------
// surface creation / destruction
@@ -237,6 +249,18 @@
bool mAnimation = false;
bool mEarlyWakeup = false;
+ // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
+ // to be presented. When it is not possible to present at exactly that time, it will be
+ // presented after the time has passed.
+ //
+ // Desired present times that are more than 1 second in the future may be ignored.
+ // When a desired present time has already passed, the transaction will be presented as soon
+ // as possible.
+ //
+ // Transactions from the same process are presented in the same order that they are applied.
+ // The desired present time does not affect this ordering.
+ int64_t mDesiredPresentTime = -1;
+
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
@@ -317,6 +341,7 @@
Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame);
Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer);
+ Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId);
Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
@@ -325,6 +350,7 @@
Transaction& setApi(const sp<SurfaceControl>& sc, int32_t api);
Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
const sp<NativeHandle>& sidebandStream);
+ Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 7fc69ff..ac97733 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -489,5 +489,13 @@
toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1);
fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP);
}
+
+TEST_F(InputSurfacesTest, input_respects_outscreen) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(-1, -1);
+
+ injectTap(0, 0);
+ surface->expectTap(1, 1);
+}
}
}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 60173dc..259ef9f 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -556,7 +556,9 @@
void setTransactionState(const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
const sp<IBinder>& /*applyToken*/,
- const InputWindowCommands& /*inputWindowCommands*/) override {}
+ const InputWindowCommands& /*inputWindowCommands*/,
+ int64_t /*desiredPresentTime*/) override {}
+
void bootFinished() override {}
bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& /*surface*/) const override {
@@ -655,7 +657,14 @@
return NO_ERROR;
}
- virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; }
+ status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
+ status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
+
+ status_t cacheBuffer(const sp<IBinder>& /*token*/, const sp<GraphicBuffer>& /*buffer*/,
+ int32_t* /*outBufferId*/) {
+ return NO_ERROR;
+ }
+ status_t uncacheBuffer(const sp<IBinder>& /*token*/, int32_t /*bufferId*/) { return NO_ERROR; }
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index db86c8e..9fd25f9 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -29,6 +29,17 @@
namespace android {
+const char* motionClassificationToString(MotionClassification classification) {
+ switch (classification) {
+ case MotionClassification::NONE:
+ return "NONE";
+ case MotionClassification::AMBIGUOUS_GESTURE:
+ return "AMBIGUOUS_GESTURE";
+ case MotionClassification::DEEP_PRESS:
+ return "DEEP_PRESS";
+ }
+}
+
// --- InputEvent ---
void InputEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 0ddee44..0f7a1f0 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -157,6 +157,8 @@
msg->body.motion.metaState = body.motion.metaState;
// int32_t buttonState
msg->body.motion.buttonState = body.motion.buttonState;
+ // MotionClassification classification
+ msg->body.motion.classification = body.motion.classification;
// int32_t edgeFlags
msg->body.motion.edgeFlags = body.motion.edgeFlags;
// nsecs_t downTime
@@ -448,6 +450,7 @@
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
+ MotionClassification classification,
float xOffset,
float yOffset,
float xPrecision,
@@ -461,13 +464,13 @@
ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
"displayId=%" PRId32 ", "
"action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
- "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
+ "metaState=0x%x, buttonState=0x%x, classification=%s, xOffset=%f, yOffset=%f, "
"xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
"pointerCount=%" PRIu32,
mChannel->getName().c_str(), seq,
deviceId, source, displayId, action, actionButton, flags, edgeFlags, metaState,
- buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime,
- pointerCount);
+ buttonState, motionClassificationToString(classification),
+ xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
#endif
if (!seq) {
@@ -493,6 +496,7 @@
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
msg.body.motion.buttonState = buttonState;
+ msg.body.motion.classification = classification;
msg.body.motion.xOffset = xOffset;
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
@@ -1112,7 +1116,7 @@
msg->body.motion.edgeFlags,
msg->body.motion.metaState,
msg->body.motion.buttonState,
- MotionClassification::NONE,
+ msg->body.motion.classification,
msg->body.motion.xOffset,
msg->body.motion.yOffset,
msg->body.motion.xPrecision,
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index 96c165c..f1675c0 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <array>
+
#include "TestHelpers.h"
#include <unistd.h>
@@ -155,5 +157,37 @@
<< "sendMessage should have returned DEAD_OBJECT";
}
+TEST_F(InputChannelTest, SendAndReceive_MotionClassification) {
+ sp<InputChannel> serverChannel, clientChannel;
+ status_t result = InputChannel::openInputChannelPair("channel name",
+ serverChannel, clientChannel);
+ ASSERT_EQ(OK, result)
+ << "should have successfully opened a channel pair";
+
+ std::array<MotionClassification, 3> classifications = {
+ MotionClassification::NONE,
+ MotionClassification::AMBIGUOUS_GESTURE,
+ MotionClassification::DEEP_PRESS,
+ };
+
+ InputMessage serverMsg = {}, clientMsg;
+ serverMsg.header.type = InputMessage::TYPE_MOTION;
+ serverMsg.body.motion.seq = 1;
+ serverMsg.body.motion.pointerCount = 1;
+
+ for (MotionClassification classification : classifications) {
+ // Send and receive a message with classification
+ serverMsg.body.motion.classification = classification;
+ EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
+ << "server channel should be able to send message to client channel";
+
+ EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
+ << "client channel should be able to receive message from server channel";
+ EXPECT_EQ(serverMsg.header.type, clientMsg.header.type);
+ EXPECT_EQ(classification, clientMsg.body.motion.classification) <<
+ "Expected to receive " << motionClassificationToString(classification);
+ }
+}
+
} // namespace android
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index e4c1514..2b75c82 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <array>
#include <math.h>
#include <binder/Parcel.h>
@@ -25,11 +26,7 @@
// Default display id.
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
-class BaseTest : public testing::Test {
-protected:
- virtual void SetUp() { }
- virtual void TearDown() { }
-};
+class BaseTest : public testing::Test { };
// --- PointerCoordsTest ---
@@ -316,6 +313,7 @@
ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
+ ASSERT_EQ(MotionClassification::NONE, event->getClassification());
ASSERT_EQ(X_OFFSET, event->getXOffset());
ASSERT_EQ(Y_OFFSET, event->getYOffset());
ASSERT_EQ(2.0f, event->getXPrecision());
@@ -609,4 +607,30 @@
ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
}
+TEST_F(MotionEventTest, Initialize_SetsClassification) {
+ std::array<MotionClassification, 3> classifications = {
+ MotionClassification::NONE,
+ MotionClassification::AMBIGUOUS_GESTURE,
+ MotionClassification::DEEP_PRESS,
+ };
+
+ MotionEvent event;
+ constexpr size_t pointerCount = 1;
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].clear();
+ pointerProperties[i].id = i;
+ pointerCoords[i].clear();
+ }
+
+ for (MotionClassification classification : classifications) {
+ event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0,
+ classification, 0, 0, 0, 0, 0 /*downTime*/, 0 /*eventTime*/,
+ pointerCount, pointerProperties, pointerCoords);
+ ASSERT_EQ(classification, event.getClassification());
+ }
+}
+
} // namespace android
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 0788c89..f2cd1be 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -141,6 +141,7 @@
constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
constexpr int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
+ constexpr MotionClassification classification = MotionClassification::AMBIGUOUS_GESTURE;
constexpr float xOffset = -10;
constexpr float yOffset = -20;
constexpr float xPrecision = 0.25;
@@ -168,8 +169,8 @@
}
status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
- flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
- downTime, eventTime, pointerCount,
+ flags, edgeFlags, metaState, buttonState, classification,
+ xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount,
pointerProperties, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
@@ -195,6 +196,7 @@
EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
EXPECT_EQ(metaState, motionEvent->getMetaState());
EXPECT_EQ(buttonState, motionEvent->getButtonState());
+ EXPECT_EQ(classification, motionEvent->getClassification());
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
EXPECT_EQ(downTime, motionEvent->getDownTime());
@@ -264,7 +266,8 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -276,7 +279,8 @@
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -293,7 +297,8 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 12a6782..62023fb 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -57,7 +57,8 @@
CHECK_OFFSET(InputMessage::Body::Motion, flags, 36);
CHECK_OFFSET(InputMessage::Body::Motion, metaState, 40);
CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 44);
- CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 48);
+ CHECK_OFFSET(InputMessage::Body::Motion, classification, 48);
+ CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 52);
CHECK_OFFSET(InputMessage::Body::Motion, downTime, 56);
CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 64);
CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
new file mode 100644
index 0000000..6fb149a
--- /dev/null
+++ b/libs/math/OWNERS
@@ -0,0 +1,6 @@
+jaesoo@google.com
+jiyong@google.com
+mathias@google.com
+pawin@google.com
+randolphs@google.com
+romainguy@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 2915bb8..f57bf9c 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1280,7 +1280,7 @@
std::lock_guard<std::mutex> lock(mMutex);
mCondition.wait(mMutex,
- [&]() REQUIRES(mMutex) { return !mQueue.empty() && !mRunning; });
+ [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
if (!mRunning) {
// if mRunning is false, then FlushTracer is being destroyed, so
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 6926f7f..324d443 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -57,15 +57,15 @@
uint8_t b[16];
int64_t i64[2];
};
- uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
+ explicit uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
uuid_t() : b{0} {}
};
Sensor(const Sensor&) = default;
Sensor& operator=(const Sensor&) = default;
- Sensor(const char * name = "");
- Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
+ explicit Sensor(const char * name = "");
+ explicit Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0);
~Sensor();
diff --git a/libs/sensor/include/sensor/SensorEventQueue.h b/libs/sensor/include/sensor/SensorEventQueue.h
index baed2ee..8176578 100644
--- a/libs/sensor/include/sensor/SensorEventQueue.h
+++ b/libs/sensor/include/sensor/SensorEventQueue.h
@@ -64,7 +64,7 @@
// Default sensor sample period
static constexpr int32_t SENSOR_DELAY_NORMAL = 200000;
- SensorEventQueue(const sp<ISensorEventConnection>& connection);
+ explicit SensorEventQueue(const sp<ISensorEventConnection>& connection);
virtual ~SensorEventQueue();
virtual void onFirstRef();
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 23f7a91..f09c9c6 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -71,7 +71,7 @@
void sensorManagerDied();
static status_t waitForSensorService(sp<ISensorServer> *server);
- SensorManager(const String16& opPackageName);
+ explicit SensorManager(const String16& opPackageName);
status_t assertStateLocked();
private:
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index d089bf6..74450d7 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -60,7 +60,9 @@
"Fence.cpp",
"FenceTime.cpp",
"FrameStats.cpp",
+ "Gralloc.cpp",
"Gralloc2.cpp",
+ "Gralloc3.cpp",
"GraphicBuffer.cpp",
"GraphicBufferAllocator.cpp",
"GraphicBufferMapper.cpp",
@@ -68,6 +70,7 @@
"PixelFormat.cpp",
"Rect.cpp",
"Region.cpp",
+ "Size.cpp",
"Transform.cpp",
"UiConfig.cpp",
],
@@ -79,9 +82,11 @@
shared_libs: [
"android.frameworks.bufferhub@1.0",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@3.0",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
"libbase",
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 052e650..6310f29 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -319,11 +319,6 @@
mMetadata.IsValid() && mBufferClient != nullptr;
}
-// TODO(b/68770788): implement Poll() once we have event fd
-int BufferHubBuffer::Poll(int /* timeoutMs */) {
- return -ENOSYS;
-}
-
native_handle_t* BufferHubBuffer::Duplicate() {
if (mBufferClient == nullptr) {
ALOGE("%s: missing BufferClient!", __FUNCTION__);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/libs/ui/Gralloc.cpp
similarity index 67%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to libs/ui/Gralloc.cpp
index e6ac6bf..8e09a13 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/libs/ui/Gralloc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2016 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#define LOG_TAG "Gralloc"
+
+#include <ui/Gralloc.h>
namespace android {
-namespace mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+GrallocMapper::~GrallocMapper() {}
-} // namespace mock
+GrallocAllocator::~GrallocAllocator() {}
+
} // namespace android
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 20f27c5..ea7321e 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -27,9 +27,15 @@
#include <sync/sync.h>
#pragma clang diagnostic pop
-namespace android {
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V2_0::Error;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using android::hardware::graphics::mapper::V2_1::IMapper;
-namespace Gralloc2 {
+namespace android {
namespace {
@@ -59,17 +65,26 @@
return valid11UsageBits;
}
+static inline IMapper::Rect sGralloc2Rect(const Rect& rect) {
+ IMapper::Rect outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
+}
+
} // anonymous namespace
-void Mapper::preload() {
+void Gralloc2Mapper::preload() {
android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
}
-Mapper::Mapper()
-{
+Gralloc2Mapper::Gralloc2Mapper() {
mMapper = hardware::graphics::mapper::V2_0::IMapper::getService();
if (mMapper == nullptr) {
- LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+ ALOGW("mapper 2.x is not supported");
+ return;
}
if (mMapper->isRemote()) {
LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
@@ -79,30 +94,37 @@
mMapperV2_1 = IMapper::castFrom(mMapper);
}
-Gralloc2::Error Mapper::validateBufferDescriptorInfo(
- const IMapper::BufferDescriptorInfo& descriptorInfo) const {
+bool Gralloc2Mapper::isSupported() const {
+ return mMapper != nullptr;
+}
+
+status_t Gralloc2Mapper::validateBufferDescriptorInfo(
+ IMapper::BufferDescriptorInfo* descriptorInfo) const {
uint64_t validUsageBits = getValid10UsageBits();
if (mMapperV2_1 != nullptr) {
validUsageBits = validUsageBits | getValid11UsageBits();
}
- if (descriptorInfo.usage & ~validUsageBits) {
+ if (descriptorInfo->usage & ~validUsageBits) {
ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
- descriptorInfo.usage & ~validUsageBits);
- return Error::BAD_VALUE;
+ descriptorInfo->usage & ~validUsageBits);
+ return BAD_VALUE;
}
- return Error::NONE;
+ return NO_ERROR;
}
-Error Mapper::createDescriptor(
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- BufferDescriptor* outDescriptor) const
-{
- Error error = validateBufferDescriptorInfo(descriptorInfo);
- if (error != Error::NONE) {
- return error;
+status_t Gralloc2Mapper::createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const {
+ IMapper::BufferDescriptorInfo* descriptorInfo =
+ static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+ BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+ status_t status = validateBufferDescriptorInfo(descriptorInfo);
+ if (status != NO_ERROR) {
+ return status;
}
+ Error error;
auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor)
{
error = tmpError;
@@ -115,24 +137,23 @@
hardware::Return<void> ret;
if (mMapperV2_1 != nullptr) {
- ret = mMapperV2_1->createDescriptor_2_1(descriptorInfo, hidl_cb);
+ ret = mMapperV2_1->createDescriptor_2_1(*descriptorInfo, hidl_cb);
} else {
const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = {
- descriptorInfo.width,
- descriptorInfo.height,
- descriptorInfo.layerCount,
- static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo.format),
- descriptorInfo.usage,
+ descriptorInfo->width,
+ descriptorInfo->height,
+ descriptorInfo->layerCount,
+ static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo->format),
+ descriptorInfo->usage,
};
ret = mMapper->createDescriptor(info, hidl_cb);
}
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-Error Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
- buffer_handle_t* outBufferHandle) const
-{
+status_t Gralloc2Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const {
Error error;
auto ret = mMapper->importBuffer(rawHandle,
[&](const auto& tmpError, const auto& tmpBuffer)
@@ -145,11 +166,10 @@
*outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
});
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-void Mapper::freeBuffer(buffer_handle_t bufferHandle) const
-{
+void Gralloc2Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
auto ret = mMapper->freeBuffer(buffer);
@@ -158,23 +178,29 @@
buffer, error);
}
-Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t stride) const
-{
+status_t Gralloc2Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const {
if (mMapperV2_1 == nullptr) {
- return Error::NONE;
+ return NO_ERROR;
}
+ IMapper::BufferDescriptorInfo descriptorInfo = {};
+ descriptorInfo.width = width;
+ descriptorInfo.height = height;
+ descriptorInfo.layerCount = layerCount;
+ descriptorInfo.format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ descriptorInfo.usage = usage;
+
auto buffer = const_cast<native_handle_t*>(bufferHandle);
auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
- return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
}
-void Mapper::getTransportSize(buffer_handle_t bufferHandle,
- uint32_t* outNumFds, uint32_t* outNumInts) const
-{
+void Gralloc2Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const {
*outNumFds = uint32_t(bufferHandle->numFds);
*outNumInts = uint32_t(bufferHandle->numInts);
@@ -195,19 +221,17 @@
*outNumInts = tmpNumInts;
});
- if (!ret.isOk()) {
- error = kTransactionError;
- }
- ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
- buffer, error);
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
}
-Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, void** outData) const
-{
+status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ IMapper::Rect accessRegion = sGralloc2Rect(bounds);
+
// put acquireFence in a hidl_handle
hardware::hidl_handle acquireFenceHandle;
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -234,15 +258,19 @@
close(acquireFence);
}
- return (ret.isOk()) ? error : kTransactionError;
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+ return static_cast<status_t>(error);
}
-Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, YCbCrLayout* outLayout) const
-{
+status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ IMapper::Rect accessRegion = sGralloc2Rect(bounds);
+
// put acquireFence in a hidl_handle
hardware::hidl_handle acquireFenceHandle;
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -252,6 +280,7 @@
acquireFenceHandle = h;
}
+ YCbCrLayout layout;
Error error;
auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion,
acquireFenceHandle,
@@ -262,19 +291,27 @@
return;
}
- *outLayout = tmpLayout;
+ layout = tmpLayout;
});
+ if (error == Error::NONE) {
+ ycbcr->y = layout.y;
+ ycbcr->cb = layout.cb;
+ ycbcr->cr = layout.cr;
+ ycbcr->ystride = static_cast<size_t>(layout.yStride);
+ ycbcr->cstride = static_cast<size_t>(layout.cStride);
+ ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+ }
+
// we own acquireFence even on errors
if (acquireFence >= 0) {
close(acquireFence);
}
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-int Mapper::unlock(buffer_handle_t bufferHandle) const
-{
+int Gralloc2Mapper::unlock(buffer_handle_t bufferHandle) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
int releaseFence = -1;
@@ -299,10 +336,7 @@
}
});
- if (!ret.isOk()) {
- error = kTransactionError;
- }
-
+ error = (ret.isOk()) ? error : kTransactionError;
if (error != Error::NONE) {
ALOGE("unlock(%p) failed with %d", buffer, error);
}
@@ -310,17 +344,19 @@
return releaseFence;
}
-Allocator::Allocator(const Mapper& mapper)
- : mMapper(mapper)
-{
+Gralloc2Allocator::Gralloc2Allocator(const Gralloc2Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
if (mAllocator == nullptr) {
- LOG_ALWAYS_FATAL("gralloc-alloc is missing");
+ ALOGW("allocator 2.x is not supported");
+ return;
}
}
-std::string Allocator::dumpDebugInfo() const
-{
+bool Gralloc2Allocator::isSupported() const {
+ return mAllocator != nullptr;
+}
+
+std::string Gralloc2Allocator::dumpDebugInfo() const {
std::string debugInfo;
mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) {
@@ -330,40 +366,51 @@
return debugInfo;
}
-Error Allocator::allocate(BufferDescriptor descriptor, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const
-{
- Error error;
- auto ret = mAllocator->allocate(descriptor, count,
- [&](const auto& tmpError, const auto& tmpStride,
- const auto& tmpBuffers) {
- error = tmpError;
- if (tmpError != Error::NONE) {
- return;
- }
+status_t Gralloc2Allocator::allocate(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+ IMapper::BufferDescriptorInfo descriptorInfo = {};
+ descriptorInfo.width = width;
+ descriptorInfo.height = height;
+ descriptorInfo.layerCount = layerCount;
+ descriptorInfo.format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ descriptorInfo.usage = usage;
- // import buffers
- for (uint32_t i = 0; i < count; i++) {
- error = mMapper.importBuffer(tmpBuffers[i],
- &outBufferHandles[i]);
- if (error != Error::NONE) {
- for (uint32_t j = 0; j < i; j++) {
- mMapper.freeBuffer(outBufferHandles[j]);
- outBufferHandles[j] = nullptr;
- }
- return;
- }
- }
+ BufferDescriptor descriptor;
+ status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+ static_cast<void*>(&descriptor));
+ if (error != NO_ERROR) {
+ return error;
+ }
- *outStride = tmpStride;
- });
+ auto ret = mAllocator->allocate(descriptor, bufferCount,
+ [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ error = static_cast<status_t>(tmpError);
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ // import buffers
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ error = mMapper.importBuffer(tmpBuffers[i],
+ &outBufferHandles[i]);
+ if (error != NO_ERROR) {
+ for (uint32_t j = 0; j < i; j++) {
+ mMapper.freeBuffer(outBufferHandles[j]);
+ outBufferHandles[j] = nullptr;
+ }
+ return;
+ }
+ }
+
+ *outStride = tmpStride;
+ });
// make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
hardware::IPCThreadState::self()->flushCommands();
- return (ret.isOk()) ? error : kTransactionError;
+ return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
}
-} // namespace Gralloc2
-
} // namespace android
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
new file mode 100644
index 0000000..128200e
--- /dev/null
+++ b/libs/ui/Gralloc3.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2016 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 "Gralloc3"
+
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
+#include <ui/Gralloc3.h>
+
+#include <inttypes.h>
+#include <log/log.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#include <sync/sync.h>
+#pragma clang diagnostic pop
+
+using android::hardware::graphics::allocator::V3_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::mapper::V3_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V3_0::Error;
+using android::hardware::graphics::mapper::V3_0::IMapper;
+using android::hardware::graphics::mapper::V3_0::YCbCrLayout;
+
+namespace android {
+
+namespace {
+
+static constexpr Error kTransactionError = Error::NO_RESOURCES;
+
+uint64_t getValidUsageBits() {
+ static const uint64_t validUsageBits = []() -> uint64_t {
+ uint64_t bits = 0;
+ for (const auto bit :
+ hardware::hidl_enum_range<hardware::graphics::common::V1_0::BufferUsage>()) {
+ bits = bits | bit;
+ }
+ for (const auto bit :
+ hardware::hidl_enum_range<hardware::graphics::common::V1_1::BufferUsage>()) {
+ bits = bits | bit;
+ }
+ return bits;
+ }();
+ return validUsageBits;
+}
+
+static inline IMapper::Rect sGralloc3Rect(const Rect& rect) {
+ IMapper::Rect outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
+}
+static inline void sBufferDescriptorInfo(uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount,
+ uint64_t usage,
+ IMapper::BufferDescriptorInfo* outDescriptorInfo) {
+ outDescriptorInfo->width = width;
+ outDescriptorInfo->height = height;
+ outDescriptorInfo->layerCount = layerCount;
+ outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ outDescriptorInfo->usage = usage;
+}
+
+} // anonymous namespace
+
+void Gralloc3Mapper::preload() {
+ android::hardware::preloadPassthroughService<IMapper>();
+}
+
+Gralloc3Mapper::Gralloc3Mapper() {
+ mMapper = IMapper::getService();
+ if (mMapper == nullptr) {
+ ALOGW("mapper 3.x is not supported");
+ return;
+ }
+ if (mMapper->isRemote()) {
+ LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
+ }
+}
+
+bool Gralloc3Mapper::isSupported() const {
+ return mMapper != nullptr;
+}
+
+status_t Gralloc3Mapper::validateBufferDescriptorInfo(
+ IMapper::BufferDescriptorInfo* descriptorInfo) const {
+ uint64_t validUsageBits = getValidUsageBits();
+
+ if (descriptorInfo->usage & ~validUsageBits) {
+ ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+ descriptorInfo->usage & ~validUsageBits);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+status_t Gralloc3Mapper::createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const {
+ IMapper::BufferDescriptorInfo* descriptorInfo =
+ static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+ BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+ status_t status = validateBufferDescriptorInfo(descriptorInfo);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ Error error;
+ auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outDescriptor = tmpDescriptor;
+ };
+
+ hardware::Return<void> ret = mMapper->createDescriptor(*descriptorInfo, hidl_cb);
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+status_t Gralloc3Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const {
+ Error error;
+ auto ret = mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
+ });
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+void Gralloc3Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->freeBuffer(buffer);
+
+ auto error = (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+ ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc3Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+
+ return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
+}
+
+void Gralloc3Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const {
+ *outNumFds = uint32_t(bufferHandle->numFds);
+ *outNumInts = uint32_t(bufferHandle->numInts);
+
+ Error error;
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->getTransportSize(buffer,
+ [&](const auto& tmpError, const auto& tmpNumFds,
+ const auto& tmpNumInts) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outNumFds = tmpNumFds;
+ *outNumInts = tmpNumInts;
+ });
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc3Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ Error error;
+ auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpData) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outData = tmpData;
+ });
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+ return static_cast<status_t>(error);
+}
+
+status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc3Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ YCbCrLayout layout;
+ Error error;
+ auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ layout = tmpLayout;
+ });
+
+ if (error == Error::NONE) {
+ ycbcr->y = layout.y;
+ ycbcr->cb = layout.cb;
+ ycbcr->cr = layout.cr;
+ ycbcr->ystride = static_cast<size_t>(layout.yStride);
+ ycbcr->cstride = static_cast<size_t>(layout.cStride);
+ ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+ }
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+int Gralloc3Mapper::unlock(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ Error error;
+ auto ret = mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle && fenceHandle->numFds == 1) {
+ int fd = dup(fenceHandle->data[0]);
+ if (fd >= 0) {
+ releaseFence = fd;
+ } else {
+ ALOGD("failed to dup unlock release fence");
+ sync_wait(fenceHandle->data[0], -1);
+ }
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("unlock(%p) failed with %d", buffer, error);
+ }
+
+ return releaseFence;
+}
+
+Gralloc3Allocator::Gralloc3Allocator(const Gralloc3Mapper& mapper) : mMapper(mapper) {
+ mAllocator = IAllocator::getService();
+ if (mAllocator == nullptr) {
+ ALOGW("allocator 3.x is not supported");
+ return;
+ }
+}
+
+bool Gralloc3Allocator::isSupported() const {
+ return mAllocator != nullptr;
+}
+
+std::string Gralloc3Allocator::dumpDebugInfo() const {
+ std::string debugInfo;
+
+ mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+status_t Gralloc3Allocator::allocate(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ BufferDescriptor descriptor;
+ status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+ static_cast<void*>(&descriptor));
+ if (error != NO_ERROR) {
+ return error;
+ }
+
+ auto ret = mAllocator->allocate(descriptor, bufferCount,
+ [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ error = static_cast<status_t>(tmpError);
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ // import buffers
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ error = mMapper.importBuffer(tmpBuffers[i],
+ &outBufferHandles[i]);
+ if (error != NO_ERROR) {
+ for (uint32_t j = 0; j < i; j++) {
+ mMapper.freeBuffer(outBufferHandles[j]);
+ outBufferHandles[j] = nullptr;
+ }
+ return;
+ }
+ }
+ *outStride = tmpStride;
+ });
+
+ // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
+ hardware::IPCThreadState::self()->flushCommands();
+
+ return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
+}
+
+} // namespace android
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index f56e6b9..efb5798 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -29,7 +29,9 @@
#include <utils/Singleton.h>
#include <utils/Trace.h>
+#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
+#include <ui/Gralloc3.h>
#include <ui/GraphicBufferMapper.h>
namespace android {
@@ -43,11 +45,17 @@
KeyedVector<buffer_handle_t,
GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
-GraphicBufferAllocator::GraphicBufferAllocator()
- : mMapper(GraphicBufferMapper::getInstance()),
- mAllocator(std::make_unique<Gralloc2::Allocator>(
- mMapper.getGrallocMapper()))
-{
+GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
+ mAllocator = std::make_unique<const Gralloc3Allocator>(
+ reinterpret_cast<const Gralloc3Mapper&>(mMapper.getGrallocMapper()));
+ if (!mAllocator->isSupported()) {
+ mAllocator = std::make_unique<const Gralloc2Allocator>(
+ reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
+ }
+
+ if (!mAllocator->isSupported()) {
+ LOG_ALWAYS_FATAL("gralloc-allocator is missing");
+ }
}
GraphicBufferAllocator::~GraphicBufferAllocator() {}
@@ -104,15 +112,9 @@
// TODO(b/72323293, b/72703005): Remove these invalid bits from callers
usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
- Gralloc2::IMapper::BufferDescriptorInfo info = {};
- info.width = width;
- info.height = height;
- info.layerCount = layerCount;
- info.format = static_cast<Gralloc2::PixelFormat>(format);
- info.usage = usage;
-
- Gralloc2::Error error = mAllocator->allocate(info, stride, handle);
- if (error == Gralloc2::Error::NONE) {
+ status_t error =
+ mAllocator->allocate(width, height, format, layerCount, usage, 1, stride, handle);
+ if (error == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
uint32_t bpp = bytesPerPixel(format);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 2d8e582..b049329 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -32,7 +32,9 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
+#include <ui/Gralloc3.h>
#include <ui/GraphicBuffer.h>
#include <system/graphics.h>
@@ -43,12 +45,19 @@
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
void GraphicBufferMapper::preloadHal() {
- Gralloc2::Mapper::preload();
+ Gralloc2Mapper::preload();
+ Gralloc3Mapper::preload();
}
-GraphicBufferMapper::GraphicBufferMapper()
- : mMapper(std::make_unique<const Gralloc2::Mapper>())
-{
+GraphicBufferMapper::GraphicBufferMapper() {
+ mMapper = std::make_unique<const Gralloc3Mapper>();
+ if (!mMapper->isSupported()) {
+ mMapper = std::make_unique<const Gralloc2Mapper>();
+ }
+
+ if (!mMapper->isSupported()) {
+ LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+ }
}
status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
@@ -59,22 +68,15 @@
ATRACE_CALL();
buffer_handle_t bufferHandle;
- Gralloc2::Error error = mMapper->importBuffer(
- hardware::hidl_handle(rawHandle), &bufferHandle);
- if (error != Gralloc2::Error::NONE) {
+ status_t error = mMapper->importBuffer(hardware::hidl_handle(rawHandle), &bufferHandle);
+ if (error != NO_ERROR) {
ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
- return static_cast<status_t>(error);
+ return error;
}
- Gralloc2::IMapper::BufferDescriptorInfo info = {};
- info.width = width;
- info.height = height;
- info.layerCount = layerCount;
- info.format = static_cast<Gralloc2::PixelFormat>(format);
- info.usage = usage;
-
- error = mMapper->validateBufferSize(bufferHandle, info, stride);
- if (error != Gralloc2::Error::NONE) {
+ error = mMapper->validateBufferSize(bufferHandle, width, height, format, layerCount, usage,
+ stride);
+ if (error != NO_ERROR) {
ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
freeBuffer(bufferHandle);
return static_cast<status_t>(error);
@@ -100,15 +102,6 @@
return NO_ERROR;
}
-static inline Gralloc2::IMapper::Rect asGralloc2Rect(const Rect& rect) {
- Gralloc2::IMapper::Rect outRect{};
- outRect.left = rect.left;
- outRect.top = rect.top;
- outRect.width = rect.width();
- outRect.height = rect.height();
- return outRect;
-}
-
status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
const Rect& bounds, void** vaddr)
{
@@ -146,13 +139,7 @@
const uint64_t usage = static_cast<uint64_t>(
android_convertGralloc1To0Usage(producerUsage, consumerUsage));
- Gralloc2::Error error = mMapper->lock(handle, usage,
- asGralloc2Rect(bounds), fenceFd, vaddr);
-
- ALOGW_IF(error != Gralloc2::Error::NONE, "lock(%p, ...) failed: %d",
- handle, error);
-
- return static_cast<status_t>(error);
+ return mMapper->lock(handle, usage, bounds, fenceFd, vaddr);
}
status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
@@ -160,19 +147,7 @@
{
ATRACE_CALL();
- Gralloc2::YCbCrLayout layout;
- Gralloc2::Error error = mMapper->lock(handle, usage,
- asGralloc2Rect(bounds), fenceFd, &layout);
- if (error == Gralloc2::Error::NONE) {
- ycbcr->y = layout.y;
- ycbcr->cb = layout.cb;
- ycbcr->cr = layout.cr;
- ycbcr->ystride = static_cast<size_t>(layout.yStride);
- ycbcr->cstride = static_cast<size_t>(layout.cStride);
- ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
- }
-
- return static_cast<status_t>(error);
+ return mMapper->lock(handle, usage, bounds, fenceFd, ycbcr);
}
status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
new file mode 100644
index 0000000..54405e6
--- /dev/null
+++ b/libs/ui/OWNERS
@@ -0,0 +1,5 @@
+lpy@google.com
+marissaw@google.com
+mathias@google.com
+romainguy@google.com
+stoza@google.com
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/libs/ui/Size.cpp
similarity index 63%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to libs/ui/Size.cpp
index e6ac6bf..d2996d1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/libs/ui/Size.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,11 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <ui/Size.h>
-namespace android {
-namespace mock {
+namespace android::ui {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+const Size Size::INVALID{-1, -1};
+const Size Size::EMPTY{0, 0};
-} // namespace mock
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index 25128ef..d13942d 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -16,6 +16,7 @@
#include <math.h>
+#include <android-base/stringprintf.h>
#include <cutils/compiler.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -380,44 +381,47 @@
return (getOrientation() & ROT_INVALID) ? false : true;
}
-void Transform::dump(const char* name) const
-{
- type(); // updates the type
+void Transform::dump(std::string& out, const char* name) const {
+ using android::base::StringAppendF;
- String8 flags, type;
- const mat33& m(mMatrix);
- uint32_t orient = mType >> 8;
+ type(); // Ensure the information in mType is up to date
- if (orient&ROT_INVALID) {
- flags.append("ROT_INVALID ");
+ const uint32_t type = mType;
+ const uint32_t orient = type >> 8;
+
+ StringAppendF(&out, "%s 0x%08x (", name, orient);
+
+ if (orient & ROT_INVALID) {
+ out.append("ROT_INVALID ");
} else {
- if (orient&ROT_90) {
- flags.append("ROT_90 ");
+ if (orient & ROT_90) {
+ out.append("ROT_90 ");
} else {
- flags.append("ROT_0 ");
+ out.append("ROT_0 ");
}
- if (orient&FLIP_V)
- flags.append("FLIP_V ");
- if (orient&FLIP_H)
- flags.append("FLIP_H ");
+ if (orient & FLIP_V) out.append("FLIP_V ");
+ if (orient & FLIP_H) out.append("FLIP_H ");
}
- if (!(mType&(SCALE|ROTATE|TRANSLATE)))
- type.append("IDENTITY ");
- if (mType&SCALE)
- type.append("SCALE ");
- if (mType&ROTATE)
- type.append("ROTATE ");
- if (mType&TRANSLATE)
- type.append("TRANSLATE ");
+ StringAppendF(&out, ") 0x%02x (", type);
- ALOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string());
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][0]), static_cast<double>(m[1][0]),
- static_cast<double>(m[2][0]));
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][1]), static_cast<double>(m[1][1]),
- static_cast<double>(m[2][1]));
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][2]), static_cast<double>(m[1][2]),
- static_cast<double>(m[2][2]));
+ if (!(type & (SCALE | ROTATE | TRANSLATE))) out.append("IDENTITY ");
+ if (type & SCALE) out.append("SCALE ");
+ if (type & ROTATE) out.append("ROTATE ");
+ if (type & TRANSLATE) out.append("TRANSLATE ");
+
+ out.append(")\n");
+
+ for (size_t i = 0; i < 3; i++) {
+ StringAppendF(&out, " %.4f %.4f %.4f\n", static_cast<double>(mMatrix[0][i]),
+ static_cast<double>(mMatrix[1][i]), static_cast<double>(mMatrix[2][i]));
+ }
+}
+
+void Transform::dump(const char* name) const {
+ std::string out;
+ dump(out, name);
+ ALOGD("%s", out.c_str());
}
} // namespace ui
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 44dfa95..c6a4a23 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -94,9 +94,6 @@
// current cycle of the usage of the buffer.
int Release();
- // Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
- int Poll(int timeoutMs);
-
// Creates a token that stands for this BufferHubBuffer client and could be used for Import to
// create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying
// gralloc buffer and ashmem region for metadata. Note that the caller owns the token and
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
new file mode 100644
index 0000000..92bf043
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 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_UI_GRALLOC_H
+#define ANDROID_UI_GRALLOC_H
+
+#include <string>
+
+#include <hidl/HidlSupport.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+// A wrapper to IMapper
+class GrallocMapper {
+public:
+ virtual ~GrallocMapper();
+
+ virtual bool isSupported() const = 0;
+
+ virtual status_t createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const = 0;
+
+ // Import a buffer that is from another HAL, another process, or is
+ // cloned.
+ //
+ // The returned handle must be freed with freeBuffer.
+ virtual status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const = 0;
+
+ virtual void freeBuffer(buffer_handle_t bufferHandle) const = 0;
+
+ virtual status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const = 0;
+
+ virtual void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const = 0;
+
+ // The ownership of acquireFence is always transferred to the callee, even
+ // on errors.
+ virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const = 0;
+
+ // The ownership of acquireFence is always transferred to the callee, even
+ // on errors.
+ virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const = 0;
+
+ // unlock returns a fence sync object (or -1) and the fence sync object is
+ // owned by the caller
+ virtual int unlock(buffer_handle_t bufferHandle) const = 0;
+};
+
+// A wrapper to IAllocator
+class GrallocAllocator {
+public:
+ virtual ~GrallocAllocator();
+
+ virtual bool isSupported() const = 0;
+
+ virtual std::string dumpDebugInfo() const = 0;
+
+ /*
+ * The returned buffers are already imported and must not be imported
+ * again. outBufferHandles must point to a space that can contain at
+ * least "bufferCount" buffer_handle_t.
+ */
+ virtual status_t allocate(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC_H
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 5a8dbda..e03cb43 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -23,119 +23,71 @@
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
#include <utils/StrongPointer.h>
namespace android {
-namespace Gralloc2 {
-
-using hardware::graphics::allocator::V2_0::IAllocator;
-using hardware::graphics::common::V1_1::BufferUsage;
-using hardware::graphics::common::V1_1::PixelFormat;
-using hardware::graphics::mapper::V2_1::IMapper;
-using hardware::graphics::mapper::V2_0::BufferDescriptor;
-using hardware::graphics::mapper::V2_0::Error;
-using hardware::graphics::mapper::V2_0::YCbCrLayout;
-
-// A wrapper to IMapper
-class Mapper {
+class Gralloc2Mapper : public GrallocMapper {
public:
static void preload();
- Mapper();
+ Gralloc2Mapper();
- Error createDescriptor(
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- BufferDescriptor* outDescriptor) const;
+ bool isSupported() const override;
- // Import a buffer that is from another HAL, another process, or is
- // cloned.
- //
- // The returned handle must be freed with freeBuffer.
- Error importBuffer(const hardware::hidl_handle& rawHandle,
- buffer_handle_t* outBufferHandle) const;
+ status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
- void freeBuffer(buffer_handle_t bufferHandle) const;
+ status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const override;
- Error validateBufferSize(buffer_handle_t bufferHandle,
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t stride) const;
+ void freeBuffer(buffer_handle_t bufferHandle) const override;
- void getTransportSize(buffer_handle_t bufferHandle,
- uint32_t* outNumFds, uint32_t* outNumInts) const;
+ status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const override;
- // The ownership of acquireFence is always transferred to the callee, even
- // on errors.
- Error lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, void** outData) const;
+ void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const override;
- // The ownership of acquireFence is always transferred to the callee, even
- // on errors.
- Error lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, YCbCrLayout* outLayout) const;
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const override;
- // unlock returns a fence sync object (or -1) and the fence sync object is
- // owned by the caller
- int unlock(buffer_handle_t bufferHandle) const;
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const override;
+
+ int unlock(buffer_handle_t bufferHandle) const override;
private:
// Determines whether the passed info is compatible with the mapper.
- Error validateBufferDescriptorInfo(
- const IMapper::BufferDescriptorInfo& descriptorInfo) const;
+ status_t validateBufferDescriptorInfo(
+ hardware::graphics::mapper::V2_1::IMapper::BufferDescriptorInfo* descriptorInfo) const;
sp<hardware::graphics::mapper::V2_0::IMapper> mMapper;
- sp<IMapper> mMapperV2_1;
+ sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
};
-// A wrapper to IAllocator
-class Allocator {
+class Gralloc2Allocator : public GrallocAllocator {
public:
// An allocator relies on a mapper, and that mapper must be alive at all
// time.
- Allocator(const Mapper& mapper);
+ Gralloc2Allocator(const Gralloc2Mapper& mapper);
- std::string dumpDebugInfo() const;
+ bool isSupported() const override;
- /*
- * The returned buffers are already imported and must not be imported
- * again. outBufferHandles must point to a space that can contain at
- * least "count" buffer_handle_t.
- */
- Error allocate(BufferDescriptor descriptor, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const;
+ std::string dumpDebugInfo() const override;
- Error allocate(BufferDescriptor descriptor,
- uint32_t* outStride, buffer_handle_t* outBufferHandle) const
- {
- return allocate(descriptor, 1, outStride, outBufferHandle);
- }
-
- Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const
- {
- BufferDescriptor descriptor;
- Error error = mMapper.createDescriptor(descriptorInfo, &descriptor);
- if (error == Error::NONE) {
- error = allocate(descriptor, count, outStride, outBufferHandles);
- }
- return error;
- }
-
- Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t* outStride, buffer_handle_t* outBufferHandle) const
- {
- return allocate(descriptorInfo, 1, outStride, outBufferHandle);
- }
+ status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles) const override;
private:
- const Mapper& mMapper;
- sp<IAllocator> mAllocator;
+ const Gralloc2Mapper& mMapper;
+ sp<hardware::graphics::allocator::V2_0::IAllocator> mAllocator;
};
-} // namespace Gralloc2
-
} // namespace android
#endif // ANDROID_UI_GRALLOC2_H
diff --git a/libs/ui/include/ui/Gralloc3.h b/libs/ui/include/ui/Gralloc3.h
new file mode 100644
index 0000000..510ce4a
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc3.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 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_UI_GRALLOC3_H
+#define ANDROID_UI_GRALLOC3_H
+
+#include <string>
+
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Gralloc3Mapper : public GrallocMapper {
+public:
+ static void preload();
+
+ Gralloc3Mapper();
+
+ bool isSupported() const override;
+
+ status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
+
+ status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const override;
+
+ void freeBuffer(buffer_handle_t bufferHandle) const override;
+
+ status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const override;
+
+ void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const override;
+
+ int unlock(buffer_handle_t bufferHandle) const override;
+
+private:
+ // Determines whether the passed info is compatible with the mapper.
+ status_t validateBufferDescriptorInfo(
+ hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo* descriptorInfo) const;
+
+ sp<hardware::graphics::mapper::V3_0::IMapper> mMapper;
+};
+
+class Gralloc3Allocator : public GrallocAllocator {
+public:
+ // An allocator relies on a mapper, and that mapper must be alive at all
+ // time.
+ Gralloc3Allocator(const Gralloc3Mapper& mapper);
+
+ bool isSupported() const override;
+
+ std::string dumpDebugInfo() const override;
+
+ status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles) const override;
+
+private:
+ const Gralloc3Mapper& mMapper;
+ sp<hardware::graphics::allocator::V3_0::IAllocator> mAllocator;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC3_H
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 7e2b230..3a547b6 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -34,10 +34,7 @@
namespace android {
-namespace Gralloc2 {
-class Allocator;
-}
-
+class GrallocAllocator;
class GraphicBufferMapper;
class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
@@ -75,7 +72,7 @@
~GraphicBufferAllocator();
GraphicBufferMapper& mMapper;
- const std::unique_ptr<const Gralloc2::Allocator> mAllocator;
+ std::unique_ptr<const GrallocAllocator> mAllocator;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 7cf003d..156bd7a 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -35,10 +35,7 @@
// ---------------------------------------------------------------------------
-namespace Gralloc2 {
-class Mapper;
-}
-
+class GrallocMapper;
class Rect;
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
@@ -80,9 +77,8 @@
status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
- const Gralloc2::Mapper& getGrallocMapper() const
- {
- return *mMapper;
+ const GrallocMapper& getGrallocMapper() const {
+ return reinterpret_cast<const GrallocMapper&>(*mMapper);
}
private:
@@ -90,7 +86,7 @@
GraphicBufferMapper();
- const std::unique_ptr<const Gralloc2::Mapper> mMapper;
+ std::unique_ptr<const GrallocMapper> mMapper;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index e9da087..1768805 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -24,6 +24,7 @@
#include <ui/FloatRect.h>
#include <ui/Point.h>
+#include <ui/Size.h>
#include <android/rect.h>
@@ -78,6 +79,13 @@
bottom = static_cast<int32_t>(floatRect.bottom + 0.5f);
}
+ inline explicit Rect(const ui::Size& size) {
+ left = 0;
+ top = 0;
+ right = size.width;
+ bottom = size.height;
+ }
+
void makeInvalid();
inline void clear() {
@@ -106,6 +114,8 @@
return bottom - top;
}
+ ui::Size getSize() const { return ui::Size(getWidth(), getHeight()); }
+
__attribute__((no_sanitize("signed-integer-overflow")))
inline Rect getBounds() const {
return Rect(right - left, bottom - top);
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
new file mode 100644
index 0000000..c39d8af
--- /dev/null
+++ b/libs/ui/include/ui/Size.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2019 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 <algorithm>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace android {
+namespace ui {
+
+// Forward declare a few things.
+struct Size;
+bool operator==(const Size& lhs, const Size& rhs);
+
+/**
+ * A simple value type representing a two-dimensional size
+ */
+struct Size {
+ int32_t width;
+ int32_t height;
+
+ // Special values
+ static const Size INVALID;
+ static const Size EMPTY;
+
+ // ------------------------------------------------------------------------
+ // Construction
+ // ------------------------------------------------------------------------
+
+ Size() : Size(INVALID) {}
+ template <typename T>
+ Size(T&& w, T&& h)
+ : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
+ height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ int32_t getWidth() const { return width; }
+ int32_t getHeight() const { return height; }
+
+ template <typename T>
+ void setWidth(T&& v) {
+ width = Size::clamp<int32_t, T>(std::forward<T>(v));
+ }
+ template <typename T>
+ void setHeight(T&& v) {
+ height = Size::clamp<int32_t, T>(std::forward<T>(v));
+ }
+
+ // ------------------------------------------------------------------------
+ // Assignment
+ // ------------------------------------------------------------------------
+
+ void set(const Size& size) { *this = size; }
+ template <typename T>
+ void set(T&& w, T&& h) {
+ set(Size(std::forward<T>(w), std::forward<T>(h)));
+ }
+
+ // Sets the value to INVALID
+ void makeInvalid() { set(INVALID); }
+
+ // Sets the value to EMPTY
+ void clear() { set(EMPTY); }
+
+ // ------------------------------------------------------------------------
+ // Semantic checks
+ // ------------------------------------------------------------------------
+
+ // Valid means non-negative width and height
+ bool isValid() const { return width >= 0 && height >= 0; }
+
+ // Empty means zero width and height
+ bool isEmpty() const { return *this == EMPTY; }
+
+ // ------------------------------------------------------------------------
+ // Clamp Helpers
+ // ------------------------------------------------------------------------
+
+ // Note: We use only features available in C++11 here for compatibility with
+ // external targets which include this file directly or indirectly and which
+ // themselves use C++11.
+
+ // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
+ template <typename T>
+ using remove_cv_reference_t =
+ typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+ // Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
+ // clamping the input value to the output range if necessary.
+ template <typename ToType, typename FromType>
+ static Size::remove_cv_reference_t<ToType> clamp(
+ typename std::enable_if<
+ std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_bounded &&
+ std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_bounded,
+ FromType&&>::type v) {
+ static constexpr auto toHighest = std::numeric_limits<remove_cv_reference_t<ToType>>::max();
+ static constexpr auto toLowest =
+ std::numeric_limits<remove_cv_reference_t<ToType>>::lowest();
+ static constexpr auto fromHighest =
+ std::numeric_limits<remove_cv_reference_t<FromType>>::max();
+ static constexpr auto fromLowest =
+ std::numeric_limits<remove_cv_reference_t<FromType>>::lowest();
+
+ // A clamp is needed if the range of FromType is not a subset of the range of ToType
+ static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest);
+
+ // If a clamp is not needed, the conversion is just a trivial cast.
+ if (!isClampNeeded) {
+ return static_cast<ToType>(v);
+ }
+
+ // Otherwise we leverage implicit conversion to safely compare values of
+ // different types, to ensure we return a value clamped to the range of
+ // ToType.
+ return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
+ }
+};
+
+// ------------------------------------------------------------------------
+// Comparisons
+// ------------------------------------------------------------------------
+
+inline bool operator==(const Size& lhs, const Size& rhs) {
+ return lhs.width == rhs.width && lhs.height == rhs.height;
+}
+
+inline bool operator!=(const Size& lhs, const Size& rhs) {
+ return !operator==(lhs, rhs);
+}
+
+inline bool operator<(const Size& lhs, const Size& rhs) {
+ // Orders by increasing width, then height.
+ if (lhs.width != rhs.width) return lhs.width < rhs.width;
+ return lhs.height < rhs.height;
+}
+
+} // namespace ui
+} // namespace android
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 900a5c4..dcb26cf 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <string>
#include <hardware/hardware.h>
#include <math/vec2.h>
@@ -90,6 +91,7 @@
Transform inverse() const;
// for debugging
+ void dump(std::string& result, const char* name) const;
void dump(const char* name) const;
private:
diff --git a/libs/ui/include_vndk/ui/Size.h b/libs/ui/include_vndk/ui/Size.h
new file mode 120000
index 0000000..fd2b21b
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Size.h
@@ -0,0 +1 @@
+../../include/ui/Size.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 665469e..373fa4f 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -71,3 +71,10 @@
],
cflags: ["-Wall", "-Werror"],
}
+
+cc_test {
+ name: "Size_test",
+ shared_libs: ["libui"],
+ srcs: ["Size_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
new file mode 100644
index 0000000..69e1ac8
--- /dev/null
+++ b/libs/ui/tests/Size_test.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2019 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 "SizeTest"
+
+#include <cmath>
+#include <cstdlib>
+
+#include <ui/Size.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace ui {
+
+TEST(SizeTest, BasicConstructionAndEqualityComparison) {
+ Size s(123, 456);
+
+ EXPECT_EQ(123, s.width);
+ EXPECT_EQ(123, s.getWidth());
+
+ EXPECT_EQ(456, s.height);
+ EXPECT_EQ(456, s.getHeight());
+
+ EXPECT_EQ(Size(123, 456), s);
+ EXPECT_NE(Size(456, 123), s);
+}
+
+TEST(SizeTest, BasicLessThanComparison) {
+ EXPECT_TRUE(Size(0, 1) < Size(2, 3));
+ EXPECT_FALSE(Size(2, 3) < Size(0, 1));
+
+ EXPECT_TRUE(Size(0, 3) < Size(2, 1));
+ EXPECT_FALSE(Size(2, 1) < Size(0, 3));
+
+ EXPECT_TRUE(Size(0, 1) < Size(0, 3));
+ EXPECT_FALSE(Size(0, 3) < Size(0, 1));
+
+ EXPECT_FALSE(Size(1, 1) < Size(1, 1));
+}
+
+TEST(SizeTest, ValidAndEmpty) {
+ {
+ Size s;
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1, -1);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(1, -1000);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1000, 1);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1000, -1000);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ const auto& s = Size::INVALID;
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ s.makeInvalid();
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(0, 0);
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ const auto& s = Size::EMPTY;
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ s.clear();
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ EXPECT_TRUE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+}
+
+TEST(SizeTest, Set) {
+ {
+ Size s;
+ s.setWidth(0);
+ EXPECT_EQ(Size(0, -1), s);
+ }
+
+ {
+ Size s;
+ s.setHeight(0);
+ EXPECT_EQ(Size(-1, 0), s);
+ }
+
+ {
+ Size s;
+ s.set(123, 456);
+ EXPECT_EQ(Size(123, 456), s);
+ }
+}
+
+template <typename T, typename U>
+void ClampTest(T input, U expected) {
+ // The constructor, set(), setWidth() and setHeight() all allow arbitrary
+ // conversions from other numeric types, and implement clamping if necessary.
+
+ EXPECT_EQ(Size(expected, expected), Size(input, input));
+
+ {
+ Size s;
+ s.set(input, input);
+ EXPECT_EQ(Size(expected, expected), s);
+ }
+
+ {
+ Size s;
+ s.setWidth(input);
+ EXPECT_EQ(expected, s.width);
+ }
+
+ {
+ Size s;
+ s.setHeight(input);
+ EXPECT_EQ(expected, s.height);
+ }
+}
+
+TEST(SizeTest, Int8RangeIsNotClamped) {
+ ClampTest(std::numeric_limits<int8_t>::max(), std::numeric_limits<int8_t>::max());
+ ClampTest(int8_t(0), int8_t(0));
+ ClampTest(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::lowest());
+}
+
+TEST(SizeTest, FloatRangeIsClamped) {
+ ClampTest(std::numeric_limits<float>::max(), std::numeric_limits<int32_t>::max());
+ ClampTest(float(0), int32_t(0));
+ ClampTest(std::numeric_limits<float>::lowest(), std::numeric_limits<int32_t>::lowest());
+}
+
+} // namespace ui
+} // namespace android
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 f2c40fe..f5761d5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -162,39 +162,6 @@
void operator=(const BufferTraits&) = delete;
};
-struct DetachedBufferRPC {
- private:
- enum {
- kOpDetachedBufferBase = 1000,
-
- // Allocates a standalone DetachedBuffer not associated with any producer
- // consumer set.
- kOpCreate,
-
- // Imports the given channel handle to a DetachedBuffer, taking ownership.
- kOpImport,
-
- // Creates a DetachedBuffer client from an existing one. The new client will
- // share the same underlying gralloc buffer and ashmem region for metadata.
- kOpDuplicate,
- };
-
- // Aliases.
- using LocalChannelHandle = pdx::LocalChannelHandle;
- using LocalHandle = pdx::LocalHandle;
- using Void = pdx::rpc::Void;
-
- public:
- PDX_REMOTE_METHOD(Create, kOpCreate,
- void(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size));
- PDX_REMOTE_METHOD(Import, kOpImport, BufferTraits<LocalHandle>(Void));
- PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
-
- PDX_REMOTE_API(API, Create, Import, Duplicate);
-};
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 4f8bdbf..2829353 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -47,6 +47,7 @@
"liblog",
"libhardware",
"libnativewindow",
+ "libprocessgroup",
"libutils",
"libEGL",
"libGLESv1_CM",
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index b57383a..a8a8476 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -12,9 +12,9 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
-#include <cutils/sched_policy.h>
#include <log/log.h>
#include <private/dvr/display_client.h>
+#include <processgroup/sched_policy.h>
#include <sys/prctl.h>
#include <sys/resource.h>
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index dd8fbfc..f936ac0 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -375,12 +375,13 @@
auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
if (app_namespace && !android::base::StartsWith(layer, kSystemLayerLibraryDir)) {
bool native_bridge = false;
- std::string error_message;
- handle = OpenNativeLibrary(app_namespace, layer.c_str(), &native_bridge,
- &error_message);
+ char* error_message = nullptr;
+ handle = OpenNativeLibraryInNamespace(
+ app_namespace, layer.c_str(), &native_bridge, &error_message);
if (!handle) {
ALOGE("Failed to load layer %s with error: %s", layer.c_str(),
- error_message.c_str());
+ error_message);
+ android::NativeLoaderFreeErrorMessage(error_message);
return;
}
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index ad49cd6..a40443d 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -216,7 +216,7 @@
stream << " ";
stream << std::setw(10) << "State";
stream << " ";
- stream << std::setw(10) << "Index";
+ stream << std::setw(8) << "Index";
stream << std::endl;
for (auto iter = clientCount.begin(); iter != clientCount.end(); ++iter) {
@@ -251,6 +251,7 @@
stream << " ";
stream << "0x" << std::hex << std::setfill('0');
stream << std::setw(8) << /*State=*/state;
+ stream << std::dec << std::setfill(' ');
stream << " ";
stream << std::setw(8) << /*Index=*/index;
stream << std::endl;
diff --git a/services/displayservice/OWNERS b/services/displayservice/OWNERS
new file mode 100644
index 0000000..7a3e4c2
--- /dev/null
+++ b/services/displayservice/OWNERS
@@ -0,0 +1,2 @@
+smoreland@google.com
+lpy@google.com
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 9af189a..9d92435 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2155,7 +2155,7 @@
motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
- motionEntry->metaState, motionEntry->buttonState,
+ motionEntry->metaState, motionEntry->buttonState, motionEntry->classification,
xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
@@ -2491,6 +2491,7 @@
originalMotionEntry->flags,
originalMotionEntry->metaState,
originalMotionEntry->buttonState,
+ originalMotionEntry->classification,
originalMotionEntry->edgeFlags,
originalMotionEntry->xPrecision,
originalMotionEntry->yPrecision,
@@ -2707,7 +2708,7 @@
MotionEntry* newEntry = new MotionEntry(args->sequenceNum, args->eventTime,
args->deviceId, args->source, args->displayId, policyFlags,
args->action, args->actionButton, args->flags,
- args->metaState, args->buttonState,
+ args->metaState, args->buttonState, args->classification,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
@@ -2845,7 +2846,7 @@
policyFlags,
action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
- motionEvent->getEdgeFlags(),
+ motionEvent->getClassification(), motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties, samplePointerCoords,
@@ -2860,7 +2861,7 @@
motionEvent->getDisplayId(), policyFlags,
action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
- motionEvent->getEdgeFlags(),
+ motionEvent->getClassification(), motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties, samplePointerCoords,
@@ -4404,8 +4405,8 @@
InputDispatcher::MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
int32_t actionButton,
- int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- float xPrecision, float yPrecision, nsecs_t downTime,
+ int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
+ int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime,
uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset) :
@@ -4413,7 +4414,8 @@
eventTime(eventTime),
deviceId(deviceId), source(source), displayId(displayId), action(action),
actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState),
- edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision),
+ classification(classification), edgeFlags(edgeFlags),
+ xPrecision(xPrecision), yPrecision(yPrecision),
downTime(downTime), pointerCount(pointerCount) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -4430,9 +4432,10 @@
void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
- "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[",
+ "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[",
deviceId, source, displayId, motionActionToString(action).c_str(), actionButton, flags,
- metaState, buttonState, edgeFlags, xPrecision, yPrecision);
+ metaState, buttonState, motionClassificationToString(classification), edgeFlags,
+ xPrecision, yPrecision);
for (uint32_t i = 0; i < pointerCount; i++) {
if (i) {
@@ -4733,15 +4736,15 @@
for (size_t i = 0; i < mMotionMementos.size(); i++) {
const MotionMemento& memento = mMotionMementos.itemAt(i);
if (shouldCancelMotion(memento, options)) {
+ const int32_t action = memento.hovering ?
+ AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
outEvents.push(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
- memento.hovering
- ? AMOTION_EVENT_ACTION_HOVER_EXIT
- : AMOTION_EVENT_ACTION_CANCEL,
- memento.flags, 0, 0, 0, 0,
+ action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
memento.xPrecision, memento.yPrecision, memento.downTime,
memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
- 0, 0));
+ 0 /*xOffset*/, 0 /*yOffset*/));
}
}
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 49de6f3..327dbbd 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -535,6 +535,7 @@
int32_t flags;
int32_t metaState;
int32_t buttonState;
+ MotionClassification classification;
int32_t edgeFlags;
float xPrecision;
float yPrecision;
@@ -546,8 +547,9 @@
MotionEntry(uint32_t sequenceNum, nsecs_t eventTime,
int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- float xPrecision, float yPrecision, nsecs_t downTime, uint32_t pointerCount,
+ int32_t metaState, int32_t buttonState, MotionClassification classification,
+ int32_t edgeFlags, float xPrecision, float yPrecision,
+ nsecs_t downTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset);
virtual void appendDescription(std::string& msg) const;
diff --git a/services/sensorservice/SensorRecord.h b/services/sensorservice/SensorRecord.h
index 5a35410..031744a 100644
--- a/services/sensorservice/SensorRecord.h
+++ b/services/sensorservice/SensorRecord.h
@@ -25,7 +25,7 @@
class SensorService::SensorRecord {
public:
- SensorRecord(const sp<const SensorEventConnection>& connection);
+ explicit SensorRecord(const sp<const SensorEventConnection>& connection);
bool addConnection(const sp<const SensorEventConnection>& connection);
bool removeConnection(const wp<const SensorEventConnection>& connection);
size_t getNumConnections() const { return mConnections.size(); }
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index ddcee28..8d7a05b 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -43,7 +43,7 @@
struct SensorManager final : public ISensorManager {
- SensorManager(JavaVM* vm);
+ explicit SensorManager(JavaVM* vm);
~SensorManager();
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
index 495c14e..934ae58 100644
--- a/services/sensorservice/mat.h
+++ b/services/sensorservice/mat.h
@@ -139,13 +139,13 @@
mat() { }
mat(const mat& rhs) : base(rhs) { }
- mat(const base& rhs) : base(rhs) { } // NOLINT(implicit)
+ mat(const base& rhs) : base(rhs) { } // NOLINT(google-explicit-constructor)
// -----------------------------------------------------------------------
// conversion constructors
// sets the diagonal to the value, off-diagonal to zero
- mat(pTYPE rhs) { // NOLINT(implicit)
+ mat(pTYPE rhs) { // NOLINT(google-explicit-constructor)
helpers::doAssign(*this, rhs);
}
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
index 9e5d280..c195434 100644
--- a/services/sensorservice/vec.h
+++ b/services/sensorservice/vec.h
@@ -322,12 +322,12 @@
vec() { }
vec(const vec& rhs) : base(rhs) { }
- vec(const base& rhs) : base(rhs) { } // NOLINT(implicit)
+ vec(const base& rhs) : base(rhs) { } // NOLINT(google-explicit-constructor)
// -----------------------------------------------------------------------
// conversion constructors
- vec(pTYPE rhs) { // NOLINT(implicit)
+ vec(pTYPE rhs) { // NOLINT(google-explicit-constructor)
for (size_t i=0 ; i<SIZE ; i++)
base::operator[](i) = rhs;
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 5b3bbca..01c60d8 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -25,6 +25,7 @@
"android.hardware.configstore@1.1",
"android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -49,6 +50,7 @@
"liblog",
"libnativewindow",
"libpdx_default_transport",
+ "libprocessgroup",
"libprotobuf-cpp-lite",
"libsync",
"libtimestats_proto",
@@ -77,6 +79,7 @@
],
export_shared_lib_headers: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -114,6 +117,7 @@
"BufferLayerConsumer.cpp",
"BufferQueueLayer.cpp",
"BufferStateLayer.cpp",
+ "BufferStateLayerCache.cpp",
"Client.cpp",
"ColorLayer.cpp",
"ContainerLayer.cpp",
@@ -186,6 +190,7 @@
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"libbinder",
"libcutils",
"libdisplayservicehidl",
@@ -194,6 +199,7 @@
"libinput",
"liblayers_proto",
"liblog",
+ "libprocessgroup",
"libsync",
"libtimestats_proto",
"libutils",
@@ -226,6 +232,7 @@
"libcutils",
"libdl",
"liblog",
+ "libprocessgroup",
],
product_variables: {
// uses jni which may not be available in PDK
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e0d9d23..2132f59 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -48,10 +48,28 @@
// Interface implementation for Layer
// -----------------------------------------------------------------------
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;
+ // The previous release fence notifies the client that SurfaceFlinger is done with the previous
+ // buffer that was presented on this layer. The first transaction that came in this frame that
+ // replaced the previous buffer on this layer needs this release fence, because the fence will
+ // let the client know when that previous buffer is removed from the screen.
+ //
+ // Every other transaction on this layer does not need a release fence because no other
+ // Transactions that were set on this layer this frame are going to have their preceeding buffer
+ // removed from the display this frame.
+ //
+ // For example, if we have 3 transactions this frame. The first transaction doesn't contain a
+ // buffer so it doesn't need a previous release fence because the layer still needs the previous
+ // buffer. The second transaction contains a buffer so it needs a previous release fence because
+ // the previous buffer will be released this frame. The third transaction also contains a
+ // buffer. It replaces the buffer in the second transaction. The buffer in the second
+ // transaction will now no longer be presented so it is released immediately and the third
+ // transaction doesn't need a previous release fence.
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->releasePreviousBuffer) {
+ handle->previousReleaseFence = releaseFence;
+ break;
+ }
+ }
}
void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -60,7 +78,10 @@
}
void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
- return;
+ mFlinger->getTransactionCompletedThread().addPresentedCallbackHandles(
+ mDrawingState.callbackHandles);
+
+ mDrawingState.callbackHandles = {};
}
bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
@@ -257,14 +278,14 @@
// Notify the transaction completed thread that there is a pending latched callback
// handle
- mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+ mFlinger->getTransactionCompletedThread().registerPendingCallbackHandle(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);
+ mFlinger->getTransactionCompletedThread().addUnpresentedCallbackHandle(handle);
}
}
@@ -504,9 +525,9 @@
return BAD_VALUE;
}
- mFlinger->getTransactionCompletedThread()
- .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
- mPreviousReleaseFence);
+ for (auto& handle : mDrawingState.callbackHandles) {
+ handle->latchTime = latchTime;
+ }
// Handle sync fences
if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
new file mode 100644
index 0000000..c82ad7b
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 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 "BufferStateLayerCache"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BufferStateLayerCache.h"
+
+#define MAX_CACHE_SIZE 64
+
+namespace android {
+
+int32_t BufferStateLayerCache::add(const sp<IBinder>& processToken,
+ const sp<GraphicBuffer>& buffer) {
+ std::lock_guard lock(mMutex);
+
+ auto& processCache = getProccessCache(processToken);
+
+ int32_t slot = findSlot(processCache);
+ if (slot < 0) {
+ return slot;
+ }
+
+ processCache[slot] = buffer;
+
+ return slot;
+}
+
+void BufferStateLayerCache::release(const sp<IBinder>& processToken, int32_t id) {
+ if (id < 0) {
+ ALOGE("invalid buffer id");
+ return;
+ }
+
+ std::lock_guard lock(mMutex);
+ auto& processCache = getProccessCache(processToken);
+
+ if (id >= processCache.size()) {
+ ALOGE("invalid buffer id");
+ return;
+ }
+ processCache[id] = nullptr;
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, int32_t id) {
+ if (id < 0) {
+ ALOGE("invalid buffer id");
+ return nullptr;
+ }
+
+ std::lock_guard lock(mMutex);
+ auto& processCache = getProccessCache(processToken);
+
+ if (id >= processCache.size()) {
+ ALOGE("invalid buffer id");
+ return nullptr;
+ }
+ return processCache[id];
+}
+
+std::vector<sp<GraphicBuffer>>& BufferStateLayerCache::getProccessCache(
+ const sp<IBinder>& processToken) {
+ return mBuffers[processToken];
+}
+
+int32_t BufferStateLayerCache::findSlot(std::vector<sp<GraphicBuffer>>& processCache) {
+ int32_t slot = 0;
+
+ for (const sp<GraphicBuffer> buffer : processCache) {
+ if (!buffer) {
+ return slot;
+ }
+ slot++;
+ }
+
+ if (processCache.size() < MAX_CACHE_SIZE) {
+ processCache.push_back(nullptr);
+ return slot;
+ }
+
+ return -1;
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
new file mode 100644
index 0000000..623f0c6
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
+
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+
+class BufferStateLayerCache {
+public:
+ int32_t add(const sp<IBinder>& processToken, const sp<GraphicBuffer>& buffer);
+ void release(const sp<IBinder>& processToken, int32_t id);
+
+ sp<GraphicBuffer> get(const sp<IBinder>& processToken, int32_t id);
+
+private:
+ std::mutex mMutex;
+
+ std::vector<sp<GraphicBuffer>>& getProccessCache(const sp<IBinder>& processToken)
+ REQUIRES(mMutex);
+
+ int32_t findSlot(std::vector<sp<GraphicBuffer>>& proccessCache) REQUIRES(mMutex);
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+ };
+
+ std::unordered_map<sp<IBinder> /*caching process*/, std::vector<sp<GraphicBuffer>>, IBinderHash>
+ mBuffers GUARDED_BY(mMutex);
+};
+
+}; // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index ec5e131..49fa84a 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -16,6 +16,8 @@
"libgui",
"liblayers_proto",
"liblog",
+ "libnativewindow",
+ "libsync",
"libtimestats_proto",
"libui",
"libutils",
@@ -35,6 +37,13 @@
defaults: ["libcompositionengine_defaults"],
srcs: [
"src/CompositionEngine.cpp",
+ "src/Display.cpp",
+ "src/DisplayColorProfile.cpp",
+ "src/DisplaySurface.cpp",
+ "src/DumpHelpers.cpp",
+ "src/Output.cpp",
+ "src/OutputCompositionState.cpp",
+ "src/RenderSurface.cpp",
],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
@@ -45,6 +54,11 @@
defaults: ["libcompositionengine_defaults"],
srcs: [
"mock/CompositionEngine.cpp",
+ "mock/Display.cpp",
+ "mock/DisplayColorProfile.cpp",
+ "mock/DisplaySurface.cpp",
+ "mock/Output.cpp",
+ "mock/RenderSurface.cpp",
],
static_libs: [
"libgtest",
@@ -61,7 +75,11 @@
defaults: ["libcompositionengine_defaults"],
srcs: [
"tests/CompositionEngineTest.cpp",
+ "tests/DisplayColorProfileTest.cpp",
+ "tests/DisplayTest.cpp",
"tests/MockHWComposer.cpp",
+ "tests/OutputTest.cpp",
+ "tests/RenderSurfaceTest.cpp",
],
static_libs: [
"libcompositionengine",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index af8515f..30cdb49 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -28,6 +28,10 @@
namespace compositionengine {
+class Display;
+
+struct DisplayCreationArgs;
+
/**
* Encapsulates all the interfaces and implementation details for performing
* display output composition.
@@ -36,6 +40,9 @@
public:
virtual ~CompositionEngine();
+ // Create a composition Display
+ virtual std::shared_ptr<Display> createDisplay(DisplayCreationArgs&&) = 0;
+
virtual HWComposer& getHwComposer() const = 0;
virtual void setHwComposer(std::unique_ptr<HWComposer>) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
new file mode 100644
index 0000000..dbcd3bd
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <optional>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+#include <compositionengine/Output.h>
+
+namespace android::compositionengine {
+
+struct RenderSurfaceCreationArgs;
+struct DisplayColorProfileCreationArgs;
+
+/**
+ * A display is a composition target which may be backed by a hardware composer
+ * display device
+ */
+class Display : public virtual Output {
+public:
+ // Gets the HWC DisplayId for the display if there is one
+ virtual const std::optional<DisplayId>& getId() const = 0;
+
+ // True if the display is secure
+ virtual bool isSecure() const = 0;
+
+ // True if the display is virtual
+ virtual bool isVirtual() const = 0;
+
+ // Releases the use of the HWC display, if any
+ virtual void disconnect() = 0;
+
+ // Creates a render color mode for the display
+ virtual void createDisplayColorProfile(DisplayColorProfileCreationArgs&&) = 0;
+
+ // Creates a render surface for the display
+ virtual void createRenderSurface(RenderSurfaceCreationArgs&&) = 0;
+
+protected:
+ ~Display() = default;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
new file mode 100644
index 0000000..e2a0d42
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 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 <cstdint>
+
+#include <ui/GraphicTypes.h>
+
+namespace android {
+
+class HdrCapabilities;
+
+namespace compositionengine {
+
+/**
+ * Encapsulates all the state and functionality for how colors should be
+ * transformed for a display
+ */
+class DisplayColorProfile {
+public:
+ constexpr static float sDefaultMinLumiance = 0.0;
+ constexpr static float sDefaultMaxLumiance = 500.0;
+
+ virtual ~DisplayColorProfile();
+
+ // Returns true if the profile is valid. This is meant to be checked post-
+ // construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Returns true if the profile supports the indicated render intent
+ virtual bool hasRenderIntent(ui::RenderIntent) const = 0;
+
+ // Returns true if the profile supports the indicated dataspace
+ virtual bool hasLegacyHdrSupport(ui::Dataspace) const = 0;
+
+ // Obtains the best combination of color mode and render intent for the
+ // input values
+ virtual void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+ ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+ ui::RenderIntent* outIntent) const = 0;
+
+ // Returns true if the profile supports a wide color gamut
+ virtual bool hasWideColorGamut() const = 0;
+
+ // Returns the per-frame metadata value for this profile
+ virtual int32_t getSupportedPerFrameMetadata() const = 0;
+
+ // Returns true if HWC for this profile supports HDR10Plus
+ virtual bool hasHDR10PlusSupport() const = 0;
+
+ // Returns true if HWC for this profile supports HDR10
+ virtual bool hasHDR10Support() const = 0;
+
+ // Returns true if HWC for this profile supports HLG
+ virtual bool hasHLGSupport() const = 0;
+
+ // Returns true if HWC for this profile supports DolbyVision
+ virtual bool hasDolbyVisionSupport() const = 0;
+
+ // Gets the supported HDR capabilities for the profile
+ virtual const HdrCapabilities& getHdrCapabilities() const = 0;
+
+ // Debugging
+ virtual void dump(std::string&) const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
new file mode 100644
index 0000000..ef0f925
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <unordered_map>
+#include <vector>
+
+#include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine {
+
+/**
+ * A parameter object for creating DisplayColorProfile instances
+ */
+struct DisplayColorProfileCreationArgs {
+ using HwcColorModes = std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>;
+
+ // True if this display supports a wide color gamut
+ bool hasWideColorGamut;
+
+ // The HDR capabilities supported by the HWC
+ HdrCapabilities hdrCapabilities;
+
+ // The per-frame metadata supported by the HWC
+ int32_t supportedPerFrameMetadata;
+
+ // The mapping of color modes and render intents supported by the HWC
+ HwcColorModes hwcColorModes;
+};
+
+/**
+ * A helper for setting up a DisplayColorProfileCreationArgs value in-line.
+ *
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0,
+ * HwcColorModes()}
+ *
+ * Prefer:
+ *
+ * DisplayColorProfileCreationArgsBuilder().setHasWideColorGamut(false)
+ * .setIsVirtual(false).setDisplayId(displayId).Build();
+ */
+class DisplayColorProfileCreationArgsBuilder {
+public:
+ DisplayColorProfileCreationArgs Build() { return std::move(mArgs); }
+
+ DisplayColorProfileCreationArgsBuilder& setHasWideColorGamut(bool hasWideColorGamut) {
+ mArgs.hasWideColorGamut = hasWideColorGamut;
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setHdrCapabilities(HdrCapabilities&& hdrCapabilities) {
+ mArgs.hdrCapabilities = std::move(hdrCapabilities);
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setSupportedPerFrameMetadata(
+ int32_t supportedPerFrameMetadata) {
+ mArgs.supportedPerFrameMetadata = supportedPerFrameMetadata;
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setHwcColorModes(
+ DisplayColorProfileCreationArgs::HwcColorModes&& hwcColorModes) {
+ mArgs.hwcColorModes = std::move(hwcColorModes);
+ return *this;
+ }
+
+private:
+ DisplayColorProfileCreationArgs mArgs;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
new file mode 100644
index 0000000..0b6b4e4
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <optional>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+
+/**
+ * A parameter object for creating Display instances
+ */
+struct DisplayCreationArgs {
+ // True if this display is secure
+ bool isSecure = false;
+
+ // True if this display is a virtual display
+ bool isVirtual = false;
+
+ // Identifies the display to the HWC, if composition is supported by it
+ std::optional<DisplayId> displayId;
+};
+
+/**
+ * A helper for setting up a DisplayCreationArgs value in-line.
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * DisplayCreationArgs{false, false, displayId}
+ *
+ * Prefer:
+ *
+ * DisplayCreationArgsBuilder().setIsSecure(false).setIsVirtual(false)
+ * .setDisplayId(displayId).build();
+ */
+class DisplayCreationArgsBuilder {
+public:
+ DisplayCreationArgs build() { return std::move(mArgs); }
+
+ DisplayCreationArgsBuilder& setIsSecure(bool isSecure) {
+ mArgs.isSecure = isSecure;
+ return *this;
+ }
+ DisplayCreationArgsBuilder& setIsVirtual(bool isVirtual) {
+ mArgs.isVirtual = isVirtual;
+ return *this;
+ }
+ DisplayCreationArgsBuilder& setDisplayId(std::optional<DisplayId> displayId) {
+ mArgs.displayId = displayId;
+ return *this;
+ }
+
+private:
+ DisplayCreationArgs mArgs;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
similarity index 80%
rename from services/surfaceflinger/DisplayHardware/DisplaySurface.h
rename to services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index f744f5c..0e67acf 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -14,23 +14,27 @@
* limitations under the License.
*/
-#ifndef ANDROID_SF_DISPLAY_SURFACE_H
-#define ANDROID_SF_DISPLAY_SURFACE_H
+#pragma once
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
-// ---------------------------------------------------------------------------
namespace android {
-// ---------------------------------------------------------------------------
class Fence;
class IGraphicBufferProducer;
class String8;
+namespace compositionengine {
+
+/**
+ * An abstraction for working with a display surface (buffer queue)
+ */
class DisplaySurface : public virtual RefBase {
public:
+ virtual ~DisplaySurface();
+
// beginFrame is called at the beginning of the composition loop, before
// the configuration is known. The DisplaySurface should do anything it
// needs to do to enable HWComposer to decide how to compose the frame.
@@ -44,9 +48,9 @@
// GLES and HWC for this frame.
enum CompositionType {
COMPOSITION_UNKNOWN = 0,
- COMPOSITION_GLES = 1,
- COMPOSITION_HWC = 2,
- COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
+ COMPOSITION_GLES = 1,
+ COMPOSITION_HWC = 2,
+ COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
};
virtual status_t prepareFrame(CompositionType compositionType) = 0;
@@ -70,15 +74,7 @@
virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
-
-protected:
- DisplaySurface() {}
- virtual ~DisplaySurface() {}
};
-// ---------------------------------------------------------------------------
+} // namespace compositionengine
} // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_SF_DISPLAY_SURFACE_H
-
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
new file mode 100644
index 0000000..2d00f0c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <string>
+
+#include <math/mat4.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android::compositionengine {
+
+class DisplayColorProfile;
+class RenderSurface;
+
+namespace impl {
+struct OutputCompositionState;
+} // namespace impl
+
+/**
+ * Encapsulates all the state involved with composing layers for an output
+ */
+class Output {
+public:
+ // Returns true if the output is valid. This is meant to be checked post-
+ // construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Enables (or disables) composition on this output
+ virtual void setCompositionEnabled(bool) = 0;
+
+ // Sets the projection state to use
+ virtual void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) = 0;
+ // Sets the bounds to use
+ virtual void setBounds(const ui::Size&) = 0;
+
+ // Sets the layer stack filter for this output. If singleLayerStack is true,
+ // this output displays just the single layer stack specified by
+ // singleLayerStackId. Otherwise all layer stacks will be visible on this
+ // output.
+ virtual void setLayerStackFilter(bool singleLayerStack, uint32_t singleLayerStackId) = 0;
+
+ // Sets the color transform matrix to use
+ virtual void setColorTransform(const mat4&) = 0;
+
+ // Sets the output color mode
+ virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) = 0;
+
+ // Outputs a string with a state dump
+ virtual void dump(std::string&) const = 0;
+
+ // Gets the debug name for the output
+ virtual const std::string& getName() const = 0;
+
+ // Sets a debug name for the output
+ virtual void setName(const std::string&) = 0;
+
+ // Gets the current render color mode for the output
+ virtual DisplayColorProfile* getDisplayColorProfile() const = 0;
+
+ // Gets the current render surface for the output
+ virtual RenderSurface* getRenderSurface() const = 0;
+
+ using OutputCompositionState = compositionengine::impl::OutputCompositionState;
+
+ // Gets the raw composition state data for the output
+ // TODO(lpique): Make this protected once it is only internally called.
+ virtual const OutputCompositionState& getState() const = 0;
+
+ // Allows mutable access to the raw composition state data for the output.
+ // This is meant to be used by the various functions that are part of the
+ // composition process.
+ // TODO(lpique): Make this protected once it is only internally called.
+ virtual OutputCompositionState& editState() = 0;
+
+ // Gets the physical space dirty region. If repaintEverything is true, this
+ // will be the full display bounds. Internally the dirty region is stored in
+ // logical (aka layer stack) space.
+ virtual Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const = 0;
+
+ // Tests whether a given layerStackId belongs in this output
+ virtual bool belongsInOutput(uint32_t layerStackId) const = 0;
+
+protected:
+ ~Output() = default;
+
+ virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
+ virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
new file mode 100644
index 0000000..dd01b05
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <vector>
+
+#include <ui/Fence.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Size.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class GraphicBuffer;
+
+struct CompositionInfo;
+
+namespace compositionengine {
+
+/**
+ * Encapsulates everything for composing to a render surface with RenderEngine
+ */
+class RenderSurface {
+public:
+ virtual ~RenderSurface();
+
+ // Returns true if the render surface is valid. This is meant to be checked
+ // post-construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Performs one-time initialization of the render surface. This is meant
+ // to be called after the validation check.
+ virtual void initialize() = 0;
+
+ // Returns the bounds of the surface
+ virtual const ui::Size& getSize() const = 0;
+
+ // Gets the latest fence to pass to the HWC to signal that the surface
+ // buffer is done rendering
+ virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
+
+ // Sets the size of the surface
+ virtual void setDisplaySize(const ui::Size&) = 0;
+
+ // Sets the dataspace used for rendering the surface
+ virtual void setBufferDataspace(ui::Dataspace) = 0;
+
+ // Configures the protected rendering on the surface
+ virtual void setProtected(bool useProtected) = 0;
+
+ // Called to signal that rendering has started. 'mustRecompose' should be
+ // true if the entire frame must be recomposed.
+ virtual status_t beginFrame(bool mustRecompose) = 0;
+
+ // Prepares the frame for rendering
+ virtual status_t prepareFrame(std::vector<CompositionInfo>& compositionData) = 0;
+
+ // Allocates a buffer as scratch space for GPU composition
+ virtual sp<GraphicBuffer> dequeueBuffer() = 0;
+
+ // Queues the drawn buffer for consumption by HWC
+ virtual void queueBuffer() = 0;
+
+ // Called after the HWC calls are made to present the display
+ virtual void onPresentDisplayCompleted() = 0;
+
+ // Marks the current buffer has finished, so that it can be presented and
+ // swapped out
+ virtual void finishBuffer() = 0;
+
+ // Called to set the viewport and projection state for rendering into this
+ // surface
+ virtual void setViewportAndProjection() = 0;
+
+ // Called after the surface has been rendering to signal the surface should
+ // be made ready for displaying
+ virtual void flip() = 0;
+
+ // Debugging - Dumps the state of the RenderSurface to a string
+ virtual void dump(std::string& result) const = 0;
+
+ // Debugging - gets the page flip count for the RenderSurface
+ virtual std::uint32_t getPageFlipCount() const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
new file mode 100644
index 0000000..a1230b3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <memory>
+
+#include <compositionengine/DisplaySurface.h>
+#include <utils/StrongPointer.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+namespace compositionengine {
+
+class Display;
+
+/**
+ * A parameter object for creating RenderSurface instances
+ */
+struct RenderSurfaceCreationArgs {
+ // The initial width of the surface
+ int32_t displayWidth;
+
+ // The initial height of the surface
+ int32_t displayHeight;
+
+ // The ANativeWindow for the buffer queue for this surface
+ sp<ANativeWindow> nativeWindow;
+
+ // The DisplaySurface for this surface
+ sp<DisplaySurface> displaySurface;
+};
+
+/**
+ * A helper for setting up a RenderSurfaceCreationArgs value in-line.
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * RenderSurfaceCreationArgs{1000, 1000, nativeWindow, displaySurface}
+ *
+ * Prefer:
+ *
+ * RenderSurfaceCreationArgsBuilder().setDisplayWidth(1000).setDisplayHeight(1000)
+ * .setNativeWindow(nativeWindow).setDisplaySurface(displaySurface).Build();
+ */
+class RenderSurfaceCreationArgsBuilder {
+public:
+ RenderSurfaceCreationArgs build() { return std::move(mArgs); }
+
+ RenderSurfaceCreationArgsBuilder& setDisplayWidth(int32_t displayWidth) {
+ mArgs.displayWidth = displayWidth;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setDisplayHeight(int32_t displayHeight) {
+ mArgs.displayHeight = displayHeight;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setNativeWindow(sp<ANativeWindow> nativeWindow) {
+ mArgs.nativeWindow = nativeWindow;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setDisplaySurface(sp<DisplaySurface> displaySurface) {
+ mArgs.displaySurface = displaySurface;
+ return *this;
+ }
+
+private:
+ RenderSurfaceCreationArgs mArgs;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 86d1774..e23c431 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -25,6 +25,9 @@
CompositionEngine();
~CompositionEngine() override;
+ std::shared_ptr<compositionengine::Display> createDisplay(
+ compositionengine::DisplayCreationArgs&&) override;
+
HWComposer& getHwComposer() const override;
void setHwComposer(std::unique_ptr<HWComposer>) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
new file mode 100644
index 0000000..0e20c43
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 <memory>
+
+#include <compositionengine/Display.h>
+#include <compositionengine/impl/Output.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+
+struct DisplayCreationArgs;
+
+namespace impl {
+
+class Display : public compositionengine::impl::Output, public compositionengine::Display {
+public:
+ Display(const CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+ virtual ~Display();
+
+ // compositionengine::Output overrides
+ void dump(std::string&) const override;
+ void setColorTransform(const mat4&) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+
+ // compositionengine::Display overrides
+ const std::optional<DisplayId>& getId() const override;
+ bool isSecure() const override;
+ bool isVirtual() const override;
+ void disconnect() override;
+ void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override;
+ void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
+
+private:
+ const bool mIsVirtual;
+ std::optional<DisplayId> mId;
+};
+
+std::shared_ptr<compositionengine::Display> createDisplay(
+ const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
new file mode 100644
index 0000000..49c2d2c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <unordered_map>
+#include <vector>
+
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class Display;
+
+namespace impl {
+
+class DisplayColorProfile : public compositionengine::DisplayColorProfile {
+public:
+ DisplayColorProfile(DisplayColorProfileCreationArgs&&);
+ ~DisplayColorProfile() override;
+
+ bool isValid() const override;
+
+ bool hasRenderIntent(ui::RenderIntent intent) const override;
+ bool hasLegacyHdrSupport(ui::Dataspace dataspace) const override;
+ void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+ ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+ ui::RenderIntent* outIntent) const override;
+
+ bool hasWideColorGamut() const override;
+ int32_t getSupportedPerFrameMetadata() const override;
+
+ // Whether h/w composer has native support for specific HDR type.
+ bool hasHDR10PlusSupport() const override;
+ bool hasHDR10Support() const override;
+ bool hasHLGSupport() const override;
+ bool hasDolbyVisionSupport() const override;
+
+ const HdrCapabilities& getHdrCapabilities() const override;
+
+ void dump(std::string&) const override;
+
+private:
+ void populateColorModes(const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes);
+ void addColorMode(const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes,
+ const ui::ColorMode mode, const ui::RenderIntent intent);
+
+ // Mappings from desired Dataspace/RenderIntent to the supported
+ // Dataspace/ColorMode/RenderIntent.
+ using ColorModeKey = uint64_t;
+ struct ColorModeValue {
+ ui::Dataspace dataspace;
+ ui::ColorMode colorMode;
+ ui::RenderIntent renderIntent;
+ };
+
+ static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {
+ return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent);
+ }
+
+ // Need to know if display is wide-color capable or not.
+ // Initialized by SurfaceFlinger when the DisplayDevice is created.
+ // Fed to RenderEngine during composition.
+ bool mHasWideColorGamut{false};
+ int32_t mSupportedPerFrameMetadata{0};
+ bool mHasHdr10Plus{false};
+ bool mHasHdr10{false};
+ bool mHasHLG{false};
+ bool mHasDolbyVision{false};
+ HdrCapabilities mHdrCapabilities;
+ std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
+};
+
+std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
+ DisplayColorProfileCreationArgs&&);
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
new file mode 100644
index 0000000..782c8d7
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <string>
+#include <type_traits>
+
+#include <math/mat4.h>
+#include <ui/FloatRect.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android::compositionengine::impl {
+
+void dumpVal(std::string& out, const char* name, bool);
+void dumpVal(std::string& out, const char* name, const void*);
+void dumpVal(std::string& out, const char* name, int);
+void dumpVal(std::string& out, const char* name, float);
+void dumpVal(std::string& out, const char* name, uint32_t);
+void dumpHex(std::string& out, const char* name, uint64_t);
+void dumpVal(std::string& out, const char* name, const char* value);
+void dumpVal(std::string& out, const char* name, const std::string& value);
+
+// For enums with named values
+void dumpVal(std::string& out, const char* name, const char*, int);
+void dumpVal(std::string& out, const char* name, const std::string&, int);
+
+template <typename EnumType>
+void dumpVal(std::string& out, const char* name, const char* valueName, EnumType value) {
+ dumpVal(out, name, valueName, static_cast<std::underlying_type_t<EnumType>>(value));
+}
+
+template <typename EnumType>
+void dumpVal(std::string& out, const char* name, const std::string& valueName, EnumType value) {
+ dumpVal(out, name, valueName, static_cast<std::underlying_type_t<EnumType>>(value));
+}
+
+void dumpVal(std::string& out, const char* name, const FloatRect& rect);
+void dumpVal(std::string& out, const char* name, const Rect& rect);
+void dumpVal(std::string& out, const char* name, const Region& region);
+void dumpVal(std::string& out, const char* name, const ui::Transform&);
+void dumpVal(std::string& out, const char* name, const ui::Size&);
+
+void dumpVal(std::string& out, const char* name, const mat4& tr);
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
new file mode 100644
index 0000000..521e1d7
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2019 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 <memory>
+
+#include <compositionengine/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+
+namespace impl {
+
+class Output : public virtual compositionengine::Output {
+public:
+ Output(const CompositionEngine&);
+ virtual ~Output();
+
+ bool isValid() const override;
+
+ void setCompositionEnabled(bool) override;
+ void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) override;
+ void setBounds(const ui::Size&) override;
+ void setLayerStackFilter(bool singleLayerStack, uint32_t singleLayerStackId) override;
+
+ void setColorTransform(const mat4&) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+
+ void dump(std::string&) const override;
+
+ const std::string& getName() const override;
+ void setName(const std::string&) override;
+
+ compositionengine::DisplayColorProfile* getDisplayColorProfile() const override;
+ void setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile>) override;
+
+ compositionengine::RenderSurface* getRenderSurface() const override;
+ void setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>) override;
+
+ const OutputCompositionState& getState() const override;
+ OutputCompositionState& editState() override;
+
+ Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const override;
+ bool belongsInOutput(uint32_t) const override;
+
+ // Testing
+ void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
+ void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
+
+protected:
+ const CompositionEngine& getCompositionEngine() const;
+ void dumpBase(std::string&) const;
+
+private:
+ void dirtyEntireOutput();
+
+ const CompositionEngine& mCompositionEngine;
+
+ std::string mName;
+
+ OutputCompositionState mState;
+
+ std::unique_ptr<compositionengine::DisplayColorProfile> mDisplayColorProfile;
+ std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
+};
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
new file mode 100644
index 0000000..96a0e0f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019 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 <cstdint>
+
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android {
+
+namespace compositionengine::impl {
+
+struct OutputCompositionState {
+ // If false, composition will not per performed for this display
+ bool isEnabled{false};
+
+ // If false, this output is not considered secure
+ bool isSecure{false};
+
+ // If true, only layer stacks with a matching layerStack value will be
+ // displayed. If false, all layer stacks will be displayed.
+ bool singleLayerStack{true};
+
+ // The layer stack to display on this display
+ uint32_t singleLayerStackId{~0u};
+
+ // The physical space screen bounds
+ Rect bounds;
+
+ // The logical to physical transformation to use
+ ui::Transform transform;
+
+ // The physical orientation of the display, expressed as ui::Transform
+ // orientation flags.
+ uint32_t orientation{0};
+
+ // The logical space user visible bounds
+ Rect frame;
+
+ // The logical space user viewport rectangle
+ Rect viewport;
+
+ // The physical space scissor rectangle
+ Rect scissor;
+
+ // If true, RenderEngine filtering should be enabled
+ bool needsFiltering{false};
+
+ // The logical coordinates for the dirty region for the display.
+ // dirtyRegion is semi-persistent state. Dirty rectangles are added to it
+ // by the FE until composition happens, at which point it is cleared.
+ Region dirtyRegion;
+
+ // The logical coordinates for the undefined region for the display.
+ // The undefined region is internal to the composition engine. It is
+ // updated every time the geometry changes.
+ Region undefinedRegion;
+
+ // True if the last composition frame had visible layers
+ bool lastCompositionHadVisibleLayers{false};
+
+ // The color transform to apply
+ android_color_transform_t colorTransform{HAL_COLOR_TRANSFORM_IDENTITY};
+
+ // Current active color mode
+ ui::ColorMode colorMode{ui::ColorMode::NATIVE};
+
+ // Current active render intent
+ ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
+
+ // Current active dstaspace
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
+ // Debugging
+ void dump(std::string& result) const;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
new file mode 100644
index 0000000..0489310
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019 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 <memory>
+
+#include <android-base/unique_fd.h>
+#include <compositionengine/RenderSurface.h>
+#include <utils/StrongPointer.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+namespace compositionengine {
+
+class CompositionEngine;
+class Display;
+class DisplaySurface;
+
+struct RenderSurfaceCreationArgs;
+
+namespace impl {
+
+class RenderSurface : public compositionengine::RenderSurface {
+public:
+ RenderSurface(const CompositionEngine&, compositionengine::Display&,
+ compositionengine::RenderSurfaceCreationArgs&&);
+ ~RenderSurface() override;
+
+ bool isValid() const override;
+ void initialize() override;
+ const ui::Size& getSize() const override;
+
+ const sp<Fence>& getClientTargetAcquireFence() const override;
+ void setBufferDataspace(ui::Dataspace) override;
+ void setDisplaySize(const ui::Size&) override;
+ void setProtected(bool useProtected) override;
+ status_t beginFrame(bool mustRecompose) override;
+ status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
+ sp<GraphicBuffer> dequeueBuffer() override;
+ void queueBuffer() override;
+ void onPresentDisplayCompleted() override;
+ void finishBuffer() override;
+ void setViewportAndProjection() override;
+ void flip() override;
+
+ // Debugging
+ void dump(std::string& result) const override;
+ std::uint32_t getPageFlipCount() const override;
+
+ // Testing
+ void setPageFlipCountForTest(std::uint32_t);
+ void setSizeForTest(const ui::Size&);
+ sp<GraphicBuffer>& mutableGraphicBufferForTest();
+ base::unique_fd& mutableBufferReadyForTest();
+
+private:
+ const compositionengine::CompositionEngine& mCompositionEngine;
+ const compositionengine::Display& mDisplay;
+
+ // ANativeWindow being rendered into
+ const sp<ANativeWindow> mNativeWindow;
+ // Current buffer being rendered into
+ sp<GraphicBuffer> mGraphicBuffer;
+ // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
+ // that drawing to the buffer is now complete.
+ base::unique_fd mBufferReady;
+ const sp<DisplaySurface> mDisplaySurface;
+ ui::Size mSize;
+ std::uint32_t mPageFlipCount{0};
+};
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+ const compositionengine::CompositionEngine&, compositionengine::Display&,
+ compositionengine::RenderSurfaceCreationArgs&&);
+
+} // namespace impl
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 9ba213e..1967666 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -17,6 +17,7 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayCreationArgs.h>
#include <gmock/gmock.h>
#include <renderengine/RenderEngine.h>
@@ -29,6 +30,8 @@
CompositionEngine();
~CompositionEngine() override;
+ MOCK_METHOD1(createDisplay, std::shared_ptr<Display>(DisplayCreationArgs&&));
+
MOCK_CONST_METHOD0(getHwComposer, HWComposer&());
MOCK_METHOD1(setHwComposer, void(std::unique_ptr<HWComposer>));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
new file mode 100644
index 0000000..d763aa6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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 <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/mock/Output.h>
+#include <gmock/gmock.h>
+#include <system/window.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine::mock {
+
+class Display : public compositionengine::mock::Output, public compositionengine::Display {
+public:
+ Display();
+ virtual ~Display();
+
+ MOCK_CONST_METHOD0(getId, const std::optional<DisplayId>&());
+ MOCK_CONST_METHOD0(isSecure, bool());
+ MOCK_CONST_METHOD0(isVirtual, bool());
+
+ MOCK_METHOD0(disconnect, void());
+
+ MOCK_METHOD1(createDisplayColorProfile, void(DisplayColorProfileCreationArgs&&));
+ MOCK_METHOD1(createRenderSurface, void(RenderSurfaceCreationArgs&&));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
new file mode 100644
index 0000000..8056c9d
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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 <compositionengine/DisplayColorProfile.h>
+#include <gmock/gmock.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine::mock {
+
+class DisplayColorProfile : public compositionengine::DisplayColorProfile {
+public:
+ DisplayColorProfile();
+ ~DisplayColorProfile() override;
+
+ MOCK_CONST_METHOD0(isValid, bool());
+
+ MOCK_CONST_METHOD1(hasRenderIntent, bool(ui::RenderIntent));
+ MOCK_CONST_METHOD1(hasLegacyHdrSupport, bool(ui::Dataspace));
+ MOCK_CONST_METHOD5(getBestColorMode,
+ void(ui::Dataspace, ui::RenderIntent, ui::Dataspace*, ui::ColorMode*,
+ ui::RenderIntent*));
+ MOCK_CONST_METHOD0(hasWideColorGamut, bool());
+ MOCK_CONST_METHOD0(getSupportedPerFrameMetadata, int32_t());
+ MOCK_CONST_METHOD0(hasHDR10PlusSupport, bool());
+ MOCK_CONST_METHOD0(hasHDR10Support, bool());
+ MOCK_CONST_METHOD0(hasHLGSupport, bool());
+ MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool());
+
+ MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&());
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
similarity index 81%
rename from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h
rename to services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
index d6c9aa4..31b5f95 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -16,16 +16,13 @@
#pragma once
+#include <compositionengine/DisplaySurface.h>
#include <gmock/gmock.h>
-
#include <utils/String8.h>
-#include "DisplayHardware/DisplaySurface.h"
+namespace android::compositionengine::mock {
-namespace android {
-namespace mock {
-
-class DisplaySurface : public android::DisplaySurface {
+class DisplaySurface : public compositionengine::DisplaySurface {
public:
DisplaySurface();
~DisplaySurface() override;
@@ -39,5 +36,4 @@
MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
};
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
new file mode 100644
index 0000000..37f7007
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Output.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+class Output : public virtual compositionengine::Output {
+public:
+ Output();
+ virtual ~Output();
+
+ MOCK_CONST_METHOD0(isValid, bool());
+
+ MOCK_METHOD1(setCompositionEnabled, void(bool));
+ MOCK_METHOD6(setProjection,
+ void(const ui::Transform&, int32_t, const Rect&, const Rect&, const Rect&, bool));
+ MOCK_METHOD1(setBounds, void(const ui::Size&));
+ MOCK_METHOD2(setLayerStackFilter, void(bool, uint32_t));
+
+ MOCK_METHOD1(setColorTransform, void(const mat4&));
+ MOCK_METHOD3(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent));
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+ MOCK_CONST_METHOD0(getName, const std::string&());
+ MOCK_METHOD1(setName, void(const std::string&));
+
+ MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*());
+ MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr<DisplayColorProfile>));
+
+ MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
+ MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));
+
+ MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
+ MOCK_METHOD0(editState, OutputCompositionState&());
+
+ MOCK_CONST_METHOD1(getPhysicalSpaceDirtyRegion, Region(bool));
+ MOCK_CONST_METHOD1(belongsInOutput, bool(uint32_t));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
new file mode 100644
index 0000000..2269e57
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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 <compositionengine/RenderSurface.h>
+#include <gmock/gmock.h>
+#include <ui/GraphicBuffer.h>
+
+#include "LayerBE.h"
+
+namespace android::compositionengine::mock {
+
+class RenderSurface : public compositionengine::RenderSurface {
+public:
+ RenderSurface();
+ ~RenderSurface() override;
+
+ MOCK_CONST_METHOD0(isValid, bool());
+ MOCK_METHOD0(initialize, void());
+ MOCK_CONST_METHOD0(getSize, const ui::Size&());
+ MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
+ MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
+ MOCK_METHOD1(setProtected, void(bool));
+ MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
+ MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
+ MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
+ MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
+ MOCK_METHOD0(queueBuffer, void());
+ MOCK_METHOD0(onPresentDisplayCompleted, void());
+ MOCK_METHOD0(finishBuffer, void());
+ MOCK_METHOD0(setViewportAndProjection, void());
+ MOCK_METHOD0(flip, void());
+ MOCK_CONST_METHOD1(dump, void(std::string& result));
+ MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/Display.cpp
similarity index 60%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/Display.cpp
index e6ac6bf..01cf112 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Display.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/Display.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Display::Display() = default;
+Display::~Display() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
similarity index 66%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
index e6ac6bf..581d1f7 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
- *
+ * Copyright 2019 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
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/DisplayColorProfile.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+DisplayColorProfile::DisplayColorProfile() = default;
+DisplayColorProfile::~DisplayColorProfile() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
similarity index 67%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
index e6ac6bf..bbbd7c1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "compositionengine/mock/DisplaySurface.h"
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
DisplaySurface::DisplaySurface() = default;
DisplaySurface::~DisplaySurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/Output.cpp
similarity index 60%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/Output.cpp
index e6ac6bf..44df4c3 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Output.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/Output.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Output::Output() = default;
+Output::~Output() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
similarity index 68%
rename from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
rename to services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
index e6ac6bf..fe718d6 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
- *
+ * Copyright 2019 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
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/RenderSurface.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+RenderSurface::RenderSurface() = default;
+RenderSurface::~RenderSurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index fbf71b5..127d729 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -15,6 +15,7 @@
*/
#include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/impl/Display.h>
#include <renderengine/RenderEngine.h>
#include "DisplayHardware/HWComposer.h"
@@ -32,6 +33,11 @@
CompositionEngine::CompositionEngine() = default;
CompositionEngine::~CompositionEngine() = default;
+std::shared_ptr<compositionengine::Display> CompositionEngine::createDisplay(
+ DisplayCreationArgs&& args) {
+ return compositionengine::impl::createDisplay(*this, std::move(args));
+}
+
HWComposer& CompositionEngine::getHwComposer() const {
return *mHwComposer.get();
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
new file mode 100644
index 0000000..f9d70e3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine::impl {
+
+std::shared_ptr<compositionengine::Display> createDisplay(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::DisplayCreationArgs&& args) {
+ return std::make_shared<Display>(compositionEngine, std::move(args));
+}
+
+Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args)
+ : compositionengine::impl::Output(compositionEngine),
+ mIsVirtual(args.isVirtual),
+ mId(args.displayId) {
+ editState().isSecure = args.isSecure;
+}
+
+Display::~Display() = default;
+
+const std::optional<DisplayId>& Display::getId() const {
+ return mId;
+}
+
+bool Display::isSecure() const {
+ return getState().isSecure;
+}
+
+bool Display::isVirtual() const {
+ return mIsVirtual;
+}
+
+void Display::disconnect() {
+ if (!mId) {
+ return;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.disconnectDisplay(*mId);
+ mId.reset();
+}
+
+void Display::setColorTransform(const mat4& transform) {
+ Output::setColorTransform(transform);
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ status_t result = hwc.setColorTransform(*mId, transform);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d",
+ mId ? to_string(*mId).c_str() : "", result);
+}
+
+void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
+ ui::RenderIntent renderIntent) {
+ if (mode == getState().colorMode && dataspace == getState().dataspace &&
+ renderIntent == getState().renderIntent) {
+ return;
+ }
+
+ if (mIsVirtual) {
+ ALOGW("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
+ Output::setColorMode(mode, dataspace, renderIntent);
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.setActiveColorMode(*mId, mode, renderIntent);
+}
+
+void Display::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str());
+
+ out.append("\n ");
+
+ dumpVal(out, "isVirtual", mIsVirtual);
+ if (mId) {
+ dumpVal(out, "hwcId", to_string(*mId));
+ } else {
+ StringAppendF(&out, "no hwcId, ");
+ }
+
+ out.append("\n");
+
+ Output::dumpBase(out);
+}
+
+void Display::createDisplayColorProfile(DisplayColorProfileCreationArgs&& args) {
+ setDisplayColorProfile(compositionengine::impl::createDisplayColorProfile(std::move(args)));
+}
+
+void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) {
+ setRenderSurface(compositionengine::impl::createRenderSurface(getCompositionEngine(), *this,
+ std::move(args)));
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
new file mode 100644
index 0000000..6e6f3c0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2019 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 <array>
+#include <unordered_set>
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <log/log.h>
+#include <ui/DebugUtils.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+DisplayColorProfile::~DisplayColorProfile() = default;
+
+namespace impl {
+namespace {
+
+using ui::ColorMode;
+using ui::Dataspace;
+using ui::RenderIntent;
+
+// ordered list of known SDR color modes
+const std::array<ColorMode, 3> sSdrColorModes = {
+ ColorMode::DISPLAY_BT2020,
+ ColorMode::DISPLAY_P3,
+ ColorMode::SRGB,
+};
+
+// ordered list of known HDR color modes
+const std::array<ColorMode, 2> sHdrColorModes = {
+ ColorMode::BT2100_PQ,
+ ColorMode::BT2100_HLG,
+};
+
+// ordered list of known SDR render intents
+const std::array<RenderIntent, 2> sSdrRenderIntents = {
+ RenderIntent::ENHANCE,
+ RenderIntent::COLORIMETRIC,
+};
+
+// ordered list of known HDR render intents
+const std::array<RenderIntent, 2> sHdrRenderIntents = {
+ RenderIntent::TONE_MAP_ENHANCE,
+ RenderIntent::TONE_MAP_COLORIMETRIC,
+};
+
+// map known color mode to dataspace
+Dataspace colorModeToDataspace(ColorMode mode) {
+ switch (mode) {
+ case ColorMode::SRGB:
+ return Dataspace::V0_SRGB;
+ case ColorMode::DISPLAY_P3:
+ return Dataspace::DISPLAY_P3;
+ case ColorMode::DISPLAY_BT2020:
+ return Dataspace::DISPLAY_BT2020;
+ case ColorMode::BT2100_HLG:
+ return Dataspace::BT2020_HLG;
+ case ColorMode::BT2100_PQ:
+ return Dataspace::BT2020_PQ;
+ default:
+ return Dataspace::UNKNOWN;
+ }
+}
+
+// Return a list of candidate color modes.
+std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
+ std::vector<ColorMode> candidates;
+
+ // add mode itself
+ candidates.push_back(mode);
+
+ // check if mode is HDR
+ bool isHdr = false;
+ for (auto hdrMode : sHdrColorModes) {
+ if (hdrMode == mode) {
+ isHdr = true;
+ break;
+ }
+ }
+
+ // add other HDR candidates when mode is HDR
+ if (isHdr) {
+ for (auto hdrMode : sHdrColorModes) {
+ if (hdrMode != mode) {
+ candidates.push_back(hdrMode);
+ }
+ }
+ }
+
+ // add other SDR candidates
+ for (auto sdrMode : sSdrColorModes) {
+ if (sdrMode != mode) {
+ candidates.push_back(sdrMode);
+ }
+ }
+
+ return candidates;
+}
+
+// Return a list of candidate render intents.
+std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
+ std::vector<RenderIntent> candidates;
+
+ // add intent itself
+ candidates.push_back(intent);
+
+ // check if intent is HDR
+ bool isHdr = false;
+ for (auto hdrIntent : sHdrRenderIntents) {
+ if (hdrIntent == intent) {
+ isHdr = true;
+ break;
+ }
+ }
+
+ if (isHdr) {
+ // add other HDR candidates when intent is HDR
+ for (auto hdrIntent : sHdrRenderIntents) {
+ if (hdrIntent != intent) {
+ candidates.push_back(hdrIntent);
+ }
+ }
+ } else {
+ // add other SDR candidates when intent is SDR
+ for (auto sdrIntent : sSdrRenderIntents) {
+ if (sdrIntent != intent) {
+ candidates.push_back(sdrIntent);
+ }
+ }
+ }
+
+ return candidates;
+}
+
+// Return the best color mode supported by HWC.
+ColorMode getHwcColorMode(
+ const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
+ ColorMode mode) {
+ std::vector<ColorMode> candidates = getColorModeCandidates(mode);
+ for (auto candidate : candidates) {
+ auto iter = hwcColorModes.find(candidate);
+ if (iter != hwcColorModes.end()) {
+ return candidate;
+ }
+ }
+
+ return ColorMode::NATIVE;
+}
+
+// Return the best render intent supported by HWC.
+RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
+ std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
+ for (auto candidate : candidates) {
+ for (auto hwcIntent : hwcIntents) {
+ if (candidate == hwcIntent) {
+ return candidate;
+ }
+ }
+ }
+
+ return RenderIntent::COLORIMETRIC;
+}
+
+} // anonymous namespace
+
+std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
+ DisplayColorProfileCreationArgs&& args) {
+ return std::make_unique<DisplayColorProfile>(std::move(args));
+}
+
+DisplayColorProfile::DisplayColorProfile(DisplayColorProfileCreationArgs&& args)
+ : mHasWideColorGamut(args.hasWideColorGamut),
+ mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
+ populateColorModes(args.hwcColorModes);
+
+ std::vector<ui::Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
+ for (ui::Hdr hdrType : types) {
+ switch (hdrType) {
+ case ui::Hdr::HDR10_PLUS:
+ mHasHdr10Plus = true;
+ break;
+ case ui::Hdr::HDR10:
+ mHasHdr10 = true;
+ break;
+ case ui::Hdr::HLG:
+ mHasHLG = true;
+ break;
+ case ui::Hdr::DOLBY_VISION:
+ mHasDolbyVision = true;
+ break;
+ default:
+ ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
+ }
+ }
+
+ float minLuminance = args.hdrCapabilities.getDesiredMinLuminance();
+ float maxLuminance = args.hdrCapabilities.getDesiredMaxLuminance();
+ float maxAverageLuminance = args.hdrCapabilities.getDesiredMaxAverageLuminance();
+
+ minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
+ maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
+ maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
+ if (args.hasWideColorGamut) {
+ // insert HDR10/HLG as we will force client composition for HDR10/HLG
+ // layers
+ if (!hasHDR10Support()) {
+ types.push_back(ui::Hdr::HDR10);
+ }
+
+ if (!hasHLGSupport()) {
+ types.push_back(ui::Hdr::HLG);
+ }
+ }
+
+ mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
+}
+
+DisplayColorProfile::~DisplayColorProfile() = default;
+
+bool DisplayColorProfile::isValid() const {
+ return true;
+}
+
+bool DisplayColorProfile::hasWideColorGamut() const {
+ return mHasWideColorGamut;
+}
+
+int32_t DisplayColorProfile::getSupportedPerFrameMetadata() const {
+ return mSupportedPerFrameMetadata;
+}
+
+bool DisplayColorProfile::hasHDR10PlusSupport() const {
+ return mHasHdr10Plus;
+}
+
+bool DisplayColorProfile::hasHDR10Support() const {
+ return mHasHdr10;
+}
+
+bool DisplayColorProfile::hasHLGSupport() const {
+ return mHasHLG;
+}
+
+bool DisplayColorProfile::hasDolbyVisionSupport() const {
+ return mHasDolbyVision;
+}
+
+const HdrCapabilities& DisplayColorProfile::getHdrCapabilities() const {
+ return mHdrCapabilities;
+}
+
+void DisplayColorProfile::populateColorModes(
+ const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes) {
+ if (!hasWideColorGamut()) {
+ return;
+ }
+
+ // collect all known SDR render intents
+ std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
+ sSdrRenderIntents.end());
+ auto iter = hwcColorModes.find(ColorMode::SRGB);
+ if (iter != hwcColorModes.end()) {
+ for (auto intent : iter->second) {
+ sdrRenderIntents.insert(intent);
+ }
+ }
+
+ // add all known SDR combinations
+ for (auto intent : sdrRenderIntents) {
+ for (auto mode : sSdrColorModes) {
+ addColorMode(hwcColorModes, mode, intent);
+ }
+ }
+
+ // collect all known HDR render intents
+ std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
+ sHdrRenderIntents.end());
+ iter = hwcColorModes.find(ColorMode::BT2100_PQ);
+ if (iter != hwcColorModes.end()) {
+ for (auto intent : iter->second) {
+ hdrRenderIntents.insert(intent);
+ }
+ }
+
+ // add all known HDR combinations
+ for (auto intent : sHdrRenderIntents) {
+ for (auto mode : sHdrColorModes) {
+ addColorMode(hwcColorModes, mode, intent);
+ }
+ }
+}
+
+// Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
+// supported by HWC.
+void DisplayColorProfile::addColorMode(
+ const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes, const ColorMode mode,
+ const RenderIntent intent) {
+ // find the best color mode
+ const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
+
+ // find the best render intent
+ auto iter = hwcColorModes.find(hwcColorMode);
+ const auto& hwcIntents =
+ iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
+ const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
+
+ const Dataspace dataspace = colorModeToDataspace(mode);
+ const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
+
+ ALOGV("DisplayColorProfile: map (%s, %s) to (%s, %s, %s)",
+ dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+ decodeRenderIntent(intent).c_str(),
+ dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
+ decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
+
+ mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
+}
+
+bool DisplayColorProfile::hasRenderIntent(RenderIntent intent) const {
+ // assume a render intent is supported when SRGB supports it; we should
+ // get rid of that assumption.
+ auto iter = mColorModes.find(getColorModeKey(Dataspace::V0_SRGB, intent));
+ return iter != mColorModes.end() && iter->second.renderIntent == intent;
+}
+
+bool DisplayColorProfile::hasLegacyHdrSupport(Dataspace dataspace) const {
+ if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
+ (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
+ auto iter =
+ mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
+ return iter == mColorModes.end() || iter->second.dataspace != dataspace;
+ }
+
+ return false;
+}
+
+void DisplayColorProfile::getBestColorMode(Dataspace dataspace, RenderIntent intent,
+ Dataspace* outDataspace, ColorMode* outMode,
+ RenderIntent* outIntent) const {
+ auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
+ if (iter != mColorModes.end()) {
+ *outDataspace = iter->second.dataspace;
+ *outMode = iter->second.colorMode;
+ *outIntent = iter->second.renderIntent;
+ } else {
+ // this is unexpected on a WCG display
+ if (hasWideColorGamut()) {
+ ALOGE("map unknown (%s)/(%s) to default color mode",
+ dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+ decodeRenderIntent(intent).c_str());
+ }
+
+ *outDataspace = Dataspace::UNKNOWN;
+ *outMode = ColorMode::NATIVE;
+ *outIntent = RenderIntent::COLORIMETRIC;
+ }
+}
+
+void DisplayColorProfile::dump(std::string& out) const {
+ out.append(" Composition Display Color State:");
+
+ out.append("\n HWC Support: ");
+
+ dumpVal(out, "wideColorGamut", hasWideColorGamut());
+ dumpVal(out, "hdr10plus", hasHDR10PlusSupport());
+ dumpVal(out, "hdr10", hasHDR10Support());
+ dumpVal(out, "hlg", hasHLGSupport());
+ dumpVal(out, "dv", hasDolbyVisionSupport());
+ dumpVal(out, "metadata", getSupportedPerFrameMetadata());
+
+ out.append("\n");
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
similarity index 68%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
index e6ac6bf..db6d4f2 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,10 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/DisplaySurface.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
DisplaySurface::~DisplaySurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
new file mode 100644
index 0000000..c497013
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019 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 <cinttypes>
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/impl/DumpHelpers.h>
+
+namespace android::compositionengine::impl {
+
+using android::base::StringAppendF;
+
+void dumpVal(std::string& out, const char* name, bool value) {
+ StringAppendF(&out, "%s=%c ", name, value ? 'T' : 'F');
+}
+
+void dumpVal(std::string& out, const char* name, const void* value) {
+ StringAppendF(&out, "%s=%p ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, int value) {
+ StringAppendF(&out, "%s=%d ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, float value) {
+ StringAppendF(&out, "%s=%f ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, uint32_t value) {
+ StringAppendF(&out, "%s=%u ", name, value);
+}
+
+void dumpHex(std::string& out, const char* name, uint64_t value) {
+ StringAppendF(&out, "%s=0x08%" PRIx64 " ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, const char* value) {
+ StringAppendF(&out, "%s=%s ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, const std::string& value) {
+ dumpVal(out, name, value.c_str());
+}
+
+void dumpVal(std::string& out, const char* name, const char* valueName, int value) {
+ StringAppendF(&out, "%s=%s (%d)", name, valueName, value);
+}
+
+void dumpVal(std::string& out, const char* name, const std::string& valueName, int value) {
+ dumpVal(out, name, valueName.c_str(), value);
+}
+
+void dumpVal(std::string& out, const char* name, const FloatRect& rect) {
+ StringAppendF(&out, "%s=[%f %f %f %f] ", name, rect.left, rect.top, rect.right, rect.bottom);
+}
+
+void dumpVal(std::string& out, const char* name, const Rect& rect) {
+ StringAppendF(&out, "%s=[%d %d %d %d] ", name, rect.left, rect.top, rect.right, rect.bottom);
+}
+
+void dumpVal(std::string& out, const char* name, const Region& region) {
+ region.dump(out, name, 0);
+}
+
+void dumpVal(std::string& out, const char* name, const ui::Transform& transform) {
+ transform.dump(out, name);
+}
+
+void dumpVal(std::string& out, const char* name, const ui::Size& size) {
+ StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
+}
+
+void dumpVal(std::string& out, const char* name, const mat4& tr) {
+ StringAppendF(&out,
+ "%s=["
+ /* clang-format off */
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]]",
+ name,
+ tr[0][0], tr[1][0], tr[2][0], tr[3][0],
+ tr[0][1], tr[1][1], tr[2][1], tr[3][1],
+ tr[0][2], tr[1][2], tr[2][2], tr[3][2],
+ tr[0][3], tr[1][3], tr[2][3], tr[3][3]
+ ); /* clang-format on */
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
new file mode 100644
index 0000000..dbf77b0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/Output.h>
+#include <ui/DebugUtils.h>
+
+namespace android::compositionengine::impl {
+
+Output::Output(const CompositionEngine& compositionEngine)
+ : mCompositionEngine(compositionEngine) {}
+
+Output::~Output() = default;
+
+const CompositionEngine& Output::getCompositionEngine() const {
+ return mCompositionEngine;
+}
+
+bool Output::isValid() const {
+ return mDisplayColorProfile && mDisplayColorProfile->isValid() && mRenderSurface &&
+ mRenderSurface->isValid();
+}
+
+const std::string& Output::getName() const {
+ return mName;
+}
+
+void Output::setName(const std::string& name) {
+ mName = name;
+}
+
+void Output::setCompositionEnabled(bool enabled) {
+ if (mState.isEnabled == enabled) {
+ return;
+ }
+
+ mState.isEnabled = enabled;
+ dirtyEntireOutput();
+}
+
+void Output::setProjection(const ui::Transform& transform, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) {
+ mState.transform = transform;
+ mState.orientation = orientation;
+ mState.scissor = scissor;
+ mState.frame = frame;
+ mState.viewport = viewport;
+ mState.needsFiltering = needsFiltering;
+
+ dirtyEntireOutput();
+}
+
+// TODO(lpique): Rename setSize() once more is moved.
+void Output::setBounds(const ui::Size& size) {
+ mRenderSurface->setDisplaySize(size);
+ // TODO(lpique): Rename mState.size once more is moved.
+ mState.bounds = Rect(mRenderSurface->getSize());
+
+ dirtyEntireOutput();
+}
+
+void Output::setLayerStackFilter(bool singleLayerStack, uint32_t singleLayerStackId) {
+ mState.singleLayerStack = singleLayerStack;
+ mState.singleLayerStackId = singleLayerStackId;
+
+ dirtyEntireOutput();
+}
+
+void Output::setColorTransform(const mat4& transform) {
+ const bool isIdentity = (transform == mat4());
+
+ mState.colorTransform =
+ isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+}
+
+void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
+ ui::RenderIntent renderIntent) {
+ mState.colorMode = mode;
+ mState.dataspace = dataspace;
+ mState.renderIntent = renderIntent;
+
+ mRenderSurface->setBufferDataspace(dataspace);
+
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
+ decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
+ renderIntent);
+}
+
+void Output::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ StringAppendF(&out, " Composition Output State: [\"%s\"]", mName.c_str());
+
+ out.append("\n ");
+
+ dumpBase(out);
+}
+
+void Output::dumpBase(std::string& out) const {
+ mState.dump(out);
+
+ if (mDisplayColorProfile) {
+ mDisplayColorProfile->dump(out);
+ } else {
+ out.append(" No display color profile!\n");
+ }
+
+ if (mRenderSurface) {
+ mRenderSurface->dump(out);
+ } else {
+ out.append(" No render surface!\n");
+ }
+}
+
+compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const {
+ return mDisplayColorProfile.get();
+}
+
+void Output::setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
+ mDisplayColorProfile = std::move(mode);
+}
+
+void Output::setDisplayColorProfileForTest(
+ std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
+ mDisplayColorProfile = std::move(mode);
+}
+
+compositionengine::RenderSurface* Output::getRenderSurface() const {
+ return mRenderSurface.get();
+}
+
+void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
+ mRenderSurface = std::move(surface);
+ mState.bounds = Rect(mRenderSurface->getSize());
+
+ dirtyEntireOutput();
+}
+
+void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
+ mRenderSurface = std::move(surface);
+}
+
+const OutputCompositionState& Output::getState() const {
+ return mState;
+}
+
+OutputCompositionState& Output::editState() {
+ return mState;
+}
+
+Region Output::getPhysicalSpaceDirtyRegion(bool repaintEverything) const {
+ Region dirty;
+ if (repaintEverything) {
+ dirty.set(mState.bounds);
+ } else {
+ dirty = mState.transform.transform(mState.dirtyRegion);
+ dirty.andSelf(mState.bounds);
+ }
+ return dirty;
+}
+
+bool Output::belongsInOutput(uint32_t layerStackId) const {
+ return !mState.singleLayerStack || (layerStackId == mState.singleLayerStackId);
+}
+
+void Output::dirtyEntireOutput() {
+ mState.dirtyRegion.set(mState.bounds);
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
new file mode 100644
index 0000000..7d8765f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+
+namespace android::compositionengine::impl {
+
+void OutputCompositionState::dump(std::string& out) const {
+ dumpVal(out, "isEnabled", isEnabled);
+ dumpVal(out, "isSecure", isSecure);
+ if (singleLayerStack) {
+ out.append("layerStack=<any>");
+ } else {
+ dumpVal(out, "layerStack", singleLayerStackId);
+ }
+
+ out.append("\n ");
+
+ dumpVal(out, "transform", transform);
+
+ out.append("\n ");
+
+ dumpVal(out, "frame", frame);
+ dumpVal(out, "viewport", viewport);
+ dumpVal(out, "scissor", scissor);
+ dumpVal(out, "needsFiltering", needsFiltering);
+
+ out.append("\n");
+
+ dumpVal(out, "colorMode", toString(colorMode), colorMode);
+ dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
+ dumpVal(out, "dataspace", toString(dataspace), dataspace);
+ dumpVal(out, "colorTransform", colorTransform);
+
+ out.append("\n");
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
new file mode 100644
index 0000000..d546fc8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <android/native_window.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <log/log.h>
+#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <system/window.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+RenderSurface::~RenderSurface() = default;
+
+namespace impl {
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::Display& display, compositionengine::RenderSurfaceCreationArgs&& args) {
+ return std::make_unique<RenderSurface>(compositionEngine, display, std::move(args));
+}
+
+RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display,
+ RenderSurfaceCreationArgs&& args)
+ : mCompositionEngine(compositionEngine),
+ mDisplay(display),
+ mNativeWindow(args.nativeWindow),
+ mDisplaySurface(args.displaySurface),
+ mSize(args.displayWidth, args.displayHeight) {}
+
+RenderSurface::~RenderSurface() = default;
+
+bool RenderSurface::isValid() const {
+ return mSize.isValid();
+}
+
+void RenderSurface::initialize() {
+ ANativeWindow* const window = mNativeWindow.get();
+
+ int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
+ status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
+ status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
+}
+
+const ui::Size& RenderSurface::getSize() const {
+ return mSize;
+}
+
+const sp<Fence>& RenderSurface::getClientTargetAcquireFence() const {
+ return mDisplaySurface->getClientTargetAcquireFence();
+}
+
+void RenderSurface::setDisplaySize(const ui::Size& size) {
+ mDisplaySurface->resizeBuffers(size.width, size.height);
+ mSize = size;
+}
+
+void RenderSurface::setBufferDataspace(ui::Dataspace dataspace) {
+ native_window_set_buffers_data_space(mNativeWindow.get(),
+ static_cast<android_dataspace>(dataspace));
+}
+
+void RenderSurface::setProtected(bool useProtected) {
+ uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
+ if (useProtected) {
+ usageFlags |= GRALLOC_USAGE_PROTECTED;
+ }
+ const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
+}
+
+status_t RenderSurface::beginFrame(bool mustRecompose) {
+ return mDisplaySurface->beginFrame(mustRecompose);
+}
+
+status_t RenderSurface::prepareFrame(std::vector<CompositionInfo>& compositionData) {
+ auto& hwc = mCompositionEngine.getHwComposer();
+ const auto id = mDisplay.getId();
+ if (id) {
+ status_t error = hwc.prepare(*id, compositionData);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ }
+
+ DisplaySurface::CompositionType compositionType;
+ const bool hasClient = hwc.hasClientComposition(id);
+ const bool hasDevice = hwc.hasDeviceComposition(id);
+ if (hasClient && hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_MIXED;
+ } else if (hasClient) {
+ compositionType = DisplaySurface::COMPOSITION_GLES;
+ } else if (hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ } else {
+ // Nothing to do -- when turning the screen off we get a frame like
+ // this. Call it a HWC frame since we won't be doing any GLES work but
+ // will do a prepare/set cycle.
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ }
+ return mDisplaySurface->prepareFrame(compositionType);
+}
+
+sp<GraphicBuffer> RenderSurface::dequeueBuffer() {
+ int fd = -1;
+ ANativeWindowBuffer* buffer = nullptr;
+
+ status_t result = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
+
+ if (result != NO_ERROR) {
+ ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
+ mDisplay.getName().c_str(), result);
+ // 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 RenderSurface::queueBuffer() {
+ auto& hwc = mCompositionEngine.getHwComposer();
+ const auto id = mDisplay.getId();
+
+ if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+ // 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",
+ mDisplay.getName().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]", mDisplay.getName().c_str());
+ } else {
+ status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
+ if (result != NO_ERROR) {
+ ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
+ result);
+ // We risk blocking on dequeueBuffer if the primary display failed
+ // to queue up its buffer, so crash here.
+ if (!mDisplay.isVirtual()) {
+ LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
+ } else {
+ mNativeWindow->cancelBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
+ }
+ }
+
+ mBufferReady.reset();
+ mGraphicBuffer = nullptr;
+ }
+ }
+
+ status_t result = mDisplaySurface->advanceFrame();
+ if (result != NO_ERROR) {
+ ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplay.getName().c_str(), result);
+ }
+}
+
+void RenderSurface::onPresentDisplayCompleted() {
+ mDisplaySurface->onFrameCommitted();
+}
+
+void RenderSurface::setViewportAndProjection() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ Rect sourceCrop = Rect(mSize);
+ renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop,
+ ui::Transform::ROT_0);
+}
+
+void RenderSurface::finishBuffer() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ mBufferReady = renderEngine.flush();
+ if (mBufferReady.get() < 0) {
+ renderEngine.finish();
+ }
+}
+
+void RenderSurface::flip() {
+ mPageFlipCount++;
+}
+
+void RenderSurface::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ out.append(" Composition RenderSurface State:");
+
+ out.append("\n ");
+
+ dumpVal(out, "size", mSize);
+ StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(),
+ ANativeWindow_getFormat(mNativeWindow.get()));
+ dumpVal(out, "flips", mPageFlipCount);
+ out.append("\n");
+
+ String8 surfaceDump;
+ mDisplaySurface->dumpAsString(surfaceDump);
+ out.append(surfaceDump);
+}
+
+std::uint32_t RenderSurface::getPageFlipCount() const {
+ return mPageFlipCount;
+}
+
+void RenderSurface::setPageFlipCountForTest(std::uint32_t count) {
+ mPageFlipCount = count;
+}
+
+void RenderSurface::setSizeForTest(const ui::Size& size) {
+ mSize = size;
+}
+
+sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() {
+ return mGraphicBuffer;
+}
+
+base::unique_fd& RenderSurface::mutableBufferReadyForTest() {
+ return mBufferReady;
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
new file mode 100644
index 0000000..d20fdda
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -0,0 +1,644 @@
+/*
+ * Copyright 2019 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 <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <gtest/gtest.h>
+
+namespace android::hardware::graphics::common::V1_1 {
+
+// Note: These operator overloads need to be defined in the same namespace as
+// the values they print.
+
+std::ostream& operator<<(std::ostream& os, const RenderIntent& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+} // namespace android::hardware::graphics::common::V1_1
+
+namespace android::hardware::graphics::common::V1_2 {
+
+// Note: These operator overloads need to be defined in the same namespace as
+// the values they print.
+
+std::ostream& operator<<(std::ostream& os, const Dataspace& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, const ColorMode& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+} // namespace android::hardware::graphics::common::V1_2
+
+namespace android::compositionengine {
+namespace {
+
+using testing::_;
+using testing::Contains;
+using testing::IsEmpty;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SizeIs;
+using testing::StrictMock;
+
+using ui::ColorMode;
+using ui::Dataspace;
+using ui::Hdr;
+using ui::RenderIntent;
+
+// This allows us to simulate a vendor-specified intent being used.
+constexpr RenderIntent VendorRenderIntent = static_cast<RenderIntent>(0x100);
+
+class DisplayColorProfileTest : public testing::Test {
+public:
+ ~DisplayColorProfileTest() override = default;
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+};
+
+class ProfileFactory {
+public:
+ impl::DisplayColorProfile build() const {
+ return impl::DisplayColorProfile{DisplayColorProfileCreationArgs{
+ mHasWideColorGamut,
+ HdrCapabilities(mSupportedHdrTypes, mMaxLuminance, mMaxAverageLuminance,
+ mMinLuminance),
+ mSupportedPerFrameMetadata,
+ mSupportedColorModes,
+ }};
+ }
+
+ ProfileFactory& setHasWideColorGamut(bool value) {
+ mHasWideColorGamut = value;
+ return *this;
+ }
+
+ ProfileFactory& setPerFrameMetadata(int32_t value) {
+ mSupportedPerFrameMetadata = value;
+ return *this;
+ }
+
+ ProfileFactory& addHdrType(Hdr value) {
+ mSupportedHdrTypes.emplace_back(value);
+ return *this;
+ }
+
+ ProfileFactory& addHdrTypes(std::initializer_list<Hdr> values) {
+ for (auto value : values) {
+ mSupportedHdrTypes.emplace_back(value);
+ }
+ return *this;
+ }
+
+ ProfileFactory& setMaxLuminance(float value) {
+ mMaxLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& setMaxAverageLuminance(float value) {
+ mMaxAverageLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& setMinLuminance(float value) {
+ mMinLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& addColorModeRenderIntent(ColorMode colorMode, RenderIntent renderIntent) {
+ mSupportedColorModes[colorMode].emplace_back(renderIntent);
+ return *this;
+ }
+
+ ProfileFactory& addColorModeRenderIntents(ColorMode colorMode,
+ std::initializer_list<RenderIntent> renderIntents) {
+ auto& profileedRenderIntents = mSupportedColorModes[colorMode];
+ for (auto renderIntent : renderIntents) {
+ profileedRenderIntents.emplace_back(renderIntent);
+ }
+ return *this;
+ }
+
+ static impl::DisplayColorProfile createProfileWithNoColorModeSupport() {
+ return ProfileFactory().build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithBT2020ColorModeSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HDR10)
+ .addColorModeRenderIntent(ColorMode::DISPLAY_BT2020, VendorRenderIntent)
+ .build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithSRGBColorModeSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HDR10)
+ .addColorModeRenderIntent(ColorMode::SRGB, VendorRenderIntent)
+ .build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithBT2100PQSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HLG)
+ .addColorModeRenderIntent(ColorMode::BT2100_PQ, VendorRenderIntent)
+ .build();
+ }
+
+private:
+ bool mHasWideColorGamut = false;
+ std::vector<Hdr> mSupportedHdrTypes;
+ float mMaxLuminance = -1.f;
+ float mMaxAverageLuminance = -1.f;
+ float mMinLuminance = -1.f;
+ int32_t mSupportedPerFrameMetadata = 0;
+ std::unordered_map<ColorMode, std::vector<RenderIntent>> mSupportedColorModes;
+};
+
+/* ------------------------------------------------------------------------
+ * RenderSurface Construction
+ */
+
+TEST_F(DisplayColorProfileTest, ctorSetsHasWideColorGamutFromInputArgs) {
+ {
+ auto profile = ProfileFactory().setHasWideColorGamut(false).build();
+
+ EXPECT_FALSE(profile.hasWideColorGamut());
+ }
+
+ {
+ auto profile = ProfileFactory().setHasWideColorGamut(true).build();
+
+ EXPECT_TRUE(profile.hasWideColorGamut());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorSetsSupportedPerFrameMetadataFromInputArgs) {
+ {
+ auto profile = ProfileFactory().setPerFrameMetadata(0).build();
+
+ EXPECT_EQ(0, profile.getSupportedPerFrameMetadata());
+ }
+
+ {
+ impl::DisplayColorProfile profile = ProfileFactory().setPerFrameMetadata(123).build();
+
+ EXPECT_EQ(123, profile.getSupportedPerFrameMetadata());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorDetectsSupportedHdrTypesFromInputArgs) {
+ {
+ // The constructor will set the internal state to not indicate any
+ // profile for HDR modes if none are profileed.
+ auto profile = ProfileFactory().build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HDR10Plus
+ // profile if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HDR10_PLUS).build();
+
+ EXPECT_TRUE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HDR10 profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HDR10).build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_TRUE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HLG profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HLG).build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_TRUE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate Dolbyvision profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::DOLBY_VISION).build();
+
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_TRUE(profile.hasDolbyVisionSupport());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorUsesOrDefaultsLuminanceValuesFromInputArgs) {
+ {
+ // The constructor will use a default value for each luminance setting
+ // that is negative.
+ auto profile = ProfileFactory()
+ .setMaxLuminance(-1.f)
+ .setMaxAverageLuminance(-1.f)
+ .setMinLuminance(-1.f)
+ .build();
+
+ EXPECT_EQ(DisplayColorProfile::sDefaultMaxLumiance,
+ profile.getHdrCapabilities().getDesiredMaxLuminance());
+ EXPECT_EQ(DisplayColorProfile::sDefaultMaxLumiance,
+ profile.getHdrCapabilities().getDesiredMaxAverageLuminance());
+ EXPECT_EQ(DisplayColorProfile::sDefaultMinLumiance,
+ profile.getHdrCapabilities().getDesiredMinLuminance());
+ }
+
+ {
+ // The constructor will otherwise take and use a positive value for each
+ // of the luminance settings.
+ auto profile = ProfileFactory()
+ .setMaxLuminance(1001.f)
+ .setMaxAverageLuminance(1002.f)
+ .setMinLuminance(1003.f)
+ .build();
+
+ EXPECT_EQ(1001.f, profile.getHdrCapabilities().getDesiredMaxLuminance());
+ EXPECT_EQ(1002.f, profile.getHdrCapabilities().getDesiredMaxAverageLuminance());
+ EXPECT_EQ(1003.f, profile.getHdrCapabilities().getDesiredMinLuminance());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorSignalsHdrSupportForAnyWideColorGamutDevice) {
+ {
+ // If the output does not profile wide color gamut, then no HDR modes
+ // will be profileed in the generated HDR capabilities.
+ auto profile = ProfileFactory().setHasWideColorGamut(false).build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), IsEmpty());
+ }
+
+ {
+ // If the HWC does not show profile for certain HDR modes, then the
+ // generated HDR capabilities will indicate profile anyway.
+ auto profile = ProfileFactory().setHasWideColorGamut(true).build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG));
+ }
+
+ {
+ // If the HWC profiles the HDR modes, then the generated capabilities
+ // still has one entry for each HDR type.
+ auto profile = ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrTypes({Hdr::HLG, Hdr::HDR10})
+ .build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG));
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * DisplayColorProfile::hasRenderIntent
+ */
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasNoSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasBT2020upport) {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasSRGBSupport) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_TRUE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasBTG2100PQSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+/* ------------------------------------------------------------------------
+ * DisplayColorProfile::hasLegacyHdrSupport
+ */
+
+TEST_F(DisplayColorProfileTest, hasLegacyHdrSupport) {
+ {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getBestColorMode()
+ */
+
+void checkGetBestColorMode(
+ DisplayColorProfile& profile,
+ const std::array<std::tuple<Dataspace, ColorMode, RenderIntent>, 25>& expected) {
+ using ArgsType = std::tuple<Dataspace, RenderIntent>;
+
+ // These are the combinations of dataspaces and render intents that could be
+ // passed to RenderSurface::getBestColorMode()
+ const std::array<std::tuple<Dataspace, RenderIntent>, 25> kArgs = {
+ /* clang-format off */
+
+ // Non-HDR combinations
+
+ /* 0 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 1 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::ENHANCE},
+ /* 2 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 3 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 4 */ ArgsType{Dataspace::DISPLAY_BT2020, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 5 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+ /* 6 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::ENHANCE},
+ /* 7 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 8 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 9 */ ArgsType{Dataspace::DISPLAY_P3, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 10 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::COLORIMETRIC},
+ /* 11 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::ENHANCE},
+ /* 12 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 13 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 14 */ ArgsType{Dataspace::V0_SRGB, VendorRenderIntent}, // Vendor explicit setting
+
+ // HDR combinations
+
+ /* 15 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_COLORIMETRIC},
+ /* 16 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_ENHANCE},
+ /* 17 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::COLORIMETRIC}, // Vendor explicit setting
+ /* 18 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::ENHANCE}, // Vendor explicit setting
+ /* 19 */ ArgsType{Dataspace::BT2020_PQ, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 20 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_COLORIMETRIC},
+ /* 21 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_ENHANCE},
+ /* 22 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::COLORIMETRIC}, // Vendor explicit setting
+ /* 23 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::ENHANCE}, // Vendor explicit setting
+ /* 24 */ ArgsType{Dataspace::BT2020_HLG, VendorRenderIntent}, // Vendor explicit setting
+ /* clang-format on */
+ };
+
+ for (size_t i = 0; i < kArgs.size(); i++) {
+ std::tuple<Dataspace, ColorMode, RenderIntent> actual;
+ profile.getBestColorMode(std::get<0>(kArgs[i]), std::get<1>(kArgs[i]), &std::get<0>(actual),
+ &std::get<1>(actual), &std::get<2>(actual));
+
+ EXPECT_EQ(expected[i], actual) << " for index " << i;
+ }
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasNoSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 10 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasBT2020Support) {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 10 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasSRGBSupport) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 5 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 10 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 15 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasBT2100PQSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
new file mode 100644
index 0000000..8cb6936
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2019 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 <cmath>
+
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/RenderSurface.h>
+#include <gtest/gtest.h>
+#include <system/window.h>
+
+#include "MockHWComposer.h"
+
+namespace android::compositionengine {
+namespace {
+
+using testing::Return;
+using testing::ReturnRef;
+using testing::StrictMock;
+
+constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
+
+class DisplayTest : public testing::Test {
+public:
+ ~DisplayTest() override = default;
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ impl::Display mDisplay{mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(DisplayTest, canInstantiateDisplay) {
+ {
+ constexpr DisplayId display1 = DisplayId{123u};
+ auto display =
+ impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(display1).build());
+ EXPECT_FALSE(display->isSecure());
+ EXPECT_FALSE(display->isVirtual());
+ EXPECT_EQ(display1, display->getId());
+ }
+
+ {
+ constexpr DisplayId display2 = DisplayId{546u};
+ auto display = impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder()
+ .setIsSecure(true)
+ .setDisplayId(display2)
+ .build());
+ EXPECT_TRUE(display->isSecure());
+ EXPECT_FALSE(display->isVirtual());
+ EXPECT_EQ(display2, display->getId());
+ }
+
+ {
+ constexpr DisplayId display3 = DisplayId{789u};
+ auto display = impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder()
+ .setIsVirtual(true)
+ .setDisplayId(display3)
+ .build());
+ EXPECT_FALSE(display->isSecure());
+ EXPECT_TRUE(display->isVirtual());
+ EXPECT_EQ(display3, display->getId());
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * Display::disconnect()
+ */
+
+TEST_F(DisplayTest, disconnectDisconnectsDisplay) {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ // The first call to disconnect will disconnect the display with the HWC and
+ // set mHwcId to -1.
+ EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1);
+ mDisplay.disconnect();
+ EXPECT_FALSE(mDisplay.getId());
+
+ // Subsequent calls will do nothing,
+ EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(0);
+ mDisplay.disconnect();
+ EXPECT_FALSE(mDisplay.getId());
+}
+
+/* ------------------------------------------------------------------------
+ * Display::setColorTransform()
+ */
+
+TEST_F(DisplayTest, setColorTransformSetsTransform) {
+ // Identity matrix sets an identity state value
+ const mat4 identity;
+
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
+
+ mDisplay.setColorTransform(identity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mDisplay.getState().colorTransform);
+
+ // Non-identity matrix sets a non-identity state value
+ const mat4 nonIdentity = mat4() * 2;
+
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, nonIdentity)).Times(1);
+
+ mDisplay.setColorTransform(nonIdentity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::setColorMode()
+ */
+
+TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ // These values are expected to be the initial state.
+ ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
+ ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+
+ // Otherwise if the values are unchanged, nothing happens
+ mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
+ ui::RenderIntent::COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+
+ // Otherwise if the values are different, updates happen
+ EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(mHwComposer,
+ setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::BT2100_PQ,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC))
+ .Times(1);
+
+ mDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::BT2100_PQ, mDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::SRGB, mDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
+}
+
+TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) {
+ impl::Display virtualDisplay{mCompositionEngine,
+ DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
+
+ virtualDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::createDisplayColorProfile()
+ */
+
+TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) {
+ EXPECT_TRUE(mDisplay.getDisplayColorProfile() == nullptr);
+ mDisplay.createDisplayColorProfile(
+ DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0,
+ DisplayColorProfileCreationArgs::HwcColorModes()});
+ EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::createRenderSurface()
+ */
+
+TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) {
+ EXPECT_TRUE(mDisplay.getRenderSurface() == nullptr);
+ mDisplay.createRenderSurface(RenderSurfaceCreationArgs{640, 480, nullptr, nullptr});
+ EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
new file mode 100644
index 0000000..f060cff
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2019 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 <cmath>
+
+#include <compositionengine/impl/Output.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
+#include <compositionengine/mock/RenderSurface.h>
+#include <gtest/gtest.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include "RegionMatcher.h"
+#include "TransformMatcher.h"
+
+namespace android::compositionengine {
+namespace {
+
+using testing::Return;
+using testing::ReturnRef;
+using testing::StrictMock;
+
+class OutputTest : public testing::Test {
+public:
+ OutputTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+ ~OutputTest() override = default;
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ impl::Output mOutput{mCompositionEngine};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(OutputTest, canInstantiateOutput) {
+ // The validation check checks each required component.
+ EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderSurface, isValid()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mOutput.isValid());
+
+ // If we take away the required components, it is no longer valid.
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>());
+
+ EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
+
+ EXPECT_FALSE(mOutput.isValid());
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setCompositionEnabled()
+ */
+
+TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = true;
+
+ mOutput.setCompositionEnabled(true);
+
+ EXPECT_TRUE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+}
+
+TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = false;
+
+ mOutput.setCompositionEnabled(true);
+
+ EXPECT_TRUE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = true;
+
+ mOutput.setCompositionEnabled(false);
+
+ EXPECT_FALSE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setProjection()
+ */
+
+TEST_F(OutputTest, setProjectionTriviallyWorks) {
+ const ui::Transform transform{ui::Transform::ROT_180};
+ const int32_t orientation = 123;
+ const Rect frame{1, 2, 3, 4};
+ const Rect viewport{5, 6, 7, 8};
+ const Rect scissor{9, 10, 11, 12};
+ const bool needsFiltering = true;
+
+ mOutput.setProjection(transform, orientation, frame, viewport, scissor, needsFiltering);
+
+ EXPECT_THAT(mOutput.getState().transform, TransformEq(transform));
+ EXPECT_EQ(orientation, mOutput.getState().orientation);
+ EXPECT_EQ(frame, mOutput.getState().frame);
+ EXPECT_EQ(viewport, mOutput.getState().viewport);
+ EXPECT_EQ(scissor, mOutput.getState().scissor);
+ EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setBounds()
+ */
+
+TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
+ const ui::Size displaySize{100, 200};
+
+ EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
+ EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
+
+ mOutput.setBounds(displaySize);
+
+ EXPECT_EQ(Rect(displaySize), mOutput.getState().bounds);
+
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setLayerStackFilter()
+ */
+
+TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+
+ const uint32_t layerStack = 123u;
+ mOutput.setLayerStackFilter(true, layerStack);
+
+ EXPECT_TRUE(mOutput.getState().singleLayerStack);
+ EXPECT_EQ(layerStack, mOutput.getState().singleLayerStackId);
+
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setColorTransform
+ */
+
+TEST_F(OutputTest, setColorTransformSetsTransform) {
+ // Identity matrix sets an identity state value
+ const mat4 identity;
+
+ mOutput.setColorTransform(identity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
+
+ // Non-identity matrix sets a non-identity state value
+ const mat4 nonIdentity = mat4() * 2;
+
+ mOutput.setColorTransform(nonIdentity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setColorMode
+ */
+
+TEST_F(OutputTest, setColorModeSetsModeUnlessNoChange) {
+ EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+
+ mOutput.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::BT2100_PQ, mOutput.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::SRGB, mOutput.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setRenderSurface()
+ */
+
+TEST_F(OutputTest, setRenderSurfaceResetsBounds) {
+ const ui::Size newDisplaySize{640, 480};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ EXPECT_CALL(*renderSurface, getSize()).WillOnce(ReturnRef(newDisplaySize));
+
+ mOutput.setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
+
+ EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::getPhysicalSpaceDirtyRegion()
+ */
+
+TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingTrue) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().dirtyRegion.set(50, 300);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
+
+ EXPECT_THAT(result, RegionEq(Region(displaySize)));
+ }
+
+ // For repaint everything == true, the returned value does not depend on the display
+ // rotation.
+ mOutput.editState().transform.set(ui::Transform::ROT_90, 0, 0);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
+
+ EXPECT_THAT(result, RegionEq(Region(displaySize)));
+ }
+}
+
+TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingFalse) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().dirtyRegion.set(50, 300);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
+
+ // The dirtyRegion should be clipped to the display bounds.
+ EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
+ }
+
+ mOutput.editState().transform.set(ui::Transform::ROT_90, displaySize.getWidth(),
+ displaySize.getHeight());
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
+
+ // The dirtyRegion should be rotated and clipped to the display bounds.
+ EXPECT_THAT(result, RegionEq(Region(Rect(100, 50))));
+ }
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h b/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
new file mode 100644
index 0000000..5a4efa9
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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 <gmock/gmock.h>
+
+namespace {
+
+// Checks for a region match
+MATCHER_P(RegionEq, expected, "") {
+ std::string buf;
+ buf.append("Regions are not equal\n");
+ expected.dump(buf, "expected region");
+ arg.dump(buf, "actual region");
+ *result_listener << buf;
+
+ size_t expectedRectCount = 0;
+ android::Rect const* expectedRects = expected.getArray(&expectedRectCount);
+ size_t actualRectCount = 0;
+ android::Rect const* actualRects = arg.getArray(&actualRectCount);
+
+ if (expectedRectCount != actualRectCount) return false;
+ for (size_t i = 0; i < expectedRectCount; i++) {
+ if (expectedRects[i] != actualRects[i]) return false;
+ }
+ return true;
+}
+
+} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
new file mode 100644
index 0000000..13cc663
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2019 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 <cstdarg>
+#include <cstdint>
+
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <system/window.h>
+#include <ui/ANativeObjectBase.h>
+
+#include "MockHWComposer.h"
+
+namespace android::compositionengine {
+namespace {
+
+/* ------------------------------------------------------------------------
+ * MockNativeWindow
+ *
+ * An intentionally simplified Mock which implements a minimal subset of the full
+ * ANativeWindow interface.
+ */
+
+class MockNativeWindow : public ANativeObjectBase<ANativeWindow, MockNativeWindow, RefBase> {
+public:
+ MockNativeWindow() {
+ ANativeWindow::setSwapInterval = &forwardSetSwapInterval;
+ ANativeWindow::dequeueBuffer = &forwardDequeueBuffer;
+ ANativeWindow::cancelBuffer = &forwardCancelBuffer;
+ ANativeWindow::queueBuffer = &forwardQueueBuffer;
+ ANativeWindow::query = &forwardQuery;
+ ANativeWindow::perform = &forwardPerform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = &forwardDequeueBufferDeprecated;
+ ANativeWindow::cancelBuffer_DEPRECATED = &forwardCancelBufferDeprecated;
+ ANativeWindow::lockBuffer_DEPRECATED = &forwardLockBufferDeprecated;
+ ANativeWindow::queueBuffer_DEPRECATED = &forwardQueueBufferDeprecated;
+ }
+
+ MOCK_METHOD1(setSwapInterval, int(int));
+ MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
+ MOCK_METHOD2(cancelBuffer, int(struct ANativeWindowBuffer*, int));
+ MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
+ MOCK_CONST_METHOD2(query, int(int, int*));
+ MOCK_METHOD1(connect, int(int));
+ MOCK_METHOD1(lockBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+ MOCK_METHOD1(setBuffersFormat, int(PixelFormat));
+ MOCK_METHOD1(setBuffersDataSpace, int(ui::Dataspace));
+ MOCK_METHOD1(setUsage, int(uint64_t));
+
+ static void unexpectedCall(...) { LOG_ALWAYS_FATAL("Unexpected ANativeWindow API call"); }
+
+ static int forwardSetSwapInterval(ANativeWindow* window, int interval) {
+ return getSelf(window)->setSwapInterval(interval);
+ }
+
+ static int forwardDequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd) {
+ return getSelf(window)->dequeueBuffer(buffer, fenceFd);
+ }
+
+ static int forwardCancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd) {
+ return getSelf(window)->cancelBuffer(buffer, fenceFd);
+ }
+
+ static int forwardQueueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ return getSelf(window)->queueBuffer(buffer, fenceFd);
+ }
+
+ static int forwardQuery(const ANativeWindow* window, int what, int* value) {
+ return getSelf(window)->query(what, value);
+ }
+
+ static int forwardPerform(ANativeWindow* window, int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ int result = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_API_CONNECT: {
+ int api = va_arg(args, int);
+ result = getSelf(window)->connect(api);
+ break;
+ }
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT: {
+ PixelFormat format = va_arg(args, PixelFormat);
+ result = getSelf(window)->setBuffersFormat(format);
+ break;
+ }
+ case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: {
+ ui::Dataspace dataspace = static_cast<ui::Dataspace>(va_arg(args, int));
+ result = getSelf(window)->setBuffersDataSpace(dataspace);
+ break;
+ }
+ case NATIVE_WINDOW_SET_USAGE: {
+ // Note: Intentionally widens usage from 32 to 64 bits so we
+ // just have one implementation.
+ uint64_t usage = va_arg(args, uint32_t);
+ result = getSelf(window)->setUsage(usage);
+ break;
+ }
+ case NATIVE_WINDOW_SET_USAGE64: {
+ uint64_t usage = va_arg(args, uint64_t);
+ result = getSelf(window)->setUsage(usage);
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("Unexpected operation %d", operation);
+ break;
+ }
+
+ va_end(args);
+ return result;
+ }
+
+ static int forwardDequeueBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer** buffer) {
+ int ignoredFenceFd = -1;
+ return getSelf(window)->dequeueBuffer(buffer, &ignoredFenceFd);
+ }
+
+ static int forwardCancelBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->cancelBuffer(buffer, -1);
+ }
+
+ static int forwardLockBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->lockBuffer_DEPRECATED(buffer);
+ }
+
+ static int forwardQueueBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->queueBuffer(buffer, -1);
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * RenderSurfaceTest
+ */
+
+constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
+constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
+const std::string DEFAULT_DISPLAY_NAME = "Mock Display";
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+using testing::StrictMock;
+
+class RenderSurfaceTest : public testing::Test {
+public:
+ RenderSurfaceTest() {
+ EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
+ EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
+ EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
+ }
+ ~RenderSurfaceTest() override = default;
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<mock::Display> mDisplay;
+ sp<MockNativeWindow> mNativeWindow = new StrictMock<MockNativeWindow>();
+ sp<mock::DisplaySurface> mDisplaySurface = new StrictMock<mock::DisplaySurface>();
+ impl::RenderSurface mSurface{mCompositionEngine, mDisplay,
+ RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT, mNativeWindow,
+ mDisplaySurface}};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(RenderSurfaceTest, canInstantiate) {
+ EXPECT_TRUE(mSurface.isValid());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::initialize()
+ */
+
+TEST_F(RenderSurfaceTest, initializeConfiguresNativeWindow) {
+ EXPECT_CALL(*mNativeWindow, connect(NATIVE_WINDOW_API_EGL)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setBuffersFormat(HAL_PIXEL_FORMAT_RGBA_8888))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+ mSurface.initialize();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getSize()
+ */
+
+TEST_F(RenderSurfaceTest, sizeReturnsConstructedSize) {
+ const ui::Size expected{DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT};
+
+ EXPECT_EQ(expected, mSurface.getSize());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getClientTargetAcquireFence()
+ */
+
+TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) {
+ sp<Fence> fence = new Fence();
+
+ EXPECT_CALL(*mDisplaySurface, getClientTargetAcquireFence()).WillOnce(ReturnRef(fence));
+
+ EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setDisplaySize()
+ */
+
+TEST_F(RenderSurfaceTest, setDisplaySizeAppliesChange) {
+ EXPECT_CALL(*mDisplaySurface, resizeBuffers(640, 480)).Times(1);
+
+ mSurface.setDisplaySize(ui::Size(640, 480));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setBufferDataspace()
+ */
+
+TEST_F(RenderSurfaceTest, setBufferDataspaceAppliesChange) {
+ EXPECT_CALL(*mNativeWindow, setBuffersDataSpace(ui::Dataspace::DISPLAY_P3))
+ .WillOnce(Return(NO_ERROR));
+
+ mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setProtected()
+ */
+
+TEST_F(RenderSurfaceTest, setProtectedTrueEnablesProtection) {
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+ .WillOnce(Return(NO_ERROR));
+
+ mSurface.setProtected(true);
+}
+
+TEST_F(RenderSurfaceTest, setProtectedFalseDisablesProtection) {
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+ mSurface.setProtected(false);
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::beginFrame()
+ */
+
+TEST_F(RenderSurfaceTest, beginFrameAppliesChange) {
+ EXPECT_CALL(*mDisplaySurface, beginFrame(true)).WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::prepareFrame()
+ */
+
+TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data)))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
+ std::vector<CompositionInfo> data;
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::dequeueBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+ EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
+
+ EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer().get());
+
+ EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::queueBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
+ .WillOnce(Return(false));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(INVALID_OPERATION));
+ EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::onPresentDisplayCompleted()
+ */
+
+TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) {
+ EXPECT_CALL(*mDisplaySurface, onFrameCommitted()).Times(1);
+
+ mSurface.onPresentDisplayCompleted();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::finishBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, finishBufferJustFlushesRenderEngine) {
+ int fd = dup(1);
+
+ EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(fd))));
+
+ mSurface.finishBuffer();
+
+ EXPECT_EQ(fd, mSurface.mutableBufferReadyForTest().release());
+}
+
+TEST_F(RenderSurfaceTest, finishBufferFlushesAndFinishesRenderEngine) {
+ EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(-2))));
+ EXPECT_CALL(mRenderEngine, finish()).Times(1);
+
+ mSurface.finishBuffer();
+
+ EXPECT_EQ(-2, mSurface.mutableBufferReadyForTest().release());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setViewportAndProjection()
+ */
+
+TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) {
+ mSurface.setSizeForTest(ui::Size(100, 200));
+
+ EXPECT_CALL(mRenderEngine,
+ setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0))
+ .Times(1);
+
+ mSurface.setViewportAndProjection();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::flip()
+ */
+
+TEST_F(RenderSurfaceTest, flipForwardsSignal) {
+ mSurface.setPageFlipCountForTest(500);
+
+ mSurface.flip();
+
+ EXPECT_EQ(501, mSurface.getPageFlipCount());
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h b/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h
new file mode 100644
index 0000000..ea07bed
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 <string>
+
+#include <gmock/gmock.h>
+
+namespace {
+
+// Check for a transform match
+MATCHER_P(TransformEq, expected, "") {
+ std::string buf;
+ buf.append("Transforms are not equal\n");
+ expected.dump(buf, "expected transform");
+ arg.dump(buf, "actual transform");
+ *result_listener << buf;
+
+ const float TOLERANCE = 1e-3f;
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (std::fabs(expected[i][j] - arg[i][j]) > TOLERANCE) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e7b7fbe..54111de 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -18,47 +18,28 @@
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
-#include "DisplayDevice.h"
-
-#include <array>
-#include <unordered_set>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
#include <android-base/stringprintf.h>
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/OutputCompositionState.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 <log/log.h>
#include <system/window.h>
-#include <ui/DebugUtils.h>
-#include <ui/DisplayInfo.h>
-#include <ui/PixelFormat.h>
-#include <utils/Log.h>
-#include <utils/RefBase.h>
+#include <ui/GraphicTypes.h>
-#include "DisplayHardware/DisplaySurface.h"
-#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWC2.h"
-#include "SurfaceFlinger.h"
+#include "DisplayDevice.h"
#include "Layer.h"
+#include "SurfaceFlinger.h"
namespace android {
-// retrieve triple buffer setting from configstore
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
using android::base::StringAppendF;
-using android::ui::ColorMode;
-using android::ui::Dataspace;
-using android::ui::Hdr;
-using android::ui::RenderIntent;
/*
* Initialize the display to the specified values.
@@ -67,413 +48,72 @@
uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0;
-namespace {
-
-// ordered list of known SDR color modes
-const std::array<ColorMode, 3> sSdrColorModes = {
- ColorMode::DISPLAY_BT2020,
- ColorMode::DISPLAY_P3,
- ColorMode::SRGB,
-};
-
-// ordered list of known HDR color modes
-const std::array<ColorMode, 2> sHdrColorModes = {
- ColorMode::BT2100_PQ,
- ColorMode::BT2100_HLG,
-};
-
-// ordered list of known SDR render intents
-const std::array<RenderIntent, 2> sSdrRenderIntents = {
- RenderIntent::ENHANCE,
- RenderIntent::COLORIMETRIC,
-};
-
-// ordered list of known HDR render intents
-const std::array<RenderIntent, 2> sHdrRenderIntents = {
- RenderIntent::TONE_MAP_ENHANCE,
- RenderIntent::TONE_MAP_COLORIMETRIC,
-};
-
-// map known color mode to dataspace
-Dataspace colorModeToDataspace(ColorMode mode) {
- switch (mode) {
- case ColorMode::SRGB:
- return Dataspace::V0_SRGB;
- case ColorMode::DISPLAY_P3:
- return Dataspace::DISPLAY_P3;
- case ColorMode::DISPLAY_BT2020:
- return Dataspace::DISPLAY_BT2020;
- case ColorMode::BT2100_HLG:
- return Dataspace::BT2020_HLG;
- case ColorMode::BT2100_PQ:
- return Dataspace::BT2020_PQ;
- default:
- return Dataspace::UNKNOWN;
- }
-}
-
-// Return a list of candidate color modes.
-std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
- std::vector<ColorMode> candidates;
-
- // add mode itself
- candidates.push_back(mode);
-
- // check if mode is HDR
- bool isHdr = false;
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode == mode) {
- isHdr = true;
- break;
- }
- }
-
- // add other HDR candidates when mode is HDR
- if (isHdr) {
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode != mode) {
- candidates.push_back(hdrMode);
- }
- }
- }
-
- // add other SDR candidates
- for (auto sdrMode : sSdrColorModes) {
- if (sdrMode != mode) {
- candidates.push_back(sdrMode);
- }
- }
-
- return candidates;
-}
-
-// Return a list of candidate render intents.
-std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
- std::vector<RenderIntent> candidates;
-
- // add intent itself
- candidates.push_back(intent);
-
- // check if intent is HDR
- bool isHdr = false;
- for (auto hdrIntent : sHdrRenderIntents) {
- if (hdrIntent == intent) {
- isHdr = true;
- break;
- }
- }
-
- if (isHdr) {
- // add other HDR candidates when intent is HDR
- for (auto hdrIntent : sHdrRenderIntents) {
- if (hdrIntent != intent) {
- candidates.push_back(hdrIntent);
- }
- }
- } else {
- // add other SDR candidates when intent is SDR
- for (auto sdrIntent : sSdrRenderIntents) {
- if (sdrIntent != intent) {
- candidates.push_back(sdrIntent);
- }
- }
- }
-
- return candidates;
-}
-
-// Return the best color mode supported by HWC.
-ColorMode getHwcColorMode(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
- ColorMode mode) {
- std::vector<ColorMode> candidates = getColorModeCandidates(mode);
- for (auto candidate : candidates) {
- auto iter = hwcColorModes.find(candidate);
- if (iter != hwcColorModes.end()) {
- return candidate;
- }
- }
-
- return ColorMode::NATIVE;
-}
-
-// Return the best render intent supported by HWC.
-RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
- std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
- for (auto candidate : candidates) {
- for (auto hwcIntent : hwcIntents) {
- if (candidate == hwcIntent) {
- return candidate;
- }
- }
- }
-
- return RenderIntent::COLORIMETRIC;
-}
-
-} // anonymous namespace
-
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
const std::optional<DisplayId>& displayId)
: flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
- : lastCompositionHadVisibleLayers(false),
- mFlinger(args.flinger),
+ : mFlinger(args.flinger),
mDisplayToken(args.displayToken),
mSequenceId(args.sequenceId),
- mId(args.displayId),
- mNativeWindow(args.nativeWindow),
- mGraphicBuffer(nullptr),
- mDisplaySurface(args.displaySurface),
mDisplayInstallOrientation(args.displayInstallOrientation),
- mPageFlipCount(0),
+ mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
+ compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
+ args.displayId})},
mIsVirtual(args.isVirtual),
- mIsSecure(args.isSecure),
- mLayerStack(NO_LAYER_STACK),
mOrientation(),
- mViewport(Rect::INVALID_RECT),
- mFrame(Rect::INVALID_RECT),
- mPowerMode(args.initialPowerMode),
mActiveConfig(0),
- mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
- mHasWideColorGamut(args.hasWideColorGamut),
- mHasHdr10Plus(false),
- mHasHdr10(false),
- mHasHLG(false),
- mHasDolbyVision(false),
- mSupportedPerFrameMetadata(args.supportedPerFrameMetadata),
mIsPrimary(args.isPrimary) {
- populateColorModes(args.hwcColorModes);
+ mCompositionDisplay->createRenderSurface(
+ compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth(
+ args.nativeWindow.get()),
+ ANativeWindow_getHeight(
+ args.nativeWindow.get()),
+ args.nativeWindow, args.displaySurface});
- ALOGE_IF(!mNativeWindow, "No native window was set for display");
- ALOGE_IF(!mDisplaySurface, "No display surface was set for display");
+ mCompositionDisplay->createDisplayColorProfile(
+ compositionengine::DisplayColorProfileCreationArgs{args.hasWideColorGamut,
+ std::move(args.hdrCapabilities),
+ args.supportedPerFrameMetadata,
+ args.hwcColorModes});
- std::vector<Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
- for (Hdr hdrType : types) {
- switch (hdrType) {
- case Hdr::HDR10_PLUS:
- mHasHdr10Plus = true;
- break;
- case Hdr::HDR10:
- mHasHdr10 = true;
- break;
- case Hdr::HLG:
- mHasHLG = true;
- break;
- case Hdr::DOLBY_VISION:
- mHasDolbyVision = true;
- break;
- default:
- ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
- }
+ if (!mCompositionDisplay->isValid()) {
+ ALOGE("Composition Display did not validate!");
}
- float minLuminance = args.hdrCapabilities.getDesiredMinLuminance();
- float maxLuminance = args.hdrCapabilities.getDesiredMaxLuminance();
- float maxAverageLuminance = args.hdrCapabilities.getDesiredMaxAverageLuminance();
+ mCompositionDisplay->getRenderSurface()->initialize();
- minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
- maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
- maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
- if (this->hasWideColorGamut()) {
- // insert HDR10/HLG as we will force client composition for HDR10/HLG
- // layers
- if (!hasHDR10Support()) {
- types.push_back(Hdr::HDR10);
- }
-
- if (!hasHLGSupport()) {
- types.push_back(Hdr::HLG);
- }
- }
- mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
-
- ANativeWindow* const window = mNativeWindow.get();
-
- int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
- status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
- status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
-
- mDisplayWidth = ANativeWindow_getWidth(window);
- mDisplayHeight = ANativeWindow_getHeight(window);
+ setPowerMode(args.initialPowerMode);
// initialize the display orientation transform.
- setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
+ setProjection(DisplayState::eOrientationDefault, Rect::INVALID_RECT, Rect::INVALID_RECT);
}
DisplayDevice::~DisplayDevice() = default;
-void DisplayDevice::disconnect(HWComposer& hwc) {
- if (mId) {
- hwc.disconnectDisplay(*mId);
- mId.reset();
- }
+void DisplayDevice::disconnect() {
+ mCompositionDisplay->disconnect();
}
int DisplayDevice::getWidth() const {
- return mDisplayWidth;
+ return mCompositionDisplay->getState().bounds.getWidth();
}
int DisplayDevice::getHeight() const {
- return mDisplayHeight;
+ return mCompositionDisplay->getState().bounds.getHeight();
}
void DisplayDevice::setDisplayName(const std::string& displayName) {
if (!displayName.empty()) {
// never override the name with an empty name
mDisplayName = displayName;
+ mCompositionDisplay->setName(displayName);
}
}
uint32_t DisplayDevice::getPageFlipCount() const {
- return mPageFlipCount;
-}
-
-void DisplayDevice::flip() const
-{
- mPageFlipCount++;
-}
-
-status_t DisplayDevice::beginFrame(bool mustRecompose) const {
- return mDisplaySurface->beginFrame(mustRecompose);
-}
-
-status_t DisplayDevice::prepareFrame(HWComposer& hwc,
- std::vector<CompositionInfo>& compositionData) {
- if (mId) {
- status_t error = hwc.prepare(*mId, compositionData);
- if (error != NO_ERROR) {
- return error;
- }
- }
-
- DisplaySurface::CompositionType compositionType;
- bool hasClient = hwc.hasClientComposition(mId);
- bool hasDevice = hwc.hasDeviceComposition(mId);
- if (hasClient && hasDevice) {
- compositionType = DisplaySurface::COMPOSITION_MIXED;
- } else if (hasClient) {
- compositionType = DisplaySurface::COMPOSITION_GLES;
- } else if (hasDevice) {
- compositionType = DisplaySurface::COMPOSITION_HWC;
- } else {
- // Nothing to do -- when turning the screen off we get a frame like
- // this. Call it a HWC frame since we won't be doing any GLES work but
- // will do a prepare/set cycle.
- compositionType = DisplaySurface::COMPOSITION_HWC;
- }
- return mDisplaySurface->prepareFrame(compositionType);
-}
-
-void DisplayDevice::setProtected(bool useProtected) {
- uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
- if (useProtected) {
- usageFlags |= GRALLOC_USAGE_PROTECTED;
- }
- const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
-}
-
-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)) {
- // 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 {
- status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
- dup(mBufferReady));
- 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(),
- dup(mBufferReady));
- }
- }
-
- mBufferReady.reset();
- mGraphicBuffer = nullptr;
- }
- }
-
- status_t result = mDisplaySurface->advanceFrame();
- if (result != NO_ERROR) {
- ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.c_str(), result);
- }
-}
-
-void DisplayDevice::onPresentDisplayCompleted() {
- mDisplaySurface->onFrameCommitted();
-}
-
-void DisplayDevice::setViewportAndProjection() const {
- size_t w = mDisplayWidth;
- size_t h = mDisplayHeight;
- Rect sourceCrop(0, 0, w, h);
- 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();
+ return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
}
// ----------------------------------------------------------------------------
@@ -494,21 +134,10 @@
return mLayersNeedingFences;
}
-Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
- Region dirty;
- if (repaintEverything) {
- dirty.set(getBounds());
- } else {
- const ui::Transform& planeTransform(mGlobalTransform);
- dirty = planeTransform.transform(this->dirtyRegion);
- dirty.andSelf(getBounds());
- }
- return dirty;
-}
-
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
+ getCompositionDisplay()->setCompositionEnabled(mPowerMode != HWC_POWER_MODE_OFF);
}
int DisplayDevice::getPowerMode() const {
@@ -529,88 +158,37 @@
}
// ----------------------------------------------------------------------------
-void DisplayDevice::setActiveColorMode(ColorMode mode) {
- mActiveColorMode = mode;
-}
-
-ColorMode DisplayDevice::getActiveColorMode() const {
- return mActiveColorMode;
-}
-
-RenderIntent DisplayDevice::getActiveRenderIntent() const {
- return mActiveRenderIntent;
-}
-
-void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) {
- mActiveRenderIntent = renderIntent;
-}
-
-void DisplayDevice::setColorTransform(const mat4& transform) {
- const bool isIdentity = (transform == mat4());
- mColorTransform =
- isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
-}
-
-android_color_transform_t DisplayDevice::getColorTransform() const {
- return mColorTransform;
-}
-
-void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
- mCompositionDataSpace = dataspace;
- ANativeWindow* const window = mNativeWindow.get();
- native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
-}
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
- return mCompositionDataSpace;
+ return mCompositionDisplay->getState().dataspace;
}
// ----------------------------------------------------------------------------
void DisplayDevice::setLayerStack(uint32_t stack) {
- mLayerStack = stack;
- dirtyRegion.set(bounds());
+ mCompositionDisplay->setLayerStackFilter(!isPrimary(), stack);
}
// ----------------------------------------------------------------------------
-uint32_t DisplayDevice::getOrientationTransform() const {
- uint32_t transform = 0;
- switch (mOrientation) {
- case DisplayState::eOrientationDefault:
- transform = ui::Transform::ROT_0;
- break;
- case DisplayState::eOrientation90:
- transform = ui::Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- transform = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- transform = ui::Transform::ROT_270;
- break;
- }
- return transform;
-}
-
-status_t DisplayDevice::orientationToTransfrom(
- int orientation, int w, int h, ui::Transform* tr)
-{
- uint32_t flags = 0;
+uint32_t DisplayDevice::displayStateOrientationToTransformOrientation(int orientation) {
switch (orientation) {
case DisplayState::eOrientationDefault:
- flags = ui::Transform::ROT_0;
- break;
+ return ui::Transform::ROT_0;
case DisplayState::eOrientation90:
- flags = ui::Transform::ROT_90;
- break;
+ return ui::Transform::ROT_90;
case DisplayState::eOrientation180:
- flags = ui::Transform::ROT_180;
- break;
+ return ui::Transform::ROT_180;
case DisplayState::eOrientation270:
- flags = ui::Transform::ROT_270;
- break;
+ return ui::Transform::ROT_270;
default:
+ return ui::Transform::ROT_INVALID;
+ }
+}
+
+status_t DisplayDevice::orientationToTransfrom(int orientation, int w, int h, ui::Transform* tr) {
+ uint32_t flags = displayStateOrientationToTransformOrientation(orientation);
+ if (flags == ui::Transform::ROT_INVALID) {
return BAD_VALUE;
}
tr->set(flags, w, h);
@@ -618,12 +196,7 @@
}
void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
- dirtyRegion.set(getBounds());
-
- mDisplaySurface->resizeBuffers(newWidth, newHeight);
-
- mDisplayWidth = newWidth;
- mDisplayHeight = newHeight;
+ mCompositionDisplay->setBounds(ui::Size(newWidth, newHeight));
}
void DisplayDevice::setProjection(int orientation,
@@ -631,8 +204,11 @@
Rect viewport(newViewport);
Rect frame(newFrame);
- const int w = mDisplayWidth;
- const int h = mDisplayHeight;
+ mOrientation = orientation;
+
+ const Rect& displayBounds = getCompositionDisplay()->getState().bounds;
+ const int w = displayBounds.width();
+ const int h = displayBounds.height();
ui::Transform R;
DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
@@ -656,8 +232,6 @@
}
}
- dirtyRegion.set(getBounds());
-
ui::Transform TL, TP, S;
float src_width = viewport.width();
float src_height = viewport.height();
@@ -676,7 +250,7 @@
TL.set(-src_x, -src_y);
TP.set(dst_x, dst_y);
- // need to take care of primary display rotation for mGlobalTransform
+ // need to take care of primary display rotation for globalTransform
// for case if the panel is not installed aligned with device orientation
if (isPrimary()) {
DisplayDevice::orientationToTransfrom(
@@ -687,38 +261,25 @@
// The viewport and frame are both in the logical orientation.
// Apply the logical translation, scale to physical size, apply the
// physical translation and finally rotate to the physical orientation.
- mGlobalTransform = R * TP * S * TL;
+ ui::Transform globalTransform = R * TP * S * TL;
- const uint8_t type = mGlobalTransform.getType();
- mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
- (type >= ui::Transform::SCALE));
+ const uint8_t type = globalTransform.getType();
+ const bool needsFiltering =
+ (!globalTransform.preserveRects() || (type >= ui::Transform::SCALE));
- mScissor = mGlobalTransform.transform(viewport);
- if (mScissor.isEmpty()) {
- mScissor = getBounds();
+ Rect scissor = globalTransform.transform(viewport);
+ if (scissor.isEmpty()) {
+ scissor = displayBounds;
}
- mOrientation = orientation;
if (isPrimary()) {
- uint32_t transform = 0;
- switch (mOrientation) {
- case DisplayState::eOrientationDefault:
- transform = ui::Transform::ROT_0;
- break;
- case DisplayState::eOrientation90:
- transform = ui::Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- transform = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- transform = ui::Transform::ROT_270;
- break;
- }
- sPrimaryDisplayOrientation = transform;
+ sPrimaryDisplayOrientation = displayStateOrientationToTransformOrientation(orientation);
}
- mViewport = viewport;
- mFrame = frame;
+
+ getCompositionDisplay()->setProjection(globalTransform,
+ displayStateOrientationToTransformOrientation(
+ orientation),
+ frame, viewport, scissor, needsFiltering);
}
uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() {
@@ -726,149 +287,94 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = mId ? to_string(*mId) + ", " : std::string();
+ const auto id = getId() ? to_string(*getId()) + ", " : std::string();
return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
mDisplayName.c_str());
}
void DisplayDevice::dump(std::string& result) const {
- const ui::Transform& tr(mGlobalTransform);
- ANativeWindow* const window = mNativeWindow.get();
StringAppendF(&result, "+ %s\n", getDebugName().c_str());
- StringAppendF(&result,
- " 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());
- StringAppendF(&result,
- " 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",
- mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, mFrame.left,
- mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, mScissor.top,
- mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1],
- tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
- auto const surface = static_cast<Surface*>(window);
- ui::Dataspace dataspace = surface->getBuffersDataSpace();
- StringAppendF(&result,
- " wideColorGamut=%d, hdr10plus =%d, hdr10=%d, colorMode=%s, dataspace: %s "
- "(%d)\n",
- mHasWideColorGamut, mHasHdr10Plus, mHasHdr10,
- decodeColorMode(mActiveColorMode).c_str(),
- dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
- String8 surfaceDump;
- mDisplaySurface->dumpAsString(surfaceDump);
- result.append(surfaceDump.string(), surfaceDump.size());
+ result.append(" ");
+ StringAppendF(&result, "powerMode=%d, ", mPowerMode);
+ StringAppendF(&result, "activeConfig=%d, ", mActiveConfig);
+ StringAppendF(&result, "numLayers=%zu\n", mVisibleLayersSortedByZ.size());
+ getCompositionDisplay()->dump(result);
}
-// Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
-// supported by HWC.
-void DisplayDevice::addColorMode(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
- const ColorMode mode, const RenderIntent intent) {
- // find the best color mode
- const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
-
- // find the best render intent
- auto iter = hwcColorModes.find(hwcColorMode);
- const auto& hwcIntents =
- iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
- const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
-
- const Dataspace dataspace = colorModeToDataspace(mode);
- const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
-
- 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(),
- decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
-
- mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
+bool DisplayDevice::hasRenderIntent(ui::RenderIntent intent) const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasRenderIntent(intent);
}
-void DisplayDevice::populateColorModes(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes) {
- if (!hasWideColorGamut()) {
- return;
- }
+// ----------------------------------------------------------------------------
- // collect all known SDR render intents
- std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
- sSdrRenderIntents.end());
- auto iter = hwcColorModes.find(ColorMode::SRGB);
- if (iter != hwcColorModes.end()) {
- for (auto intent : iter->second) {
- sdrRenderIntents.insert(intent);
- }
- }
-
- // add all known SDR combinations
- for (auto intent : sdrRenderIntents) {
- for (auto mode : sSdrColorModes) {
- addColorMode(hwcColorModes, mode, intent);
- }
- }
-
- // collect all known HDR render intents
- std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
- sHdrRenderIntents.end());
- iter = hwcColorModes.find(ColorMode::BT2100_PQ);
- if (iter != hwcColorModes.end()) {
- for (auto intent : iter->second) {
- hdrRenderIntents.insert(intent);
- }
- }
-
- // add all known HDR combinations
- for (auto intent : sHdrRenderIntents) {
- for (auto mode : sHdrColorModes) {
- addColorMode(hwcColorModes, mode, intent);
- }
- }
+const std::optional<DisplayId>& DisplayDevice::getId() const {
+ return mCompositionDisplay->getId();
}
-bool DisplayDevice::hasRenderIntent(RenderIntent intent) const {
- // assume a render intent is supported when SRGB supports it; we should
- // get rid of that assumption.
- auto iter = mColorModes.find(getColorModeKey(Dataspace::V0_SRGB, intent));
- return iter != mColorModes.end() && iter->second.renderIntent == intent;
+bool DisplayDevice::isSecure() const {
+ return mCompositionDisplay->isSecure();
}
-bool DisplayDevice::hasLegacyHdrSupport(Dataspace dataspace) const {
- if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
- (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
- auto iter =
- mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
- return iter == mColorModes.end() || iter->second.dataspace != dataspace;
- }
-
- return false;
+const Rect& DisplayDevice::getBounds() const {
+ return mCompositionDisplay->getState().bounds;
}
-void DisplayDevice::getBestColorMode(Dataspace dataspace, RenderIntent intent,
- Dataspace* outDataspace, ColorMode* outMode,
- RenderIntent* outIntent) const {
- auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
- if (iter != mColorModes.end()) {
- *outDataspace = iter->second.dataspace;
- *outMode = iter->second.colorMode;
- *outIntent = iter->second.renderIntent;
- } else {
- // this is unexpected on a WCG display
- if (hasWideColorGamut()) {
- ALOGE("map unknown (%s)/(%s) to default color mode",
- dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
- decodeRenderIntent(intent).c_str());
- }
+const Region& DisplayDevice::getUndefinedRegion() const {
+ return mCompositionDisplay->getState().undefinedRegion;
+}
- *outDataspace = Dataspace::UNKNOWN;
- *outMode = ColorMode::NATIVE;
- *outIntent = RenderIntent::COLORIMETRIC;
- }
+bool DisplayDevice::needsFiltering() const {
+ return mCompositionDisplay->getState().needsFiltering;
+}
+
+uint32_t DisplayDevice::getLayerStack() const {
+ return mCompositionDisplay->getState().singleLayerStackId;
+}
+
+const ui::Transform& DisplayDevice::getTransform() const {
+ return mCompositionDisplay->getState().transform;
+}
+
+const Rect& DisplayDevice::getViewport() const {
+ return mCompositionDisplay->getState().viewport;
+}
+
+const Rect& DisplayDevice::getFrame() const {
+ return mCompositionDisplay->getState().frame;
+}
+
+const Rect& DisplayDevice::getScissor() const {
+ return mCompositionDisplay->getState().scissor;
+}
+
+bool DisplayDevice::hasWideColorGamut() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasWideColorGamut();
+}
+
+bool DisplayDevice::hasHDR10PlusSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHDR10PlusSupport();
+}
+
+bool DisplayDevice::hasHDR10Support() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHDR10Support();
+}
+
+bool DisplayDevice::hasHLGSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHLGSupport();
+}
+
+bool DisplayDevice::hasDolbyVisionSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasDolbyVisionSupport();
+}
+
+int DisplayDevice::getSupportedPerFrameMetadata() const {
+ return mCompositionDisplay->getDisplayColorProfile()->getSupportedPerFrameMetadata();
+}
+
+const HdrCapabilities& DisplayDevice::getHdrCapabilities() const {
+ return mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities();
}
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 250a650..9674f0d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -44,7 +44,6 @@
namespace android {
-class DisplaySurface;
class Fence;
class HWComposer;
class IGraphicBufferProducer;
@@ -55,35 +54,33 @@
struct DisplayDeviceCreationArgs;
struct DisplayInfo;
-class DisplayDevice : public LightRefBase<DisplayDevice>
-{
+namespace compositionengine {
+class Display;
+class DisplaySurface;
+} // namespace compositionengine
+
+class DisplayDevice : public LightRefBase<DisplayDevice> {
public:
constexpr static float sDefaultMinLumiance = 0.0;
constexpr static float sDefaultMaxLumiance = 500.0;
- // region in layer-stack space
- mutable Region dirtyRegion;
- // region in screen space
- Region undefinedRegion;
- bool lastCompositionHadVisibleLayers;
-
enum {
NO_LAYER_STACK = 0xFFFFFFFF,
};
explicit DisplayDevice(DisplayDeviceCreationArgs&& args);
- ~DisplayDevice();
+ virtual ~DisplayDevice();
+
+ std::shared_ptr<compositionengine::Display> getCompositionDisplay() const {
+ return mCompositionDisplay;
+ }
bool isVirtual() const { return mIsVirtual; }
bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
- bool isSecure() const { return mIsSecure; }
-
- // Flip the front and back buffers if the back buffer is "dirty". Might
- // be instantaneous, might involve copying the frame buffer around.
- void flip() const;
+ bool isSecure() const;
int getWidth() const;
int getHeight() const;
@@ -93,44 +90,34 @@
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
void setLayersNeedingFences(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getLayersNeedingFences() const;
- Region getDirtyRegion(bool repaintEverything) const;
void setLayerStack(uint32_t stack);
void setDisplaySize(const int newWidth, const int newHeight);
void setProjection(int orientation, const Rect& viewport, const Rect& frame);
int getOrientation() const { return mOrientation; }
- uint32_t getOrientationTransform() const;
static uint32_t getPrimaryDisplayOrientationTransform();
- const ui::Transform& getTransform() const { return mGlobalTransform; }
- const Rect getViewport() const { return mViewport; }
- const Rect getFrame() const { return mFrame; }
- const Rect& getScissor() const { return mScissor; }
- bool needsFiltering() const { return mNeedsFiltering; }
+ const ui::Transform& getTransform() const;
+ const Rect& getViewport() const;
+ const Rect& getFrame() const;
+ const Rect& getScissor() const;
+ bool needsFiltering() const;
+ uint32_t getLayerStack() const;
- uint32_t getLayerStack() const { return mLayerStack; }
-
- const std::optional<DisplayId>& getId() const { return mId; }
+ const std::optional<DisplayId>& getId() const;
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
int32_t getSequenceId() const { return mSequenceId; }
- int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
+ const Region& getUndefinedRegion() const;
- // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
- // machine happy without actually queueing a buffer if nothing has changed
- status_t beginFrame(bool mustRecompose) const;
- status_t prepareFrame(HWComposer& hwc, std::vector<CompositionInfo>& compositionInfo);
+ int32_t getSupportedPerFrameMetadata() const;
- bool hasWideColorGamut() const { return mHasWideColorGamut; }
+ bool hasWideColorGamut() const;
// Whether h/w composer has native support for specific HDR type.
- bool hasHDR10PlusSupport() const { return mHasHdr10Plus; }
- bool hasHDR10Support() const { return mHasHdr10; }
- bool hasHLGSupport() const { return mHasHLG; }
- bool hasDolbyVisionSupport() const { return mHasDolbyVision; }
-
- // Return true if the HDR dataspace is supported but
- // there is no corresponding color mode.
- bool hasLegacyHdrSupport(ui::Dataspace dataspace) const;
+ bool hasHDR10PlusSupport() const;
+ bool hasHDR10Support() const;
+ bool hasHLGSupport() const;
+ bool hasDolbyVisionSupport() const;
// The returned HdrCapabilities is the combination of HDR capabilities from
// hardware composer and RenderEngine. When the DisplayDevice supports wide
@@ -138,41 +125,17 @@
// color space for both PQ and HLG HDR contents. The minimum and maximum
// luminance will be set to sDefaultMinLumiance and sDefaultMaxLumiance
// respectively if hardware composer doesn't return meaningful values.
- const HdrCapabilities& getHdrCapabilities() const { return mHdrCapabilities; }
+ const HdrCapabilities& getHdrCapabilities() const;
// Return true if intent is supported by the display.
bool hasRenderIntent(ui::RenderIntent intent) const;
- void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
- ui::Dataspace* outDataspace, ui::ColorMode* outMode,
- ui::RenderIntent* outIntent) const;
-
- void setProtected(bool useProtected);
- // 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 onPresentDisplayCompleted();
-
- Rect getBounds() const {
- return Rect(mDisplayWidth, mDisplayHeight);
- }
- inline Rect bounds() const { return getBounds(); }
+ const Rect& getBounds() const;
+ const Rect& bounds() const { return getBounds(); }
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
- // 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;
-
/* ------------------------------------------------------------------------
* Display power mode management.
*/
@@ -180,13 +143,6 @@
void setPowerMode(int mode);
bool isPoweredOn() const;
- ui::ColorMode getActiveColorMode() const;
- void setActiveColorMode(ui::ColorMode mode);
- ui::RenderIntent getActiveRenderIntent() const;
- void setActiveRenderIntent(ui::RenderIntent renderIntent);
- android_color_transform_t getColorTransform() const;
- void setColorTransform(const mat4& transform);
- void setCompositionDataSpace(ui::Dataspace dataspace);
ui::Dataspace getCompositionDataSpace() const;
/* ------------------------------------------------------------------------
@@ -196,7 +152,7 @@
void setActiveConfig(int mode);
// release HWC resources (if any) for removable displays
- void disconnect(HWComposer& hwc);
+ void disconnect();
/* ------------------------------------------------------------------------
* Debugging
@@ -206,29 +162,18 @@
void dump(std::string& result) const;
private:
+ /*
+ * Constants, set during initialization
+ */
const sp<SurfaceFlinger> mFlinger;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
- std::optional<DisplayId> mId;
+ const int mDisplayInstallOrientation;
+ const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
- // 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;
-
- int mDisplayWidth;
- int mDisplayHeight;
- const int mDisplayInstallOrientation;
- mutable uint32_t mPageFlipCount;
- std::string mDisplayName;
-
+ std::string mDisplayName;
const bool mIsVirtual;
- const bool mIsSecure;
/*
* Can only accessed from the main thread, these members
@@ -243,66 +188,17 @@
/*
* Transaction state
*/
+ static uint32_t displayStateOrientationToTransformOrientation(int orientation);
static status_t orientationToTransfrom(int orientation,
int w, int h, ui::Transform* tr);
- // The identifier of the active layer stack for this display. Several displays
- // can use the same layer stack: A z-ordered group of layers (sometimes called
- // "surfaces"). Any given layer can only be on a single layer stack.
- uint32_t mLayerStack;
-
int mOrientation;
static uint32_t sPrimaryDisplayOrientation;
- // user-provided visible area of the layer stack
- Rect mViewport;
- // user-provided rectangle where mViewport gets mapped to
- Rect mFrame;
- // pre-computed scissor to apply to the display
- Rect mScissor;
- ui::Transform mGlobalTransform;
- bool mNeedsFiltering;
+
// Current power mode
int mPowerMode;
// Current active config
int mActiveConfig;
- // current active color mode
- ui::ColorMode mActiveColorMode = ui::ColorMode::NATIVE;
- // Current active render intent.
- ui::RenderIntent mActiveRenderIntent = ui::RenderIntent::COLORIMETRIC;
- ui::Dataspace mCompositionDataSpace = ui::Dataspace::UNKNOWN;
- // Current color transform
- android_color_transform_t mColorTransform;
-
- // Need to know if display is wide-color capable or not.
- // Initialized by SurfaceFlinger when the DisplayDevice is created.
- // Fed to RenderEngine during composition.
- bool mHasWideColorGamut;
- bool mHasHdr10Plus;
- bool mHasHdr10;
- bool mHasHLG;
- bool mHasDolbyVision;
- HdrCapabilities mHdrCapabilities;
- const int32_t mSupportedPerFrameMetadata;
-
- // Mappings from desired Dataspace/RenderIntent to the supported
- // Dataspace/ColorMode/RenderIntent.
- using ColorModeKey = uint64_t;
- struct ColorModeValue {
- ui::Dataspace dataspace;
- ui::ColorMode colorMode;
- ui::RenderIntent renderIntent;
- };
-
- static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {
- return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent);
- }
- void populateColorModes(
- const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes);
- void addColorMode(
- const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes,
- 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;
@@ -341,7 +237,7 @@
bool isVirtual{false};
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
- sp<DisplaySurface> displaySurface;
+ sp<compositionengine::DisplaySurface> displaySurface;
int displayInstallOrientation{DisplayState::eOrientationDefault};
bool hasWideColorGamut{false};
HdrCapabilities hdrCapabilities;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 2431dfd..18c524f 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -17,15 +17,15 @@
#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
-#include "DisplayIdentification.h"
-#include "DisplaySurface.h"
-#include "HWComposerBufferCache.h"
-
#include <stdint.h>
#include <sys/types.h>
+#include <compositionengine/DisplaySurface.h>
#include <gui/ConsumerBase.h>
+#include "DisplayIdentification.h"
+#include "HWComposerBufferCache.h"
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -36,8 +36,7 @@
// ---------------------------------------------------------------------------
-class FramebufferSurface : public ConsumerBase,
- public DisplaySurface {
+class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface {
public:
FramebufferSurface(HWComposer& hwc, DisplayId displayId,
const sp<IGraphicBufferConsumer>& consumer);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 27d3dc5..1c2853a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -38,12 +38,16 @@
#define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \
mDisplayName.c_str(), ##__VA_ARGS__)
-static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
+static const char* dbgCompositionTypeStr(compositionengine::DisplaySurface::CompositionType type) {
switch (type) {
- case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN";
- case DisplaySurface::COMPOSITION_GLES: return "GLES";
- case DisplaySurface::COMPOSITION_HWC: return "HWC";
- case DisplaySurface::COMPOSITION_MIXED: return "MIXED";
+ case compositionengine::DisplaySurface::COMPOSITION_UNKNOWN:
+ return "UNKNOWN";
+ case compositionengine::DisplaySurface::COMPOSITION_GLES:
+ return "GLES";
+ case compositionengine::DisplaySurface::COMPOSITION_HWC:
+ return "HWC";
+ case compositionengine::DisplaySurface::COMPOSITION_MIXED:
+ return "MIXED";
default: return "<INVALID>";
}
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 33678df..87ae7dd 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -20,13 +20,13 @@
#include <optional>
#include <string>
-#include "DisplayIdentification.h"
-#include "DisplaySurface.h"
-#include "HWComposerBufferCache.h"
-
+#include <compositionengine/DisplaySurface.h>
#include <gui/ConsumerBase.h>
#include <gui/IGraphicBufferProducer.h>
+#include "DisplayIdentification.h"
+#include "HWComposerBufferCache.h"
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -73,7 +73,7 @@
* the HWC output buffer. When HWC composition is complete, the scratch buffer
* is released and the output buffer is queued to the sink.
*/
-class VirtualDisplaySurface : public DisplaySurface,
+class VirtualDisplaySurface : public compositionengine::DisplaySurface,
public BnGraphicBufferProducer,
private ConsumerBase {
public:
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ee49610..aa9bc15 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2135,7 +2135,7 @@
return mRemovedFromCurrentState;
}
-InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
+InputWindowInfo Layer::fillInputInfo() {
InputWindowInfo info = mDrawingState.inputInfo;
ui::Transform t = getTransform();
@@ -2148,20 +2148,18 @@
}
// Transform layer size to screen space and inset it by surface insets.
- Rect layerBounds = getCroppedBufferSize(getDrawingState());
+ Rect layerBounds = getBufferSize(getDrawingState());
+ if (!layerBounds.isValid()) {
+ layerBounds = getCroppedBufferSize(getDrawingState());
+ }
layerBounds = t.transform(layerBounds);
layerBounds.inset(info.surfaceInset, info.surfaceInset, info.surfaceInset, info.surfaceInset);
- // Intersect with screen bounds to shrink the frame by the surface insets. The surface insets
- // are not set on the screen bounds directly since the surface inset region may already be
- // cropped by a parent layer.
- Rect frame;
- screenBounds.intersect(layerBounds, &frame);
-
- info.frameLeft = frame.left;
- info.frameTop = frame.top;
- info.frameRight = frame.right;
- info.frameBottom = frame.bottom;
+ // Input coordinate should match the layer bounds.
+ info.frameLeft = layerBounds.left;
+ info.frameTop = layerBounds.top;
+ info.frameRight = layerBounds.right;
+ info.frameBottom = layerBounds.bottom;
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 7bc7a82..95a8630 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -773,7 +773,7 @@
bool mPendingHWCDestroy{false};
void setInputInfo(const InputWindowInfo& info);
- InputWindowInfo fillInputInfo(const Rect& screenBounds);
+ InputWindowInfo fillInputInfo();
bool hasInput() const;
protected:
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index b74b901..9b2a6fc 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -657,6 +657,9 @@
Mutex::Autolock lock(mMutex);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t phase = mReferenceTime + mPhase;
+ if (mPeriod == 0) {
+ return 0;
+ }
return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index bf925b2..7b25adb 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -43,8 +43,12 @@
// ---------------------------------------------------------------------------
-EventThreadConnection::EventThreadConnection(EventThread* eventThread)
- : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
+EventThreadConnection::EventThreadConnection(EventThread* eventThread,
+ ResyncCallback resyncCallback)
+ : resyncCallback(std::move(resyncCallback)),
+ count(-1),
+ mEventThread(eventThread),
+ mChannel(gui::BitTube::DefaultSize) {}
EventThreadConnection::~EventThreadConnection() {
// do nothing here -- clean-up will happen automatically
@@ -88,26 +92,21 @@
namespace impl {
EventThread::EventThread(std::unique_ptr<VSyncSource> src,
- const ResyncWithRateLimitCallback& resyncWithRateLimitCallback,
const InterceptVSyncsCallback& interceptVSyncsCallback,
const ResetIdleTimerCallback& resetIdleTimerCallback,
const char* threadName)
- : EventThread(nullptr, std::move(src), resyncWithRateLimitCallback, interceptVSyncsCallback,
- threadName) {
+ : EventThread(nullptr, std::move(src), interceptVSyncsCallback, threadName) {
mResetIdleTimer = resetIdleTimerCallback;
}
-EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
- InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
- : EventThread(src, nullptr, resyncWithRateLimitCallback, interceptVSyncsCallback,
- threadName) {}
+EventThread::EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
+ const char* threadName)
+ : EventThread(src, nullptr, interceptVSyncsCallback, threadName) {}
EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
- ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
: mVSyncSource(src),
mVSyncSourceUnique(std::move(uniqueSrc)),
- mResyncWithRateLimitCallback(resyncWithRateLimitCallback),
mInterceptVSyncsCallback(interceptVSyncsCallback) {
if (src == nullptr) {
mVSyncSource = mVSyncSourceUnique.get();
@@ -150,8 +149,8 @@
mVSyncSource->setPhaseOffset(phaseOffset);
}
-sp<EventThreadConnection> EventThread::createEventConnection() const {
- return new EventThreadConnection(const_cast<EventThread*>(this));
+sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
+ return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
}
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -195,8 +194,9 @@
ATRACE_NAME("resetIdleTimer");
mResetIdleTimer();
}
- if (mResyncWithRateLimitCallback) {
- mResyncWithRateLimitCallback();
+
+ if (connection->resyncCallback) {
+ connection->resyncCallback();
}
std::lock_guard<std::mutex> lock(mMutex);
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index e110488..a411885 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -44,6 +44,8 @@
// ---------------------------------------------------------------------------
+using ResyncCallback = std::function<void()>;
+
class VSyncSource {
public:
class Callback {
@@ -60,7 +62,7 @@
class EventThreadConnection : public BnDisplayEventConnection {
public:
- explicit EventThreadConnection(EventThread* eventThread);
+ EventThreadConnection(EventThread* eventThread, ResyncCallback resyncCallback);
virtual ~EventThreadConnection();
virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -72,6 +74,9 @@
// in order to update the configs.
void requestNextVsyncForHWC();
+ // Called in response to requestNextVsync.
+ const ResyncCallback resyncCallback;
+
// count >= 1 : continuous event. count is the vsync rate
// count == 0 : one-shot event that has not fired
// count ==-1 : one-shot event that fired this round / disabled
@@ -90,7 +95,8 @@
virtual ~EventThread();
- virtual sp<EventThreadConnection> createEventConnection() const = 0;
+ virtual sp<EventThreadConnection> createEventConnection(
+ ResyncCallback resyncCallback) const = 0;
// called before the screen is turned off from main thread
virtual void onScreenReleased() = 0;
@@ -117,20 +123,18 @@
class EventThread : public android::EventThread, private VSyncSource::Callback {
public:
- using ResyncWithRateLimitCallback = std::function<void()>;
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
using ResetIdleTimerCallback = std::function<void()>;
// TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
- EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
- InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+ EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
+ const char* threadName);
EventThread(std::unique_ptr<VSyncSource> src,
- const ResyncWithRateLimitCallback& resyncWithRateLimitCallback,
const InterceptVSyncsCallback& interceptVSyncsCallback,
const ResetIdleTimerCallback& resetIdleTimerCallback, const char* threadName);
~EventThread();
- sp<EventThreadConnection> createEventConnection() const override;
+ sp<EventThreadConnection> createEventConnection(ResyncCallback resyncCallback) const override;
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) override;
@@ -155,7 +159,6 @@
// TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
- ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
@@ -179,7 +182,6 @@
VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
// constants
- const ResyncWithRateLimitCallback mResyncWithRateLimitCallback;
const InterceptVSyncsCallback mInterceptVSyncsCallback;
std::thread mThread;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 66f42bb..75a410b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -85,7 +85,8 @@
mHandler = new Handler(*this);
}
-void MessageQueue::setEventThread(android::EventThread* eventThread) {
+void MessageQueue::setEventThread(android::EventThread* eventThread,
+ ResyncCallback resyncCallback) {
if (mEventThread == eventThread) {
return;
}
@@ -95,7 +96,7 @@
}
mEventThread = eventThread;
- mEvents = eventThread->createEventConnection();
+ mEvents = eventThread->createEventConnection(std::move(resyncCallback));
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
this);
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 0bf00b0..56a00c0 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -29,12 +29,12 @@
#include <private/gui/BitTube.h>
#include "Barrier.h"
+#include "EventThread.h"
#include <functional>
namespace android {
-class EventThread;
class SurfaceFlinger;
// ---------------------------------------------------------------------------
@@ -86,7 +86,7 @@
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
// TODO(akrulec): Remove this function once everything is migrated to Scheduler.
- virtual void setEventThread(EventThread* events) = 0;
+ virtual void setEventThread(EventThread* events, ResyncCallback resyncCallback) = 0;
virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
virtual void waitMessage() = 0;
virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
@@ -127,7 +127,7 @@
public:
~MessageQueue() override = default;
void init(const sp<SurfaceFlinger>& flinger) override;
- void setEventThread(android::EventThread* events) override;
+ void setEventThread(android::EventThread* events, ResyncCallback resyncCallback) override;
void setEventConnection(const sp<EventThreadConnection>& connection) override;
void waitMessage() override;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index fec53af..0d587dd 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -86,39 +86,38 @@
Scheduler::~Scheduler() = default;
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const std::string& connectionName, int64_t phaseOffsetNs,
- impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ const std::string& connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
- makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, resyncCallback,
+ makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
interceptCallback);
auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
- eventThread->createEventConnection(),
+ eventThread->createEventConnection(
+ std::move(resyncCallback)),
std::move(eventThread));
+
mConnections.insert(std::make_pair(id, std::move(connection)));
return mConnections[id]->handle;
}
std::unique_ptr<EventThread> Scheduler::makeEventThread(
const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
- impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const std::string sourceName = connectionName + "Source";
std::unique_ptr<VSyncSource> eventThreadSource =
std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, sourceName.c_str());
const std::string threadName = connectionName + "Thread";
- return std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
- interceptCallback, [this] { resetIdleTimer(); },
- threadName.c_str());
+ return std::make_unique<impl::EventThread>(std::move(eventThreadSource), interceptCallback,
+ [this] { resetIdleTimer(); }, threadName.c_str());
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle) {
+ const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
RETURN_VALUE_IF_INVALID(nullptr);
- return mConnections[handle->id]->thread->createEventConnection();
+ return mConnections[handle->id]->thread->createEventConnection(std::move(resyncCallback));
}
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 3538f31..ba18d21 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -73,11 +73,11 @@
/** Creates an EventThread connection. */
sp<ConnectionHandle> createConnection(
- const std::string& connectionName, int64_t phaseOffsetNs,
- impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ const std::string& connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
- sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
+ sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
+ ResyncCallback resyncCallback);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -122,7 +122,6 @@
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
- impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9eff3c6..5df2876 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -17,15 +17,16 @@
// #define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <stdint.h>
#include <sys/types.h>
-#include <algorithm>
#include <errno.h>
-#include <math.h>
-#include <mutex>
#include <dlfcn.h>
-#include <inttypes.h>
-#include <stdatomic.h>
+
+#include <algorithm>
+#include <cinttypes>
+#include <cmath>
+#include <cstdint>
+#include <functional>
+#include <mutex>
#include <optional>
#include <cutils/properties.h>
@@ -36,6 +37,10 @@
#include <binder/PermissionCache.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <dvr/vr_flinger.h>
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
@@ -618,6 +623,8 @@
Mutex::Autolock _l(mStateLock);
+ auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+
// start the EventThread
if (mUseScheduler) {
mScheduler = getFactory().createScheduler([this](bool enabled) {
@@ -626,12 +633,11 @@
mAppConnectionHandle =
mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
- [this] { resyncWithRateLimit(); },
+ resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
mScheduler->createConnection("sfConnection", SurfaceFlinger::sfVsyncPhaseOffsetNs,
- [this] { resyncWithRateLimit(); },
- [this](nsecs_t timestamp) {
+ resyncCallback, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
@@ -644,7 +650,6 @@
SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
mEventThread =
std::make_unique<impl::EventThread>(mEventThreadSource.get(),
- [this] { resyncWithRateLimit(); },
impl::EventThread::InterceptVSyncsCallback(),
"appEventThread");
mSfEventThreadSource =
@@ -653,12 +658,11 @@
mSFEventThread =
std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
- [this] { resyncWithRateLimit(); },
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
},
"sfEventThread");
- mEventQueue->setEventThread(mSFEventThread.get());
+ mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
}
@@ -942,13 +946,15 @@
status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
ATRACE_NAME("setActiveConfigAsync");
- postMessageAsync(new LambdaMessage([=] { setActiveConfigInternal(displayToken, mode); }));
+ postMessageAsync(new LambdaMessage(
+ [=]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
return NO_ERROR;
}
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
ATRACE_NAME("setActiveConfigSync");
- postMessageSync(new LambdaMessage([&] { setActiveConfigInternal(displayToken, mode); }));
+ postMessageSync(new LambdaMessage(
+ [&]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
return NO_ERROR;
}
@@ -989,7 +995,7 @@
getHwComposer().setActiveConfig(*displayId, mode);
ATRACE_INT("ActiveConfigMode", mode);
- resyncToHardwareVsync(true);
+ resyncToHardwareVsync(true, getVsyncPeriod());
}
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1017,40 +1023,11 @@
ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
if (const auto display = getDisplayDevice(displayToken)) {
- return display->getActiveColorMode();
+ return display->getCompositionDisplay()->getState().colorMode;
}
return static_cast<ColorMode>(BAD_VALUE);
}
-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();
-
- if (mode == currentMode && dataSpace == currentDataSpace &&
- renderIntent == currentRenderIntent) {
- return;
- }
-
- display->setActiveColorMode(mode);
- display->setCompositionDataSpace(dataSpace);
- display->setActiveRenderIntent(renderIntent);
-
- 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=%s",
- decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent, to_string(*displayId).c_str());
-}
-
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
postMessageSync(new LambdaMessage([&] {
Vector<ColorMode> modes;
@@ -1069,8 +1046,8 @@
ALOGW("Attempt to set active color mode %s (%d) for virtual display",
decodeColorMode(mode).c_str(), mode);
} else {
- setActiveColorModeInternal(display, mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
+ display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
+ RenderIntent::COLORIMETRIC);
}
}));
@@ -1153,6 +1130,28 @@
outStats);
}
+status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const {
+ if (!outSupported) {
+ return BAD_VALUE;
+ }
+ *outSupported = getRenderEngine().supportsProtectedContent();
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
+ int32_t* outBufferId) {
+ if (!outBufferId) {
+ return BAD_VALUE;
+ }
+ *outBufferId = mBufferStateLayerCache.add(token, buffer);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
+ mBufferStateLayerCache.release(token, bufferId);
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
postMessageSync(new LambdaMessage([&] {
Mutex::Autolock _l(mStateLock);
@@ -1161,6 +1160,8 @@
return;
}
+ auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+
// TODO(akrulec): Part of the Injector should be refactored, so that it
// can be passed to Scheduler.
if (enable) {
@@ -1168,14 +1169,14 @@
if (mVSyncInjector.get() == nullptr) {
mVSyncInjector = std::make_unique<InjectVSyncSource>();
mInjectorEventThread = std::make_unique<
- impl::EventThread>(mVSyncInjector.get(), [this] { resyncWithRateLimit(); },
+ impl::EventThread>(mVSyncInjector.get(),
impl::EventThread::InterceptVSyncsCallback(),
"injEventThread");
}
- mEventQueue->setEventThread(mInjectorEventThread.get());
+ mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
} else {
ALOGV("VSync Injections disabled");
- mEventQueue->setEventThread(mSFEventThread.get());
+ mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
}
mInjectVSyncs = enable;
@@ -1232,17 +1233,22 @@
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
+ auto resyncCallback = makeResyncCallback([this] {
+ Mutex::Autolock lock(mStateLock);
+ return getVsyncPeriod();
+ });
+
if (mUseScheduler) {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mScheduler->createDisplayEventConnection(mSfConnectionHandle);
+ return mScheduler->createDisplayEventConnection(mSfConnectionHandle, resyncCallback);
} else {
- return mScheduler->createDisplayEventConnection(mAppConnectionHandle);
+ return mScheduler->createDisplayEventConnection(mAppConnectionHandle, resyncCallback);
}
} else {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mSFEventThread->createEventConnection();
+ return mSFEventThread->createEventConnection(resyncCallback);
} else {
- return mEventThread->createEventConnection();
+ return mEventThread->createEventConnection(resyncCallback);
}
}
}
@@ -1286,6 +1292,16 @@
} while (true);
}
+nsecs_t SurfaceFlinger::getVsyncPeriod() const {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId || !getHwComposer().isConnected(*displayId)) {
+ return 0;
+ }
+
+ const auto config = getHwComposer().getActiveConfig(*displayId);
+ return config ? config->getVsyncPeriod() : 0;
+}
+
void SurfaceFlinger::enableHardwareVsync() {
Mutex::Autolock _l(mHWVsyncLock);
if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
@@ -1295,7 +1311,7 @@
}
}
-void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
+void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
Mutex::Autolock _l(mHWVsyncLock);
if (makeAvailable) {
@@ -1310,14 +1326,10 @@
return;
}
- const auto displayId = getInternalDisplayId();
- if (!displayId || !getHwComposer().isConnected(*displayId)) {
+ if (period <= 0) {
return;
}
- const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- const nsecs_t period = activeConfig->getVsyncPeriod();
-
if (mUseScheduler) {
mScheduler->setVsyncPeriod(period);
} else {
@@ -1344,16 +1356,15 @@
}
}
-void SurfaceFlinger::resyncWithRateLimit() {
+void SurfaceFlinger::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
- // No explicit locking is needed here since EventThread holds a lock while calling this method
- static nsecs_t sLastResyncAttempted = 0;
const nsecs_t now = systemTime();
- if (now - sLastResyncAttempted > kIgnoreDelay) {
- resyncToHardwareVsync(false);
+ const nsecs_t last = lastResyncTime.exchange(now);
+
+ if (now - last > kIgnoreDelay) {
+ flinger.resyncToHardwareVsync(false, getVsyncPeriod());
}
- sLastResyncAttempted = now;
}
void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1553,9 +1564,8 @@
setPowerModeInternal(display, currentDisplayPowerMode);
// Reset the timing values to account for the period of the swapped in HWC
- const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
- const nsecs_t period = activeConfig->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(period);
+ const nsecs_t vsyncPeriod = getVsyncPeriod();
+ mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
// The present fences returned from vr_hwc are not an accurate
// representation of vsync times.
@@ -1569,10 +1579,10 @@
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+ DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
setCompositorTimingSnapped(stats, 0);
- resyncToHardwareVsync(false);
+ resyncToHardwareVsync(false, vsyncPeriod);
mRepaintEverything = true;
setTransactionFlags(eDisplayTransactionNeeded);
@@ -1667,9 +1677,11 @@
postComposition();
mHadClientComposition = false;
- for (const auto& [token, display] : mDisplays) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto displayId = display->getId();
mHadClientComposition =
- mHadClientComposition || getHwComposer().hasClientComposition(display->getId());
+ mHadClientComposition || getHwComposer().hasClientComposition(displayId);
}
// Setup RenderEngine sync fences if native sync is supported.
@@ -1709,13 +1721,14 @@
// build the h/w work list
if (CC_UNLIKELY(mGeometryInvalid)) {
mGeometryInvalid = false;
- for (const auto& [token, display] : mDisplays) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
- const Vector<sp<Layer>>& currentLayers = display->getVisibleLayersSortedByZ();
+ const Vector<sp<Layer>>& currentLayers = displayDevice->getVisibleLayersSortedByZ();
for (size_t i = 0; i < currentLayers.size(); i++) {
const auto& layer = currentLayers[i];
@@ -1726,7 +1739,7 @@
}
}
- layer->setGeometry(display, i);
+ layer->setGeometry(displayDevice, i);
if (mDebugDisableHWC || mDebugRegion) {
layer->forceClientComposition(*displayId);
}
@@ -1735,29 +1748,27 @@
}
// Set the per-frame data
- for (const auto& [token, display] : mDisplays) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
+ auto* profile = display->getDisplayColorProfile();
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
- status_t result =
- getHwComposer().setColorTransform(*displayId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %s: %d",
- to_string(*displayId).c_str(), result);
}
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !display->hasHDR10Support()) {
+ !profile->hasHDR10Support()) {
layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !display->hasHLGSupport()) {
+ !profile->hasHLGSupport()) {
layer->forceClientComposition(*displayId);
}
@@ -1776,16 +1787,17 @@
continue;
}
- layer->setPerFrameData(*displayId, display->getTransform(), display->getViewport(),
- display->getSupportedPerFrameMetadata());
+ const auto& displayState = display->getState();
+ layer->setPerFrameData(*displayId, displayState.transform, displayState.viewport,
+ displayDevice->getSupportedPerFrameMetadata());
}
if (useColorManagement) {
ColorMode colorMode;
Dataspace dataSpace;
RenderIntent renderIntent;
- pickColorMode(display, &colorMode, &dataSpace, &renderIntent);
- setActiveColorModeInternal(display, colorMode, dataSpace, renderIntent);
+ pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
+ display->setColorMode(colorMode, dataSpace, renderIntent);
}
}
@@ -1809,34 +1821,37 @@
}
}
-void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything)
-{
+void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& displayDevice,
+ bool repaintEverything) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
// is debugging enabled
if (CC_LIKELY(!mDebugRegion))
return;
- if (display->isPoweredOn()) {
+ if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(display->getDirtyRegion(repaintEverything));
+ const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
if (!dirtyRegion.isEmpty()) {
// redraw the whole screen
- doComposeSurfaces(display);
+ doComposeSurfaces(displayDevice);
// and draw the dirty region
auto& engine(getRenderEngine());
engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
- display->queueBuffer(getHwComposer());
+ display->getRenderSurface()->queueBuffer();
}
}
- postFramebuffer(display);
+ postFramebuffer(displayDevice);
if (mDebugRegion > 1) {
usleep(mDebugRegion * 1000);
}
- prepareFrame(display);
+ prepareFrame(displayDevice);
}
void SurfaceFlinger::doTracing(const char* where) {
@@ -2001,16 +2016,18 @@
ASSERT_ON_STACK_GUARD();
// |mStateLock| not needed as we are on the main thread
- const auto display = getDefaultDisplayDeviceLocked();
- DEFINE_STACK_GUARD(display);
+ const auto displayDevice = getDefaultDisplayDeviceLocked();
+ DEFINE_STACK_GUARD(displayDevice);
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
DEFINE_STACK_GUARD(glCompositionDoneFenceTime);
- if (display && getHwComposer().hasClientComposition(display->getId())) {
+ if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
glCompositionDoneFenceTime =
- std::make_shared<FenceTime>(display->getClientTargetAcquireFence());
+ std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
+ ->getRenderSurface()
+ ->getClientTargetAcquireFence());
getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
@@ -2019,8 +2036,8 @@
ASSERT_ON_STACK_GUARD();
getBE().mDisplayTimeline.updateSignalTimes();
- mPreviousPresentFence =
- display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
+ mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId())
+ : Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
DEFINE_STACK_GUARD(presentFenceTime);
getBE().mDisplayTimeline.push(presentFenceTime);
@@ -2052,8 +2069,9 @@
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
- bool frameLatched = layer->onPostComposition(display->getId(), glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ bool frameLatched =
+ layer->onPostComposition(displayDevice->getId(), glCompositionDoneFenceTime,
+ presentFenceTime, compositorTiming);
DEFINE_STACK_GUARD(frameLatched);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
@@ -2078,7 +2096,8 @@
}
if (!hasSyncFramework) {
- if (display && getHwComposer().isConnected(*display->getId()) && display->isPoweredOn()) {
+ if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
+ displayDevice->isPoweredOn()) {
if (mUseScheduler) {
mScheduler->enableHardwareVsync();
} else {
@@ -2097,10 +2116,11 @@
std::move(presentFenceTime));
ASSERT_ON_STACK_GUARD();
- } else if (display && getHwComposer().isConnected(*display->getId())) {
+ } else if (displayDevice && getHwComposer().isConnected(*displayDevice->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(*displayDevice->getId());
DEFINE_STACK_GUARD(presentTime);
mAnimFrameTracker.setActualPresentTime(presentTime);
@@ -2122,7 +2142,8 @@
ASSERT_ON_STACK_GUARD();
- if (display && getHwComposer().isConnected(*display->getId()) && !display->isPoweredOn()) {
+ if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
+ !displayDevice->isPoweredOn()) {
return;
}
@@ -2190,20 +2211,22 @@
invalidateHwcGeometry();
for (const auto& pair : mDisplays) {
- const auto& display = pair.second;
+ const auto& displayDevice = pair.second;
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
Region opaqueRegion;
Region dirtyRegion;
Vector<sp<Layer>> layersSortedByZ;
Vector<sp<Layer>> layersNeedingFences;
- const ui::Transform& tr = display->getTransform();
- const Rect bounds = display->getBounds();
- if (display->isPoweredOn()) {
- computeVisibleRegions(display, dirtyRegion, opaqueRegion);
+ const ui::Transform& tr = displayState.transform;
+ const Rect bounds = displayState.bounds;
+ if (displayState.isEnabled) {
+ computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool hwcLayerDestroyed = false;
- const auto displayId = display->getId();
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ const auto displayId = displayDevice->getId();
+ if (display->belongsInOutput(layer->getLayerStack())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
@@ -2234,11 +2257,14 @@
}
});
}
- display->setVisibleLayersSortedByZ(layersSortedByZ);
- display->setLayersNeedingFences(layersNeedingFences);
- display->undefinedRegion.set(bounds);
- display->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
- display->dirtyRegion.orSelf(dirtyRegion);
+ displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
+ displayDevice->setLayersNeedingFences(layersNeedingFences);
+
+ Region undefinedRegion{bounds};
+ undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
+
+ display->editState().undefinedRegion = undefinedRegion;
+ display->editState().dirtyRegion.orSelf(dirtyRegion);
}
}
}
@@ -2303,9 +2329,11 @@
Dataspace hdrDataSpace;
Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace);
+ auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();
+
// respect hdrDataSpace only when there is no legacy HDR support
- const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
- !display->hasLegacyHdrSupport(hdrDataSpace);
+ const bool isHdr =
+ hdrDataSpace != Dataspace::UNKNOWN && !profile->hasLegacyHdrSupport(hdrDataSpace);
if (isHdr) {
bestDataSpace = hdrDataSpace;
}
@@ -2324,14 +2352,16 @@
break;
}
- display->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
+ profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& display)
-{
- bool dirty = !display->getDirtyRegion(false).isEmpty();
- bool empty = display->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !display->lastCompositionHadVisibleLayers;
+void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ bool dirty = !display->getPhysicalSpaceDirtyRegion(false).isEmpty();
+ bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
+ bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
// If nothing has changed (!dirty), don't recompose.
// If something changed, but we don't currently have any visible layers,
@@ -2345,44 +2375,50 @@
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]);
+ ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
+ __FUNCTION__, mustRecompose ? "doing" : "skipping",
+ displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
+ flagPrefix[wasEmpty]);
- display->beginFrame(mustRecompose);
+ display->getRenderSurface()->beginFrame(mustRecompose);
if (mustRecompose) {
- display->lastCompositionHadVisibleLayers = !empty;
+ display->editState().lastCompositionHadVisibleLayers = !empty;
}
}
-void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& display)
-{
- if (!display->isPoweredOn()) {
+void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ if (!displayState.isEnabled) {
return;
}
- status_t result = display->prepareFrame(getHwComposer(),
- getBE().mCompositionInfo[display->getDisplayToken()]);
+ status_t result = display->getRenderSurface()->prepareFrame(
+ getBE().mCompositionInfo[displayDevice->getDisplayToken()]);
ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
- display->getDebugName().c_str(), result, strerror(-result));
+ displayDevice->getDebugName().c_str(), result, strerror(-result));
}
-void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
+void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
- if (display->isPoweredOn()) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(display->getDirtyRegion(repaintEverything));
+ const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
// repaint the framebuffer (if needed)
- doDisplayComposition(display, dirtyRegion);
+ doDisplayComposition(displayDevice, dirtyRegion);
- display->dirtyRegion.clear();
- display->flip();
+ display->editState().dirtyRegion.clear();
+ display->getRenderSurface()->flip();
}
- postFramebuffer(display);
+ postFramebuffer(displayDevice);
}
void SurfaceFlinger::postFrame()
@@ -2397,20 +2433,22 @@
}
}
-void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& display)
-{
+void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
ATRACE_CALL();
ALOGV("postFramebuffer");
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+ const auto displayId = display->getId();
+
mPostFramebufferTime = systemTime();
- if (display->isPoweredOn()) {
- const auto displayId = display->getId();
+ if (displayState.isEnabled) {
if (displayId) {
getHwComposer().presentAndGetReleaseFences(*displayId);
}
- display->onPresentDisplayCompleted();
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ display->getRenderSurface()->onPresentDisplayCompleted();
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
// The layer buffer from the previous frame (if any) is released
@@ -2427,8 +2465,9 @@
// client target acquire fence when it is available, even though
// this is suboptimal.
if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
- releaseFence = Fence::merge("LayerRelease", releaseFence,
- display->getClientTargetAcquireFence());
+ releaseFence =
+ Fence::merge("LayerRelease", releaseFence,
+ display->getRenderSurface()->getClientTargetAcquireFence());
}
layer->getBE().onLayerDisplayed(releaseFence);
@@ -2437,10 +2476,10 @@
// We've got a list of layers needing fences, that are disjoint with
// display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
- if (!display->getLayersNeedingFences().isEmpty()) {
+ if (!displayDevice->getLayersNeedingFences().isEmpty()) {
sp<Fence> presentFence =
displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
- for (auto& layer : display->getLayersNeedingFences()) {
+ for (auto& layer : displayDevice->getLayersNeedingFences()) {
layer->getBE().onLayerDisplayed(presentFence);
}
}
@@ -2521,7 +2560,7 @@
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
- const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface,
+ const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
creationArgs.sequenceId = state.sequenceId;
@@ -2582,8 +2621,8 @@
defaultColorMode = ColorMode::SRGB;
defaultDataSpace = Dataspace::V0_SRGB;
}
- setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC);
+ display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
+ RenderIntent::COLORIMETRIC);
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
@@ -2620,7 +2659,7 @@
// in drawing state but not in current state
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
- display->disconnect(getHwComposer());
+ display->disconnect();
}
if (internalDisplayId && internalDisplayId == draw[i].displayId) {
if (mUseScheduler) {
@@ -2650,7 +2689,7 @@
// from the drawing state, so that it get re-added
// below.
if (const auto display = getDisplayDeviceLocked(displayToken)) {
- display->disconnect(getHwComposer());
+ display->disconnect();
}
mDisplays.erase(displayToken);
mDrawingState.displays.removeItemsAt(i);
@@ -2681,7 +2720,7 @@
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
const DisplayDeviceState& state(curr[i]);
- sp<DisplaySurface> dispSurface;
+ sp<compositionengine::DisplaySurface> dispSurface;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
@@ -2840,7 +2879,7 @@
// if not, pick the only display it's on.
hintDisplay = nullptr;
for (const auto& [token, display] : mDisplays) {
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ if (display->getCompositionDisplay()->belongsInOutput(layer->getLayerStack())) {
if (hintDisplay) {
hintDisplay = nullptr;
break;
@@ -2923,8 +2962,7 @@
if (layer->hasInput()) {
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- inputHandles.add(layer->fillInputInfo(
- layer->computeScreenBounds(false /* reduceTransparentRegion */)));
+ inputHandles.add(layer->fillInputInfo());
}
});
mInputFlinger->setInputWindows(inputHandles);
@@ -3007,11 +3045,13 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& display,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& outDirtyRegion, Region& outOpaqueRegion) {
ATRACE_CALL();
ALOGV("computeVisibleRegions");
+ auto display = displayDevice->getCompositionDisplay();
+
Region aboveOpaqueLayers;
Region aboveCoveredLayers;
Region dirty;
@@ -3023,7 +3063,7 @@
const Layer::State& s(layer->getDrawingState());
// only consider the layers on the given layer stack
- if (!layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ if (!display->belongsInOutput(layer->getLayerStack())) {
return;
}
@@ -3147,9 +3187,10 @@
}
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
- for (const auto& [token, display] : mDisplays) {
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
- display->dirtyRegion.orSelf(dirty);
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ if (display->belongsInOutput(layer->getLayerStack())) {
+ display->editState().dirtyRegion.orSelf(dirty);
}
}
}
@@ -3236,30 +3277,35 @@
mGeometryInvalid = true;
}
-void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& display,
+void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
const Region& inDirtyRegion) {
+ auto display = displayDevice->getCompositionDisplay();
+
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- if (!display->getId() && inDirtyRegion.isEmpty()) {
+ if (!displayDevice->getId() && inDirtyRegion.isEmpty()) {
ALOGV("Skipping display composition");
return;
}
ALOGV("doDisplayComposition");
- if (!doComposeSurfaces(display)) return;
+ if (!doComposeSurfaces(displayDevice)) return;
// swap buffers (presentation)
- display->queueBuffer(getHwComposer());
+ display->getRenderSurface()->queueBuffer();
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& display) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) {
ALOGV("doComposeSurfaces");
- const Region bounds(display->bounds());
- const DisplayRenderArea renderArea(display);
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
const auto displayId = display->getId();
+
+ const Region bounds(displayState.bounds);
+ const DisplayRenderArea renderArea(displayDevice);
const bool hasClientComposition = getHwComposer().hasClientComposition(displayId);
ATRACE_INT("hasClientComposition", hasClientComposition);
@@ -3272,12 +3318,12 @@
if (hasClientComposition) {
ALOGV("hasClientComposition");
- sp<GraphicBuffer> buf = display->dequeueBuffer();
+ sp<GraphicBuffer> buf = display->getRenderSurface()->dequeueBuffer();
if (buf == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
- display->getDisplayName().c_str());
+ displayDevice->getDisplayName().c_str());
return false;
}
@@ -3287,17 +3333,18 @@
if (fbo->getStatus() != NO_ERROR) {
ALOGW("Binding buffer for display [%s] failed with status: %d",
- display->getDisplayName().c_str(), fbo->getStatus());
+ displayDevice->getDisplayName().c_str(), fbo->getStatus());
return false;
}
+ const auto* profile = display->getDisplayColorProfile();
Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (display->hasWideColorGamut()) {
- outputDataspace = display->getCompositionDataSpace();
+ if (profile->hasWideColorGamut()) {
+ outputDataspace = displayState.dataspace;
}
getRenderEngine().setOutputDataSpace(outputDataspace);
getRenderEngine().setDisplayMaxLuminance(
- display->getHdrCapabilities().getDesiredMaxLuminance());
+ profile->getHdrCapabilities().getDesiredMaxLuminance());
const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
const bool skipClientColorTransform =
@@ -3311,7 +3358,7 @@
colorMatrix = mDrawingState.colorMatrix;
}
- display->setViewportAndProjection();
+ display->getRenderSurface()->setViewportAndProjection();
// Never touch the framebuffer if we don't have any framebuffer layers
if (hasDeviceComposition) {
@@ -3325,10 +3372,10 @@
// we start with the whole screen area and remove the scissor part
// we're left with the letterbox region
// (common case is that letterbox ends-up being empty)
- const Region letterbox = bounds.subtract(display->getScissor());
+ const Region letterbox = bounds.subtract(displayState.scissor);
// compute the area to clear
- const Region region = display->undefinedRegion.merge(letterbox);
+ const Region region = displayState.undefinedRegion.merge(letterbox);
// screen is already cleared here
if (!region.isEmpty()) {
@@ -3337,8 +3384,8 @@
}
}
- const Rect& bounds = display->getBounds();
- const Rect& scissor = display->getScissor();
+ const Rect& bounds = displayState.bounds;
+ const Rect& scissor = displayState.scissor;
if (scissor != bounds) {
// scissor doesn't match the screen's dimensions, so we
// need to clear everything outside of it and enable
@@ -3354,9 +3401,9 @@
*/
ALOGV("Rendering client layers");
- const ui::Transform& displayTransform = display->getTransform();
+ const ui::Transform& displayTransform = displayState.transform;
bool firstLayer = true;
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
const Region clip(bounds.intersect(
displayTransform.transform(layer->visibleRegion)));
ALOGV("Layer: %s", layer->getName().string());
@@ -3405,7 +3452,7 @@
if (hasClientComposition) {
getRenderEngine().setColorTransform(mat4());
getRenderEngine().disableScissor();
- display->finishBuffer();
+ display->getRenderSurface()->finishBuffer();
// Clear out error flags here so that we don't wait until next
// composition to log.
getRenderEngine().checkErrors();
@@ -3435,9 +3482,11 @@
}
if (parent == nullptr && addToCurrentState) {
mCurrentState.layersSortedByZ.add(lbc);
- } else if (parent == nullptr || parent->isRemovedFromCurrentState()) {
- ALOGE("addClientLayer called with a removed parent");
- lbc->onRemovedFromCurrentState();
+ } else if (parent == nullptr) {
+ lbc->onRemovedFromCurrentState();
+ } else if (parent->isRemovedFromCurrentState()) {
+ parent->addChild(lbc);
+ lbc->onRemovedFromCurrentState();
} else {
parent->addChild(lbc);
}
@@ -3488,8 +3537,8 @@
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
- const auto& [states, displays, flags] = transactionQueue.front();
- if (composerStateContainsUnsignaledFences(states)) {
+ const auto& [states, displays, flags, desiredPresentTime] = transactionQueue.front();
+ if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
break;
}
applyTransactionState(states, displays, flags, mInputWindowCommands);
@@ -3523,23 +3572,33 @@
return false;
}
-bool SurfaceFlinger::composerStateContainsUnsignaledFences(const Vector<ComposerState>& states) {
+bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ const Vector<ComposerState>& states) {
+ const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
+ // Do not present if the desiredPresentTime has not passed unless it is more than one second
+ // in the future. We ignore timestamps more than 1 second in the future for stability reasons.
+ if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
+ desiredPresentTime < expectedPresentTime + s2ns(1)) {
+ return false;
+ }
+
for (const ComposerState& state : states) {
const layer_state_t& s = state.state;
if (!(s.what & layer_state_t::eAcquireFenceChanged)) {
continue;
}
if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
- return true;
+ return false;
}
}
- return false;
+ return true;
}
void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands) {
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) {
ATRACE_CALL();
Mutex::Autolock _l(mStateLock);
@@ -3549,8 +3608,8 @@
// If its TransactionQueue already has a pending TransactionState or if it is pending
if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
- composerStateContainsUnsignaledFences(states)) {
- mTransactionQueues[applyToken].emplace(states, displays, flags);
+ !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+ mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime);
setTransactionFlags(eTransactionNeeded);
return;
}
@@ -3912,6 +3971,11 @@
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
}
+ if (what & layer_state_t::eCachedBufferChanged) {
+ sp<GraphicBuffer> buffer =
+ mBufferStateLayerCache.get(s.cachedBuffer.token, s.cachedBuffer.bufferId);
+ if (layer->setBuffer(buffer)) flags |= eTraversalNeeded;
+ }
if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
// Do not put anything that updates layer state or modifies flags after
// setTransactionCompletedListener
@@ -4120,8 +4184,11 @@
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
- const auto displayToken = getInternalDisplayToken();
- if (!displayToken) return;
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display) return;
+
+ const sp<IBinder> token = display->getDisplayToken().promote();
+ LOG_ALWAYS_FATAL_IF(token == nullptr);
// reset screen orientation and use primary layer stack
Vector<ComposerState> state;
@@ -4129,7 +4196,7 @@
DisplayState d;
d.what = DisplayState::eDisplayProjectionChanged |
DisplayState::eLayerStackChanged;
- d.token = displayToken;
+ d.token = token;
d.layerStack = 0;
d.orientation = DisplayState::eOrientationDefault;
d.frame.makeInvalid();
@@ -4137,26 +4204,23 @@
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0, nullptr, mInputWindowCommands);
-
- const auto display = getDisplayDevice(displayToken);
- if (!display) return;
+ setTransactionState(state, displays, 0, nullptr, mInputWindowCommands, -1);
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
- const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
- const nsecs_t period = activeConfig->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(period);
+ const nsecs_t vsyncPeriod = getVsyncPeriod();
+ mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+ DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
setCompositorTimingSnapped(stats, 0);
}
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
- postMessageAsync(new LambdaMessage([this] { onInitializeDisplays(); }));
+ postMessageAsync(
+ new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
@@ -4190,7 +4254,7 @@
} else {
mEventThread->onScreenAcquired();
}
- resyncToHardwareVsync(true);
+ resyncToHardwareVsync(true, getVsyncPeriod());
}
mVisibleRegionsDirty = true;
@@ -4235,7 +4299,7 @@
} else {
mEventThread->onScreenAcquired();
}
- resyncToHardwareVsync(true);
+ resyncToHardwareVsync(true, getVsyncPeriod());
}
} else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
// Leave display going to doze
@@ -4265,7 +4329,7 @@
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- postMessageSync(new LambdaMessage([&] {
+ postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
const auto display = getDisplayDevice(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4438,12 +4502,7 @@
index++;
}
- if (const auto displayId = getInternalDisplayId();
- displayId && getHwComposer().isConnected(*displayId)) {
- const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- const nsecs_t period = activeConfig->getVsyncPeriod();
- StringAppendF(&result, "%" PRId64 "\n", period);
- }
+ StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriod());
if (name.isEmpty()) {
mAnimFrameTracker.dumpStats(result);
@@ -4639,7 +4698,7 @@
StringAppendF(&result, " %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
- ColorMode currentMode = display->getActiveColorMode();
+ ColorMode currentMode = display->getCompositionDisplay()->getState().colorMode;
StringAppendF(&result, " Current color mode: %s (%d)\n",
decodeColorMode(currentMode).c_str(), currentMode);
}
@@ -4675,18 +4734,21 @@
return layersProto;
}
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& display) const {
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& displayDevice) const {
LayersProto layersProto;
SizeProto* resolution = layersProto.mutable_resolution();
- resolution->set_w(display.getWidth());
- resolution->set_h(display.getHeight());
+ resolution->set_w(displayDevice.getWidth());
+ resolution->set_h(displayDevice.getHeight());
- layersProto.set_color_mode(decodeColorMode(display.getActiveColorMode()));
- layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
- layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
+ auto display = displayDevice.getCompositionDisplay();
+ const auto& displayState = display->getState();
- const auto displayId = display.getId();
+ layersProto.set_color_mode(decodeColorMode(displayState.colorMode));
+ layersProto.set_color_transform(decodeColorTransform(displayState.colorTransform));
+ layersProto.set_global_transform(displayState.orientation);
+
+ const auto displayId = displayDevice.getId();
LOG_ALWAYS_FATAL_IF(!displayId);
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
@@ -4744,22 +4806,16 @@
const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
- if (const auto displayId = getInternalDisplayId();
- displayId && getHwComposer().isConnected(*displayId)) {
- const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- StringAppendF(&result,
- "Display %s: 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)",
- to_string(*displayId).c_str(), vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
- appEarlyOffset, sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
- dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
- }
- result.append("\n");
+ StringAppendF(&result,
+ "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)\n",
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset, sfEarlyOffset,
+ appEarlyGlOffset, sfEarlyGlOffset, dispSyncPresentTimeOffset, getVsyncPeriod());
// Dump static screen stats
result.append("\n");
@@ -4813,7 +4869,8 @@
getRenderEngine().dump(result);
if (const auto display = getDefaultDisplayDeviceLocked()) {
- display->undefinedRegion.dump(result, "undefinedRegion");
+ display->getCompositionDisplay()->getState().undefinedRegion.dump(result,
+ "undefinedRegion");
StringAppendF(&result, " orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
display->isPoweredOn());
}
@@ -5004,7 +5061,10 @@
case SET_TRANSACTION_STATE:
case CREATE_CONNECTION:
case GET_COLOR_MANAGEMENT:
- case GET_COMPOSITION_PREFERENCE: {
+ case GET_COMPOSITION_PREFERENCE:
+ case GET_PROTECTED_CONTENT_SUPPORT:
+ case CACHE_BUFFER:
+ case UNCACHE_BUFFER: {
return OK;
}
case CAPTURE_LAYERS:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index eb7127e..499ebcd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -17,63 +17,59 @@
#ifndef ANDROID_SURFACE_FLINGER_H
#define ANDROID_SURFACE_FLINGER_H
-#include <memory>
-#include <stdint.h>
#include <sys/types.h>
/*
* NOTE: Make sure this file doesn't include anything from <gl/ > or <gl2/ >
*/
-#include <cutils/compiler.h>
+#include <android-base/thread_annotations.h>
#include <cutils/atomic.h>
-
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/SortedVector.h>
-#include <utils/threads.h>
-#include <utils/Trace.h>
-
-#include <ui/FenceTime.h>
-#include <ui/PixelFormat.h>
-#include <math/mat4.h>
-
+#include <cutils/compiler.h>
+#include <gui/BufferQueue.h>
#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
-
#include <gui/OccupancyTracker.h>
-#include <gui/BufferQueue.h>
-
#include <hardware/hwcomposer_defs.h>
-
+#include <layerproto/LayerProtoHeader.h>
+#include <math/mat4.h>
#include <serviceutils/PriorityDumper.h>
-
#include <system/graphics.h>
+#include <ui/FenceTime.h>
+#include <ui/PixelFormat.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+#include <utils/threads.h>
#include "Barrier.h"
+#include "BufferStateLayerCache.h"
#include "DisplayDevice.h"
+#include "DisplayHardware/HWC2.h"
+#include "DisplayHardware/HWComposer.h"
+#include "Effects/Daltonizer.h"
#include "FrameTracker.h"
#include "LayerBE.h"
#include "LayerStats.h"
#include "LayerVector.h"
-#include "SurfaceFlingerFactory.h"
-#include "SurfaceInterceptor.h"
-#include "SurfaceTracing.h"
-#include "TransactionCompletedThread.h"
-
-#include "DisplayHardware/HWC2.h"
-#include "DisplayHardware/HWComposer.h"
-#include "Effects/Daltonizer.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/VSyncModulator.h"
+#include "SurfaceFlingerFactory.h"
+#include "SurfaceInterceptor.h"
+#include "SurfaceTracing.h"
+#include "TransactionCompletedThread.h"
+#include <atomic>
+#include <cstdint>
#include <map>
+#include <memory>
#include <mutex>
#include <queue>
#include <set>
@@ -82,8 +78,6 @@
#include <unordered_map>
#include <utility>
-#include <layerproto/LayerProtoHeader.h>
-
using namespace android::surfaceflinger;
namespace android {
@@ -106,6 +100,10 @@
class VSyncSource;
struct CompositionInfo;
+namespace compositionengine {
+class DisplaySurface;
+} // namespace compositionengine
+
namespace impl {
class EventThread;
} // namespace impl
@@ -148,10 +146,6 @@
const std::string mHwcServiceName; // "default" for real use, something else for testing.
- // constant members (no synchronization needed for access)
- EGLContext mEGLContext;
- EGLDisplay mEGLDisplay;
-
FenceTimeline mGlCompositionDoneTimeline;
FenceTimeline mDisplayTimeline;
@@ -412,77 +406,79 @@
/* ------------------------------------------------------------------------
* IBinder interface
*/
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
- virtual status_t dump(int fd, const Vector<String16>& args) { return priorityDump(fd, args); }
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
+ status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
/* ------------------------------------------------------------------------
* ISurfaceComposer interface
*/
- virtual sp<ISurfaceComposerClient> createConnection();
- virtual sp<IBinder> createDisplay(const String8& displayName, bool secure);
- virtual void destroyDisplay(const sp<IBinder>& displayToken);
- virtual sp<IBinder> getBuiltInDisplay(int32_t id);
- virtual void setTransactionState(const Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands);
- virtual void bootFinished();
- virtual bool authenticateSurfaceTexture(
- const sp<IGraphicBufferProducer>& bufferProducer) const;
- virtual status_t getSupportedFrameTimestamps(
- std::vector<FrameEvent>* outSupported) const;
- virtual sp<IDisplayEventConnection> createDisplayEventConnection(
- ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
- virtual status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
- 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 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);
- virtual int getActiveConfig(const sp<IBinder>& displayToken);
- virtual status_t getDisplayColorModes(const sp<IBinder>& displayToken,
- Vector<ui::ColorMode>* configs);
- virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken);
- virtual status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode);
- virtual void setPowerMode(const sp<IBinder>& displayToken, int mode);
- virtual status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
- virtual status_t clearAnimationFrameStats();
- virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
- virtual status_t getHdrCapabilities(const sp<IBinder>& displayToken,
- HdrCapabilities* outCapabilities) const;
- virtual status_t enableVSyncInjections(bool enable);
- virtual status_t injectVSync(nsecs_t when);
- virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
- virtual status_t getColorManagement(bool* outGetColorManagement) const;
+ sp<ISurfaceComposerClient> createConnection() override;
+ sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
+ void destroyDisplay(const sp<IBinder>& displayToken) override;
+ sp<IBinder> getBuiltInDisplay(int32_t id) override;
+ void setTransactionState(const Vector<ComposerState>& state,
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) override;
+ void bootFinished() override;
+ bool authenticateSurfaceTexture(
+ const sp<IGraphicBufferProducer>& bufferProducer) const override;
+ status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override;
+ sp<IDisplayEventConnection> createDisplayEventConnection(
+ ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override;
+ status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
+ const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ bool useIdentityTransform, ISurfaceComposer::Rotation rotation) override;
+ status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
+ const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
+ const Rect& sourceCrop, float frameScale, bool childrenOnly) override;
+ status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
+ status_t getDisplayConfigs(const sp<IBinder>& displayToken,
+ Vector<DisplayInfo>* configs) override;
+ int getActiveConfig(const sp<IBinder>& displayToken) override;
+ status_t getDisplayColorModes(const sp<IBinder>& displayToken,
+ Vector<ui::ColorMode>* configs) override;
+ ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken) override;
+ status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
+ void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
+ status_t setActiveConfig(const sp<IBinder>& displayToken, int id) override;
+ status_t clearAnimationFrameStats() override;
+ status_t getAnimationFrameStats(FrameStats* outStats) const override;
+ status_t getHdrCapabilities(const sp<IBinder>& displayToken,
+ HdrCapabilities* outCapabilities) const override;
+ status_t enableVSyncInjections(bool enable) override;
+ status_t injectVSync(nsecs_t when) override;
+ status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const override;
+ status_t getColorManagement(bool* outGetColorManagement) const override;
status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
ui::Dataspace* outWideColorGamutDataspace,
ui::PixelFormat* outWideColorGamutPixelFormat) const override;
- virtual status_t getDisplayedContentSamplingAttributes(
- const sp<IBinder>& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace,
- uint8_t* outComponentMask) const override;
- virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
- uint8_t componentMask,
- uint64_t maxFrames) const override;
- virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
- uint64_t timestamp,
- DisplayedFrameStats* outStats) const override;
+ status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
+ ui::PixelFormat* outFormat,
+ ui::Dataspace* outDataspace,
+ uint8_t* outComponentMask) const override;
+ status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+ uint8_t componentMask,
+ uint64_t maxFrames) const override;
+ status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+ uint64_t timestamp,
+ DisplayedFrameStats* outStats) const override;
+ status_t getProtectedContentSupport(bool* outSupported) const override;
+ status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
+ int32_t* outBufferId) override;
+ status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) override;
/* ------------------------------------------------------------------------
* DeathRecipient interface
*/
- virtual void binderDied(const wp<IBinder>& who);
+ void binderDied(const wp<IBinder>& who) override;
/* ------------------------------------------------------------------------
* RefBase interface
*/
- virtual void onFirstRef();
+ void onFirstRef() override;
/* ------------------------------------------------------------------------
* HWC2::ComposerCallback / HWComposer::EventHandler interface
@@ -504,17 +500,13 @@
void signalRefresh();
// called on the main thread in response to initializeDisplays()
- void onInitializeDisplays();
+ void onInitializeDisplays() REQUIRES(mStateLock);
// setActiveConfigInternal() posted on a main thread for async execution
status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode);
// called on the main thread in response to setActiveConfig()
- void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode);
+ void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
// called on the main thread in response to setPowerMode()
- void setPowerModeInternal(const sp<DisplayDevice>& display, int mode);
-
- // Called on the main thread in response to setActiveColorMode()
- void setActiveColorModeInternal(const sp<DisplayDevice>& display, ui::ColorMode colorMode,
- ui::Dataspace dataSpace, ui::RenderIntent renderIntent);
+ void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -552,7 +544,8 @@
void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction();
bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
- bool composerStateContainsUnsignaledFences(const Vector<ComposerState>& states);
+ bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ const Vector<ComposerState>& states);
uint32_t setClientStateLocked(const ComposerState& composerState);
uint32_t setDisplayStateLocked(const DisplayState& s);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands);
@@ -706,6 +699,7 @@
void preComposition();
void postComposition();
+ void getCompositorTiming(CompositorTiming* compositorTiming);
void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime);
void setCompositorTimingSnapped(const DisplayStatInfo& stats,
@@ -749,29 +743,49 @@
/* ------------------------------------------------------------------------
* Display management
*/
- sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId,
- const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface,
- const sp<IGraphicBufferProducer>& producer);
+ sp<DisplayDevice> setupNewDisplayDeviceInternal(
+ const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
+ const DisplayDeviceState& state,
+ const sp<compositionengine::DisplaySurface>& dispSurface,
+ const sp<IGraphicBufferProducer>& producer);
void processDisplayChangesLocked();
void processDisplayHotplugEventsLocked();
/* ------------------------------------------------------------------------
* VSync
*/
+ nsecs_t getVsyncPeriod() const REQUIRES(mStateLock);
void enableHardwareVsync();
- void resyncToHardwareVsync(bool makeAvailable);
+ void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
void disableHardwareVsync(bool makeUnavailable);
-public:
- void resyncWithRateLimit();
- void getCompositorTiming(CompositorTiming* compositorTiming);
-private:
// Sets the refresh rate to newFps by switching active configs, if they are available for
// the desired refresh rate.
void setRefreshRateTo(float newFps);
+ using GetVsyncPeriod = std::function<nsecs_t()>;
+
+ // Stores per-display state about VSYNC.
+ struct VsyncState {
+ explicit VsyncState(SurfaceFlinger& flinger) : flinger(flinger) {}
+
+ void resync(const GetVsyncPeriod&);
+
+ SurfaceFlinger& flinger;
+ std::atomic<nsecs_t> lastResyncTime = 0;
+ };
+
+ const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
+
+ auto makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
+ std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
+ return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
+ if (const auto vsync = ptr.lock()) {
+ vsync->resync(getVsyncPeriod);
+ }
+ };
+ }
+
/* ------------------------------------------------------------------------
* Debugging & dumpsys
*/
@@ -817,9 +831,11 @@
}
void listLayersLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
- void dumpStatsLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
+ void dumpStatsLocked(const Vector<String16>& args, size_t& index, std::string& result) const
+ REQUIRES(mStateLock);
void clearStatsLocked(const Vector<String16>& args, size_t& index, std::string& result);
- void dumpAllLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
+ void dumpAllLocked(const Vector<String16>& args, size_t& index, std::string& result) const
+ REQUIRES(mStateLock);
bool startDdmConnection();
void appendSfConfigString(std::string& result) const;
@@ -979,12 +995,17 @@
};
struct TransactionState {
TransactionState(const Vector<ComposerState>& composerStates,
- const Vector<DisplayState>& displayStates, uint32_t transactionFlags)
- : states(composerStates), displays(displayStates), flags(transactionFlags) {}
+ const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
+ int64_t desiredPresentTime)
+ : states(composerStates),
+ displays(displayStates),
+ flags(transactionFlags),
+ time(desiredPresentTime) {}
Vector<ComposerState> states;
Vector<DisplayState> displays;
uint32_t flags;
+ int64_t time;
};
std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IBinderHash> mTransactionQueues;
@@ -1024,6 +1045,8 @@
sp<IInputFlinger> mInputFlinger;
InputWindowCommands mInputWindowCommands;
+
+ BufferStateLayerCache mBufferStateLayerCache;
};
}; // namespace android
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index a1a8692..d2b7fe0 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -62,8 +62,7 @@
mThread = std::thread(&TransactionCompletedThread::threadMain, this);
}
-void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
- const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::registerPendingCallbackHandle(const sp<CallbackHandle>& handle) {
std::lock_guard lock(mMutex);
sp<IBinder> listener = IInterface::asBinder(handle->listener);
@@ -72,19 +71,10 @@
mPendingTransactions[listener][callbackIds]++;
}
-void TransactionCompletedThread::addLatchedCallbackHandles(
- const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
- const sp<Fence>& previousReleaseFence) {
+void TransactionCompletedThread::addPresentedCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles) {
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;
@@ -101,17 +91,16 @@
ALOGE("there are more latched callbacks than there were registered callbacks");
}
- addCallbackHandle(handle, latchTime);
+ addCallbackHandle(handle);
}
}
-void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle) {
std::lock_guard lock(mMutex);
addCallbackHandle(handle);
}
-void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
- nsecs_t latchTime) {
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
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
@@ -128,9 +117,9 @@
listenerStats.listener = handle->listener;
auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
- transactionStats.latchTime = latchTime;
+ transactionStats.latchTime = handle->latchTime;
transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
- handle->releasePreviousBuffer);
+ handle->previousReleaseFence);
}
void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
@@ -151,15 +140,6 @@
while (mKeepRunning) {
mConditionVariable.wait(mMutex);
- // 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()) {
@@ -200,7 +180,6 @@
if (mPresentFence) {
mPresentFence.clear();
- mPreviousReleaseFences.clear();
}
}
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 1612f69..f49306d 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -40,7 +40,9 @@
sp<IBinder> surfaceControl;
bool releasePreviousBuffer = false;
+ sp<Fence> previousReleaseFence;
nsecs_t acquireTime = -1;
+ nsecs_t latchTime = -1;
};
class TransactionCompletedThread {
@@ -54,14 +56,13 @@
// 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);
+ void registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
+ // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
+ void addPresentedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
// 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 addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
void addPresentFence(const sp<Fence>& presentFence);
@@ -70,8 +71,7 @@
private:
void threadMain();
- void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
- REQUIRES(mMutex);
+ void addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
class ThreadDeathRecipient : public IBinder::DeathRecipient {
public:
@@ -110,7 +110,6 @@
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 92ae87b..3ad6ec3 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -21,13 +21,14 @@
#include <android/frameworks/displayservice/1.0/IDisplayService.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
-#include <cutils/sched_policy.h>
#include <displayservice/DisplayService.h>
#include <hidl/LegacySupport.h>
+#include <processgroup/sched_policy.h>
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
@@ -41,10 +42,14 @@
return OK;
}
- using android::hardware::graphics::allocator::V2_0::IAllocator;
+ status_t result = hardware::registerPassthroughServiceImplementation<
+ android::hardware::graphics::allocator::V3_0::IAllocator>();
+ if (result == OK) {
+ return OK;
+ }
- status_t result =
- hardware::registerPassthroughServiceImplementation<IAllocator>();
+ result = hardware::registerPassthroughServiceImplementation<
+ android::hardware::graphics::allocator::V2_0::IAllocator>();
if (result != OK) {
ALOGE("could not start graphics allocator service");
return result;
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index aea602b..5bec502 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -2,6 +2,7 @@
class core animation
user system
group graphics drmrpc readproc
+ updatable
onrestart restart zygote
writepid /dev/stune/foreground/tasks
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ef6999d..216532a 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2323,6 +2323,143 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
+TEST_F(LayerTransactionTest, CacheBuffer_BufferState) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ ASSERT_GE(bufferId, 0);
+
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+}
+
+TEST_F(LayerTransactionTest, CacheBuffers_BufferState) {
+ std::vector<int32_t> bufferIds;
+ int32_t bufferCount = 20;
+
+ for (int i = 0; i < bufferCount; i++) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ if (bufferId < 0) {
+ EXPECT_GE(bufferId, 0);
+ break;
+ }
+ bufferIds.push_back(bufferId);
+ }
+
+ for (int32_t bufferId : bufferIds) {
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+ }
+}
+
+TEST_F(LayerTransactionTest, CacheBufferInvalid_BufferState) {
+ sp<GraphicBuffer> buffer = nullptr;
+
+ int32_t bufferId = -1;
+ ASSERT_NE(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ ASSERT_LT(bufferId, 0);
+}
+
+TEST_F(LayerTransactionTest, UncacheBufferTwice_BufferState) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ ASSERT_GE(bufferId, 0);
+
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+ mClient->uncacheBuffer(bufferId);
+}
+
+TEST_F(LayerTransactionTest, UncacheBufferInvalidId_BufferState) {
+ mClient->uncacheBuffer(-1);
+ mClient->uncacheBuffer(0);
+ mClient->uncacheBuffer(1);
+ mClient->uncacheBuffer(5);
+ mClient->uncacheBuffer(1000);
+}
+
+TEST_F(LayerTransactionTest, SetCachedBuffer_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ ASSERT_GE(bufferId, 0);
+
+ Transaction().setCachedBuffer(layer, bufferId).apply();
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+}
+
+TEST_F(LayerTransactionTest, SetCachedBufferDelayed_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> cachedBuffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(cachedBuffer, &bufferId));
+ ASSERT_GE(bufferId, 0);
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::BLUE);
+ Transaction().setBuffer(layer, buffer).apply();
+ {
+ SCOPED_TRACE("Uncached buffer");
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ fillGraphicBufferColor(cachedBuffer, Rect(0, 0, 32, 32), Color::RED);
+ Transaction().setCachedBuffer(layer, bufferId).apply();
+ {
+ SCOPED_TRACE("Cached buffer");
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+}
+
class ColorTransformHelper {
public:
static void DegammaColorSingle(half& s) {
@@ -2542,6 +2679,7 @@
enum PreviousBuffer {
NOT_RELEASED = 0,
RELEASED,
+ UNKNOWN,
};
void reset() {
@@ -2567,11 +2705,23 @@
}
}
+ void addExpectedPresentTime(nsecs_t expectedPresentTime) {
+ mExpectedPresentTime = expectedPresentTime;
+ }
+
void verifyTransactionStats(const TransactionStats& transactionStats) const {
const auto& [latchTime, presentFence, surfaceStats] = transactionStats;
if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
ASSERT_GE(latchTime, 0) << "bad latch time";
ASSERT_NE(presentFence, nullptr);
+ if (mExpectedPresentTime >= 0) {
+ ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
+ ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
+ // if the panel is running at 30 hz, at the worst case, our expected time just
+ // misses vsync and we have to wait another 33.3ms
+ ASSERT_LE(presentFence->getSignalTime(),
+ mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
+ }
} else {
ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
@@ -2596,14 +2746,19 @@
: mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+ const auto& [surfaceControl, acquireTime, previousReleaseFence] = 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";
+
+ if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
+ ASSERT_NE(previousReleaseFence, nullptr)
+ << "failed to set release prev buffer fence";
+ } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
+ ASSERT_EQ(previousReleaseFence, nullptr)
+ << "should not have set released prev buffer fence";
+ }
}
private:
@@ -2617,6 +2772,7 @@
}
};
ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ nsecs_t mExpectedPresentTime = -1;
std::unordered_map<sp<IBinder>, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults;
};
@@ -3177,13 +3333,11 @@
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::ACQUIRED, previousBufferResult);
- previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::UNKNOWN);
int err = fillTransaction(transaction, &callback, layer);
if (err) {
@@ -3268,6 +3422,143 @@
EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
}
+TEST_F(LayerCallbackTest, DesiredPresentTime) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(time);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms after the first frame
+ time += (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ expected2.addExpectedPresentTime(time);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms before the previous frame
+ time -= (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the past
+ nsecs_t time = systemTime() - (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(systemTime());
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
class LayerUpdateTest : public LayerTransactionTest {
protected:
virtual void SetUp() {
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index a5b522e..a2c0611 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -11,6 +11,7 @@
shared_libs: [
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
"android.hardware.power@1.3",
"libbase",
"libbinder",
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f63c911..ad31a40 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -46,7 +46,6 @@
"SchedulerUtilsTest.cpp",
"TimeStatsTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
- "mock/DisplayHardware/MockDisplaySurface.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
"mock/gui/MockGraphicBufferConsumer.cpp",
"mock/gui/MockGraphicBufferProducer.cpp",
@@ -63,7 +62,6 @@
"libcompositionengine",
"libcompositionengine_mocks",
"librenderengine_mocks",
-
],
header_libs: [
"libsurfaceflinger_headers",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e417350..e972785 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
+#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <gui/IProducerListener.h>
@@ -33,7 +34,6 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/DisplayHardware/MockDisplaySurface.h"
#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
@@ -144,7 +144,8 @@
TestableSurfaceFlinger mFlinger;
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
- sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ new compositionengine::mock::DisplaySurface();
mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
@@ -326,11 +327,14 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
+ EXPECT_CALL(*test->mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
+ .Times(1);
}
static void setupRECompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+ EXPECT_CALL(*test->mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
.Times(1);
EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
.WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index ff84a62..8201704 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -19,6 +19,9 @@
#include <type_traits>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -28,7 +31,6 @@
#include "DisplayIdentificationTest.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/DisplayHardware/MockDisplaySurface.h"
#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
@@ -1152,8 +1154,10 @@
EXPECT_CALL(*mNativeWindow, perform(30)).Times(1);
auto displayDevice = mInjector.inject();
- displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
- &mOutColorMode, &mOutRenderIntent);
+ displayDevice->getCompositionDisplay()
+ ->getDisplayColorProfile()
+ ->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
+ &mOutColorMode, &mOutRenderIntent);
}
ui::Dataspace mOutDataspace;
@@ -1227,7 +1231,8 @@
template <typename Case>
void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
const sp<BBinder> displayToken = new BBinder();
- const sp<mock::DisplaySurface> displaySurface = new mock::DisplaySurface();
+ const sp<compositionengine::mock::DisplaySurface> displaySurface =
+ new compositionengine::mock::DisplaySurface();
const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
// --------------------------------------------------------------------
@@ -1970,7 +1975,7 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new mock::DisplaySurface();
+ auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
@@ -2014,7 +2019,7 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new mock::DisplaySurface();
+ auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 2d26bb3..c18068f 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -47,10 +47,11 @@
class EventThreadTest : public testing::Test {
protected:
- class MockEventThreadConnection : public android::EventThreadConnection {
+ class MockEventThreadConnection : public EventThreadConnection {
public:
- explicit MockEventThreadConnection(android::impl::EventThread* eventThread)
- : android::EventThreadConnection(eventThread) {}
+ MockEventThreadConnection(android::impl::EventThread* eventThread,
+ ResyncCallback&& resyncCallback)
+ : EventThreadConnection(eventThread, std::move(resyncCallback)) {}
MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
};
@@ -113,14 +114,14 @@
void EventThreadTest::createThread() {
mThread =
std::make_unique<android::impl::EventThread>(&mVSyncSource,
- mResyncCallRecorder.getInvocable(),
mInterceptVSyncCallRecorder.getInvocable(),
"unit-test-event-thread");
}
sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
ConnectionEventRecorder& recorder) {
- sp<MockEventThreadConnection> connection = new MockEventThreadConnection(mThread.get());
+ sp<MockEventThreadConnection> connection =
+ new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable());
EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
return connection;
}
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4253ad8..3dd5143 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -8,12 +8,9 @@
#include <mutex>
-#include "AsyncCallRecorder.h"
-#include "Scheduler/DispSync.h"
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/Scheduler.h"
-#include "mock/MockDispSync.h"
#include "mock/MockEventThread.h"
using testing::_;
@@ -26,7 +23,7 @@
class MockEventThreadConnection : public android::EventThreadConnection {
public:
explicit MockEventThreadConnection(EventThread* eventThread)
- : EventThreadConnection(eventThread) {}
+ : EventThreadConnection(eventThread, ResyncCallback()) {}
~MockEventThreadConnection() = default;
MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -46,7 +43,6 @@
std::unique_ptr<EventThread> makeEventThread(
const std::string& /* connectionName */, DispSync* /* dispSync */,
nsecs_t /* phaseOffsetNs */,
- impl::EventThread::ResyncWithRateLimitCallback /* resyncCallback */,
impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
return std::move(mEventThread);
}
@@ -61,13 +57,9 @@
~SchedulerTest() override;
sp<Scheduler::ConnectionHandle> mConnectionHandle;
- mock::DispSync* mPrimaryDispSync = new mock::DispSync();
mock::EventThread* mEventThread;
std::unique_ptr<MockScheduler> mScheduler;
sp<MockEventThreadConnection> mEventThreadConnection;
-
- AsyncCallRecorder<void (*)()> mResyncCallRecorder;
- AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
};
SchedulerTest::SchedulerTest() {
@@ -84,12 +76,12 @@
// createConnection call to scheduler makes a createEventConnection call to EventThread. Make
// sure that call gets executed and returns an EventThread::Connection object.
- EXPECT_CALL(*mEventThread, createEventConnection())
+ EXPECT_CALL(*mEventThread, createEventConnection(_))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle =
- mScheduler->createConnection("appConnection", 16, mResyncCallRecorder.getInvocable(),
- mInterceptVSyncCallRecorder.getInvocable());
+ mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
+ impl::EventThread::InterceptVSyncsCallback());
+ EXPECT_TRUE(mConnectionHandle != nullptr);
}
SchedulerTest::~SchedulerTest() {
@@ -102,17 +94,13 @@
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(SchedulerTest, canCreateAndDestroyTest) {
- EXPECT_FALSE(mResyncCallRecorder.waitForCall().has_value());
- EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall().has_value());
- EXPECT_EQ(0, mConnectionHandle->id);
-}
TEST_F(SchedulerTest, testNullPtr) {
// Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
// exceptions, just gracefully continues.
sp<IDisplayEventConnection> returnedValue;
- ASSERT_NO_FATAL_FAILURE(returnedValue = mScheduler->createDisplayEventConnection(nullptr));
+ ASSERT_NO_FATAL_FAILURE(
+ returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback()));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
@@ -132,8 +120,9 @@
sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
sp<IDisplayEventConnection> returnedValue;
- ASSERT_NO_FATAL_FAILURE(returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle));
+ ASSERT_NO_FATAL_FAILURE(
+ returnedValue =
+ mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback()));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
@@ -160,8 +149,9 @@
TEST_F(SchedulerTest, validConnectionHandle) {
sp<IDisplayEventConnection> returnedValue;
- ASSERT_NO_FATAL_FAILURE(returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle));
+ ASSERT_NO_FATAL_FAILURE(
+ returnedValue =
+ mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback()));
EXPECT_TRUE(returnedValue != nullptr);
ASSERT_EQ(returnedValue, mEventThreadConnection);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9ff5e8d..687941a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -218,7 +218,7 @@
auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface,
+ const sp<compositionengine::DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface,
producer);
@@ -235,9 +235,14 @@
auto setDisplayStateLocked(const DisplayState& s) { return mFlinger->setDisplayStateLocked(s); }
- auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); }
+ // Allow reading display state without locking, as if called on the SF main thread.
+ auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->onInitializeDisplays();
+ }
- auto setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
+ // Allow reading display state without locking, as if called on the SF main thread.
+ auto setPowerModeInternal(const sp<DisplayDevice>& display,
+ int mode) NO_THREAD_SAFETY_ANALYSIS {
return mFlinger->setPowerModeInternal(display, mode);
}
@@ -487,7 +492,7 @@
return *this;
}
- auto& setDisplaySurface(const sp<DisplaySurface>& displaySurface) {
+ auto& setDisplaySurface(const sp<compositionengine::DisplaySurface>& displaySurface) {
mCreationArgs.displaySurface = displaySurface;
return *this;
}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 48d45fa..3242ef1 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,7 +28,7 @@
EventThread();
~EventThread() override;
- MOCK_CONST_METHOD0(createEventConnection, sp<EventThreadConnection>());
+ MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index 8c113e2..e22d3e8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -30,8 +30,8 @@
~MessageQueue() override;
MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
- MOCK_METHOD1(setEventThread, void(android::EventThread*));
- MOCK_METHOD1(setEventConnection, void(const sp<android::EventThreadConnection>& connection));
+ MOCK_METHOD2(setEventThread, void(android::EventThread*, ResyncCallback));
+ MOCK_METHOD1(setEventConnection, void(const sp<EventThreadConnection>& connection));
MOCK_METHOD0(waitMessage, void());
MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
MOCK_METHOD0(invalidate, void());
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 7a7e437..ba7d7f9 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -28,7 +28,6 @@
cc_library_static {
name: "libbufferhubd",
srcs: [
- "buffer_channel.cpp",
"buffer_hub.cpp",
"consumer_channel.cpp",
"consumer_queue_channel.cpp",
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
deleted file mode 100644
index 695396c..0000000
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-#include <errno.h>
-#include <private/dvr/buffer_channel.h>
-#include <private/dvr/producer_channel.h>
-
-using android::pdx::BorrowedHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-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);
- 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,
- int channel_id,
- std::shared_ptr<BufferNode> buffer_node)
- : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_node_(buffer_node) {
- client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
- if (client_state_mask_ == 0U) {
- ALOGE("BufferChannel::BufferChannel: %s", strerror(errno));
- buffer_node_ = nullptr;
- }
-}
-
-BufferChannel::~BufferChannel() {
- ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
- channel_id(), buffer_id());
- if (client_state_mask_ != 0U) {
- buffer_node_->RemoveClientsBitFromMask(client_state_mask_);
- }
- Hangup();
-}
-
-BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
- return BufferInfo(
- 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,
- /*state=*/0, /*signaled_mask=*/0, /*index=*/0);
-}
-
-void BufferChannel::HandleImpulse(Message& /*message*/) {
- ATRACE_NAME("BufferChannel::HandleImpulse");
-}
-
-bool BufferChannel::HandleMessage(Message& message) {
- ATRACE_NAME("BufferChannel::HandleMessage");
- switch (message.GetOp()) {
- case DetachedBufferRPC::Import::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Import>(
- *this, &BufferChannel::OnImport, message);
- return true;
-
- case DetachedBufferRPC::Duplicate::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Duplicate>(
- *this, &BufferChannel::OnDuplicate, message);
- return true;
-
- default:
- return false;
- }
-}
-
-Status<BufferTraits<BorrowedHandle>> BufferChannel::OnImport(
- Message& /*message*/) {
- ATRACE_NAME("BufferChannel::OnImport");
- ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.", buffer_id());
-
- BorrowedHandle ashmem_handle =
- BorrowedHandle(buffer_node_->metadata().ashmem_fd().get());
-
- // TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
- return BufferTraits<BorrowedHandle>{
- /*buffer_handle=*/buffer_node_->buffer_handle(),
- /*metadata_handle=*/ashmem_handle,
- /*id=*/buffer_id(),
- /*client_state_mask=*/client_state_mask_,
- /*metadata_size=*/buffer_node_->metadata().metadata_size(),
- /*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{}};
-}
-
-Status<RemoteChannelHandle> BufferChannel::OnDuplicate(Message& message) {
- ATRACE_NAME("BufferChannel::OnDuplicate");
- ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.", buffer_id());
-
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status.ok()) {
- ALOGE("BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
- auto channel = std::shared_ptr<BufferChannel>(
- new BufferChannel(service(), buffer_id(), channel_id, buffer_node_));
- if (!channel->IsValid()) {
- ALOGE("BufferChannel::OnDuplicate: Invalid buffer. %s", strerror(errno));
- return ErrorStatus(EINVAL);
- }
-
- const auto channel_status =
- service()->SetChannel(channel_id, std::move(channel));
- if (!channel_status) {
- // Technically, this should never fail, as we just pushed the channel. Note
- // that LOG_FATAL will be stripped out in non-debug build.
- LOG_FATAL(
- "BufferChannel::OnDuplicate: Failed to set new buffer channel: %s.",
- channel_status.GetErrorMessage().c_str());
- }
-
- return status;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index f50d292..6409265 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -10,7 +10,6 @@
#include <log/log.h>
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/bufferhub_rpc.h>
-#include <private/dvr/buffer_channel.h>
#include <private/dvr/buffer_hub.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_channel.h>
@@ -242,11 +241,6 @@
*this, &BufferHubService::OnCreateBuffer, message);
return {};
- case DetachedBufferRPC::Create::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Create>(
- *this, &BufferHubService::OnCreateDetachedBuffer, message);
- return {};
-
case BufferHubRPC::CreateProducerQueue::Opcode:
DispatchRemoteMethod<BufferHubRPC::CreateProducerQueue>(
*this, &BufferHubService::OnCreateProducerQueue, message);
@@ -288,43 +282,6 @@
}
}
-pdx::Status<void> BufferHubService::OnCreateDetachedBuffer(
- pdx::Message& message, uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format, uint64_t usage,
- size_t user_metadata_size) {
- // Use the producer channel id as the global buffer id.
- const int buffer_id = message.GetChannelId();
- ALOGD_IF(TRACE,
- "BufferHubService::OnCreateDetachedBuffer: buffer_id=%d width=%u "
- "height=%u layer_count=%u format=%u usage=%" PRIx64
- " user_metadata_size=%zu",
- buffer_id, width, height, layer_count, format, usage,
- user_metadata_size);
-
- // See if this channel is already attached to a buffer.
- if (const auto channel = message.GetChannel<BufferHubChannel>()) {
- ALOGE(
- "BufferHubService::OnCreateDetachedBuffer: Buffer already created: "
- "buffer=%d",
- buffer_id);
- return ErrorStatus(EALREADY);
- }
-
- std::unique_ptr<BufferChannel> channel =
- BufferChannel::Create(this, buffer_id, width, height, layer_count, format,
- usage, user_metadata_size);
- if (!channel) {
- ALOGE(
- "BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
- "buffer=%d.",
- buffer_id);
- return ErrorStatus(ENOMEM);
- }
-
- message.SetChannel(std::move(channel));
- return {};
-}
-
Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
pdx::Message& message, const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy) {
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
deleted file mode 100644
index 9888db6..0000000
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
-#define ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
-
-#include <pdx/channel_handle.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub.h>
-#include <private/dvr/buffer_hub_defs.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-class BufferChannel : public BufferHubChannel {
- public:
- ~BufferChannel() override;
-
- template <typename... Args>
- static std::unique_ptr<BufferChannel> Create(Args&&... args) {
- auto buffer = std::unique_ptr<BufferChannel>(
- new BufferChannel(std::forward<Args>(args)...));
- return buffer->IsValid() ? std::move(buffer) : nullptr;
- }
-
- // Returns whether the object holds a valid graphic buffer.
- bool IsValid() const {
- return buffer_node_ != nullptr && buffer_node_->IsValid();
- }
-
- // Captures buffer info for use by BufferHubService::DumpState().
- BufferInfo GetBufferInfo() const override;
-
- bool HandleMessage(pdx::Message& message) override;
- void HandleImpulse(pdx::Message& message) override;
-
- private:
-
- // Allocates a new detached buffer.
- 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);
-
- // Creates a detached buffer from an existing BufferNode. This method is used
- // in OnDuplicate method.
- BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
- std::shared_ptr<BufferNode> buffer_node);
-
- pdx::Status<BufferTraits<pdx::BorrowedHandle>> OnImport(
- pdx::Message& message);
- pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
-
- // The concrete implementation of the Buffer object.
- std::shared_ptr<BufferNode> buffer_node_ = nullptr;
-
- // The state bit of this buffer.
- uint32_t client_state_mask_ = 0U;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
index 01520fc..909d69b 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
@@ -144,11 +144,6 @@
pdx::Status<void> OnCreateBuffer(pdx::Message& message, uint32_t width,
uint32_t height, uint32_t format,
uint64_t usage, size_t meta_size_bytes);
- pdx::Status<void> OnCreateDetachedBuffer(pdx::Message& message,
- uint32_t width, uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size);
pdx::Status<QueueInfo> OnCreateProducerQueue(
pdx::Message& message, const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy);
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 409bce9..895dee0 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -7,7 +7,6 @@
#include <thread>
#include <log/log.h>
-#include <private/dvr/buffer_channel.h>
#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_channel.h>
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 258b45b..d9df204 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -15,6 +15,7 @@
"android.frameworks.vr.composer@1.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
"libbase",
"libbufferhubqueue",
"libbinder",
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 009b257..ba4cf00 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -139,12 +139,12 @@
auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
if (app_namespace &&
!android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
- std::string error_msg;
- dlhandle_ = OpenNativeLibrary(
+ char* error_msg = nullptr;
+ dlhandle_ = OpenNativeLibraryInNamespace(
app_namespace, path_.c_str(), &native_bridge_, &error_msg);
if (!dlhandle_) {
- ALOGE("failed to load layer library '%s': %s", path_.c_str(),
- error_msg.c_str());
+ ALOGE("failed to load layer library '%s': %s", path_.c_str(), error_msg);
+ android::NativeLoaderFreeErrorMessage(error_msg);
refcount_ = 0;
return false;
}
@@ -165,9 +165,10 @@
std::lock_guard<std::mutex> lock(mutex_);
if (--refcount_ == 0) {
ALOGV("closing layer library '%s'", path_.c_str());
- std::string error_msg;
+ char* error_msg = nullptr;
if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
- ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg.c_str());
+ ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg);
+ android::NativeLoaderFreeErrorMessage(error_msg);
refcount_++;
} else {
dlhandle_ = nullptr;