Merge changes from topic "deprecate-content-detection-v1"
* changes:
Move LayerHistoryV2 to LayerHistory
SF: Deprecate content detection v1
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 560459b..a8c0500 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -14,6 +14,7 @@
libs/graphicsenv/
libs/gui/
libs/input/
+ libs/nativedisplay/
libs/renderengine/
libs/ui/
libs/vr/
diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp
index ded0ed3..203d748 100644
--- a/cmds/bugreportz/bugreportz.cpp
+++ b/cmds/bugreportz/bugreportz.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include "bugreportz.h"
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -22,11 +26,6 @@
#include <string>
-#include <android-base/file.h>
-#include <android-base/strings.h>
-
-#include "bugreportz.h"
-
static constexpr char BEGIN_PREFIX[] = "BEGIN:";
static constexpr char PROGRESS_PREFIX[] = "PROGRESS:";
@@ -70,6 +69,30 @@
}
// Process final line, in case it didn't finish with newline
write_line(line, show_progress);
+ return EXIT_SUCCESS;
+}
+int bugreportz_stream(int s) {
+ while (1) {
+ char buffer[65536];
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));
+ if (bytes_read == 0) {
+ break;
+ } else if (bytes_read == -1) {
+ // EAGAIN really means time out, so change the errno.
+ if (errno == EAGAIN) {
+ errno = ETIMEDOUT;
+ }
+ printf("FAIL:Bugreport read terminated abnormally (%s)\n", strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ if (!android::base::WriteFully(android::base::borrowed_fd(STDOUT_FILENO), buffer,
+ bytes_read)) {
+ printf("Failed to write data to stdout: trying to send %zd bytes (%s)\n", bytes_read,
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
return EXIT_SUCCESS;
}
diff --git a/cmds/bugreportz/bugreportz.h b/cmds/bugreportz/bugreportz.h
index 7af289b..cdeceae 100644
--- a/cmds/bugreportz/bugreportz.h
+++ b/cmds/bugreportz/bugreportz.h
@@ -19,4 +19,8 @@
// Ownership of the socket is not transferred.
int bugreportz(int s, bool show_progress);
+// Calls dumpstate using the given socket and write the file content to stdout
+// instead of file location. Ownership of the socket is not transferred.
+int bugreportz_stream(int s);
+
#endif // BUGREPORTZ_H
diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp
index 1d48e08..cd2652c 100644
--- a/cmds/bugreportz/main.cpp
+++ b/cmds/bugreportz/main.cpp
@@ -26,13 +26,14 @@
#include "bugreportz.h"
-static constexpr char VERSION[] = "1.1";
+static constexpr char VERSION[] = "1.2";
static void show_usage() {
fprintf(stderr,
- "usage: bugreportz [-hpv]\n"
+ "usage: bugreportz [-hpsv]\n"
" -h: to display this help message\n"
" -p: display progress\n"
+ " -s: stream content to standard output\n"
" -v: to display the version\n"
" or no arguments to generate a zipped bugreport\n");
}
@@ -43,10 +44,11 @@
int main(int argc, char* argv[]) {
bool show_progress = false;
+ bool stream_data = false;
if (argc > 1) {
/* parse arguments */
int c;
- while ((c = getopt(argc, argv, "hpv")) != -1) {
+ while ((c = getopt(argc, argv, "hpsv")) != -1) {
switch (c) {
case 'h':
show_usage();
@@ -54,6 +56,9 @@
case 'p':
show_progress = true;
break;
+ case 's':
+ stream_data = true;
+ break;
case 'v':
show_version();
return EXIT_SUCCESS;
@@ -75,7 +80,11 @@
// should be reused instead.
// Start the dumpstatez service.
- property_set("ctl.start", "dumpstatez");
+ if (stream_data) {
+ property_set("ctl.start", "dumpstate");
+ } else {
+ property_set("ctl.start", "dumpstatez");
+ }
// Socket will not be available until service starts.
int s = -1;
@@ -103,7 +112,12 @@
strerror(errno));
}
- int ret = bugreportz(s, show_progress);
+ int ret;
+ if (stream_data) {
+ ret = bugreportz_stream(s);
+ } else {
+ ret = bugreportz(s, show_progress);
+ }
if (close(s) == -1) {
fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8bdde62..cbb74b3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -719,6 +719,9 @@
return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
}
+// Opens a socket and returns its file descriptor.
+static int open_socket(const char* service);
+
Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
}
@@ -2287,20 +2290,18 @@
static void ShowUsage() {
fprintf(stderr,
- "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-d] [-p] "
- "[-z] [-s] [-S] [-q] [-P] [-R] [-L] [-V version]\n"
+ "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-p] "
+ "[-s] [-S] [-q] [-P] [-R] [-L] [-V version]\n"
" -h: display this help message\n"
" -b: play sound file instead of vibrate, at beginning of job\n"
" -e: play sound file instead of vibrate, at end of job\n"
" -o: write to custom directory (only in limited mode)\n"
- " -d: append date to filename\n"
" -p: capture screenshot to filename.png\n"
- " -z: generate zipped file\n"
- " -s: write output to control socket (for init)\n"
- " -S: write file location to control socket (for init; requires -z)\n"
+ " -s: write zipped file to control socket (for init)\n"
+ " -S: write file location to control socket (for init)\n"
" -q: disable vibrate\n"
" -P: send broadcast when started and do progress updates\n"
- " -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n"
+ " -R: take bugreport in remote mode (shouldn't be used with -P)\n"
" -w: start binder service and make it wait for a call to startBugreport\n"
" -L: output limited information that is safe for submission in feedback reports\n"
" -v: prints the dumpstate header and exit\n");
@@ -2399,21 +2400,17 @@
/*
* Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
- * if we are writing zip files and adds the version file.
+ * and adds the version file. Return false if zip_file could not be open to write.
*/
-static void PrepareToWriteToFile() {
+static bool PrepareToWriteToFile() {
MaybeResolveSymlink(&ds.bugreport_internal_dir_);
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("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_));
- ds.name_ = date;
- } else {
- ds.name_ = "undated";
- }
+ char date[80];
+ strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
+ ds.name_ = date;
if (ds.options_->telephony_only) {
ds.base_name_ += "-telephony";
@@ -2440,18 +2437,17 @@
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(ds.CalledByApi() ? "-zip.tmp" : ".zip");
- MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
- create_parent_dirs(ds.path_.c_str());
- ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
- if (ds.zip_file == nullptr) {
- MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
- } else {
- ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
- }
- ds.AddTextZipEntry("version.txt", ds.version_);
+ ds.path_ = ds.GetPath(ds.CalledByApi() ? "-zip.tmp" : ".zip");
+ MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
+ create_parent_dirs(ds.path_.c_str());
+ ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
+ if (ds.zip_file == nullptr) {
+ MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
+ return false;
}
+ ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
+ ds.AddTextZipEntry("version.txt", ds.version_);
+ return true;
}
/*
@@ -2459,14 +2455,9 @@
* printing zipped file status, etc.
*/
static void FinalizeFile() {
- bool do_text_file = true;
- if (ds.options_->do_zip_file) {
- if (!ds.FinishZipFile()) {
- MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
- do_text_file = true;
- } else {
- do_text_file = false;
- }
+ bool do_text_file = !ds.FinishZipFile();
+ if (do_text_file) {
+ MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
}
std::string final_path = ds.path_;
@@ -2475,7 +2466,9 @@
android::os::CopyFileToFile(ds.path_, final_path);
}
- if (ds.options_->use_control_socket) {
+ if (ds.options_->stream_to_socket) {
+ android::os::CopyFileToFd(ds.path_, ds.control_socket_fd_);
+ } else if (ds.options_->progress_updates_to_socket) {
if (do_text_file) {
dprintf(ds.control_socket_fd_,
"FAIL:could not create zip file, check %s "
@@ -2531,7 +2524,6 @@
break;
case Dumpstate::BugreportMode::BUGREPORT_WEAR:
options->do_progress_updates = true;
- options->do_zip_file = true;
options->do_screenshot = is_screenshot_requested;
options->dumpstate_hal_mode = DumpstateMode::WEAR;
break;
@@ -2544,7 +2536,6 @@
break;
case Dumpstate::BugreportMode::BUGREPORT_WIFI:
options->wifi_only = true;
- options->do_zip_file = true;
options->do_screenshot = false;
options->dumpstate_hal_mode = DumpstateMode::WIFI;
break;
@@ -2555,11 +2546,11 @@
static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
MYLOGI(
- "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_screenshot: %d "
+ "do_vibrate: %d stream_to_socket: %d progress_updates_to_socket: %d do_screenshot: %d "
"is_remote_mode: %d show_header_only: %d telephony_only: %d "
"wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
"limited_only: %d args: %s\n",
- options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket,
+ options.do_vibrate, options.stream_to_socket, options.progress_updates_to_socket,
options.do_screenshot, options.is_remote_mode, options.show_header_only,
options.telephony_only, options.wifi_only,
options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(),
@@ -2570,11 +2561,6 @@
const android::base::unique_fd& bugreport_fd_in,
const android::base::unique_fd& screenshot_fd_in,
bool is_screenshot_requested) {
- // In the new API world, date is always added; output is always a zip file.
- // TODO(111441001): remove these options once they are obsolete.
- do_add_date = true;
- do_zip_file = true;
-
// Duplicate the fds because the passed in fds don't outlive the binder transaction.
bugreport_fd.reset(dup(bugreport_fd_in.get()));
screenshot_fd.reset(dup(screenshot_fd_in.get()));
@@ -2588,18 +2574,20 @@
while ((c = getopt(argc, argv, "dho:svqzpLPBRSV:w")) != -1) {
switch (c) {
// clang-format off
- case 'd': do_add_date = true; break;
- case 'z': do_zip_file = true; break;
case 'o': out_dir = optarg; break;
- case 's': use_socket = true; break;
- case 'S': use_control_socket = true; break;
+ case 's': stream_to_socket = true; break;
+ case 'S': progress_updates_to_socket = true; break;
case 'v': show_header_only = true; break;
case 'q': do_vibrate = false; break;
case 'p': do_screenshot = true; break;
case 'P': do_progress_updates = true; break;
case 'R': is_remote_mode = true; break;
case 'L': limited_only = true; break;
- case 'V': break; // compatibility no-op
+ case 'V':
+ case 'd':
+ case 'z':
+ // compatibility no-op
+ break;
case 'w':
// This was already processed
break;
@@ -2628,19 +2616,15 @@
}
bool Dumpstate::DumpOptions::ValidateOptions() const {
- if (bugreport_fd.get() != -1 && !do_zip_file) {
+ if (bugreport_fd.get() != -1 && stream_to_socket) {
return false;
}
- if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) {
+ if ((progress_updates_to_socket || do_progress_updates) && stream_to_socket) {
return false;
}
- if (use_control_socket && !do_zip_file) {
- return false;
- }
-
- if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) {
+ if (is_remote_mode && (do_progress_updates || stream_to_socket)) {
return false;
}
return true;
@@ -2715,11 +2699,9 @@
* The temporary bugreport is then populated via printfs, dumping contents of files and
* output of commands to stdout.
*
- * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
- * text file.
+ * A bunch of other files and dumps are added to the zip archive.
*
- * 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.
+ * The temporary bugreport file and the log file also get added to the archive.
*
* Bugreports are first generated in a local directory and later copied to the caller's fd
* or directory if supplied.
@@ -2767,14 +2749,9 @@
MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
calling_uid, calling_package.c_str());
- // Redirect output if needed
- bool is_redirecting = options_->OutputToFile();
-
// TODO: temporarily set progress until it's part of the Dumpstate constructor
std::string stats_path =
- is_redirecting
- ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
- : "";
+ android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str());
progress_.reset(new Progress(stats_path));
if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
@@ -2797,35 +2774,33 @@
// If we are going to use a socket, do it as early as possible
// to avoid timeouts from bugreport.
- if (options_->use_socket) {
- if (!redirect_to_socket(stdout, "dumpstate")) {
- return ERROR;
- }
- }
-
- if (options_->use_control_socket) {
+ if (options_->stream_to_socket || options_->progress_updates_to_socket) {
MYLOGD("Opening control socket\n");
- control_socket_fd_ = open_socket("dumpstate");
+ control_socket_fd_ = open_socket_fn_("dumpstate");
if (control_socket_fd_ == -1) {
return ERROR;
}
- options_->do_progress_updates = 1;
+ if (options_->progress_updates_to_socket) {
+ options_->do_progress_updates = 1;
+ }
}
- if (is_redirecting) {
- PrepareToWriteToFile();
+ if (!PrepareToWriteToFile()) {
+ return ERROR;
+ }
- if (options_->do_progress_updates) {
- // clang-format off
- std::vector<std::string> am_args = {
- "--receiver-permission", "android.permission.DUMP",
- };
- // clang-format on
- // Send STARTED broadcast for apps that listen to bugreport generation events
- SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
- if (options_->use_control_socket) {
- dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
- }
+ // Interactive, wear & telephony modes are default to true.
+ // and may enable from cli option or when using control socket
+ if (options_->do_progress_updates) {
+ // clang-format off
+ std::vector<std::string> am_args = {
+ "--receiver-permission", "android.permission.DUMP",
+ };
+ // clang-format on
+ // Send STARTED broadcast for apps that listen to bugreport generation events
+ SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
+ if (options_->progress_updates_to_socket) {
+ dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
}
}
@@ -2840,40 +2815,38 @@
Vibrate(150);
}
- if (options_->do_zip_file && zip_file != nullptr) {
+ if (zip_file != nullptr) {
if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
- strerror(errno));
+ strerror(errno));
}
}
int dup_stdout_fd;
int dup_stderr_fd;
- if (is_redirecting) {
- // Redirect stderr to log_path_ for debugging.
- TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
- if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
- return ERROR;
- }
- if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
- strerror(errno));
- }
+ // Redirect stderr to log_path_ for debugging.
+ TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
+ if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
+ return ERROR;
+ }
+ if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
+ MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
+ strerror(errno));
+ }
- // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
- // moved into zip file later, if zipping.
- TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
- // TODO: why not write to a file instead of stdout to overcome this problem?
- /* TODO: rather than generating a text file now and zipping it later,
- it would be more efficient to redirect stdout to the zip entry
- directly, but the libziparchive doesn't support that option yet. */
- if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
- return ERROR;
- }
- if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
- tmp_path_.c_str(), strerror(errno));
- }
+ // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
+ // moved into zip file later, if zipping.
+ TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
+ // TODO: why not write to a file instead of stdout to overcome this problem?
+ /* TODO: rather than generating a text file now and zipping it later,
+ it would be more efficient to redirect stdout to the zip entry
+ directly, but the libziparchive doesn't support that option yet. */
+ if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
+ return ERROR;
+ }
+ if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
+ MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
+ tmp_path_.c_str(), strerror(errno));
}
// Don't buffer stdout
@@ -2927,14 +2900,10 @@
}
/* close output if needed */
- if (is_redirecting) {
- TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
- }
+ TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
// Zip the (now complete) .tmp file within the internal directory.
- if (options_->OutputToFile()) {
- FinalizeFile();
- }
+ FinalizeFile();
// Share the final file with the caller if the user has consented or Shell is the caller.
Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
@@ -2977,11 +2946,9 @@
progress_->Save();
MYLOGI("done (id %d)\n", id_);
- if (is_redirecting) {
- TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
- }
+ TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
- if (options_->use_control_socket && control_socket_fd_ != -1) {
+ if (control_socket_fd_ != -1) {
MYLOGD("Closing control socket\n");
close(control_socket_fd_);
}
@@ -3050,10 +3017,7 @@
}
void Dumpstate::EnableParallelRunIfNeeded() {
- // The thread pool needs to create temporary files to receive dump results.
- // That's why we only enable it when the bugreport client chooses to output
- // to a file.
- if (!PropertiesHelper::IsParallelRun() || !options_->OutputToFile()) {
+ if (!PropertiesHelper::IsParallelRun()) {
return;
}
dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
@@ -3198,7 +3162,8 @@
options_(new Dumpstate::DumpOptions()),
last_reported_percent_progress_(0),
version_(version),
- now_(time(nullptr)) {
+ now_(time(nullptr)),
+ open_socket_fn_(open_socket) {
}
Dumpstate& Dumpstate::GetInstance() {
@@ -3832,7 +3797,7 @@
RunCommand(title, dumpsys, options, false, out_fd);
}
-int open_socket(const char *service) {
+static int open_socket(const char* service) {
int s = android_get_control_socket(service);
if (s < 0) {
MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
@@ -3867,19 +3832,6 @@
return fd;
}
-/* redirect output to a service control socket */
-bool redirect_to_socket(FILE* redirect, const char* service) {
- int fd = open_socket(service);
- if (fd == -1) {
- return false;
- }
- fflush(redirect);
- // TODO: handle dup2 failure
- TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
- close(fd);
- return true;
-}
-
// TODO: should call is_valid_output_file and/or be merged into it.
void create_parent_dirs(const char *path) {
char *chp = const_cast<char *> (path);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 3b9b1b7..255243f 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -54,6 +54,7 @@
class DumpstateTest;
class ProgressTest;
+class ZippedBugReportStreamTest;
} // namespace dumpstate
} // namespace os
@@ -197,6 +198,7 @@
*/
class Dumpstate {
friend class android::os::dumpstate::DumpstateTest;
+ friend class android::os::dumpstate::ZippedBugReportStreamTest;
public:
enum RunStatus { OK, HELP, INVALID_INPUT, ERROR, USER_CONSENT_DENIED, USER_CONSENT_TIMED_OUT };
@@ -388,12 +390,11 @@
* Structure to hold options that determine the behavior of dumpstate.
*/
struct DumpOptions {
- 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;
+ // Writes bugreport zipped file to a socket.
+ bool stream_to_socket = false;
+ // Writes generation progress updates to a socket.
+ bool progress_updates_to_socket = false;
bool do_screenshot = false;
bool is_screenshot_copied = false;
bool is_remote_mode = false;
@@ -434,13 +435,6 @@
/* 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;
- }
-
/* Returns if options specified require writing to custom file location */
bool OutputToCustomFile() {
// Custom location is only honored in limited mode.
@@ -466,7 +460,8 @@
std::unique_ptr<Progress> progress_;
- // When set, defines a socket file-descriptor use to report progress to bugreportz.
+ // When set, defines a socket file-descriptor use to report progress to bugreportz
+ // or to stream the zipped file to.
int control_socket_fd_ = -1;
// Bugreport format version;
@@ -478,8 +473,8 @@
// `bugreport-BUILD_ID`.
std::string base_name_;
- // Name is the suffix part of the bugreport files - it's typically the date (when invoked with
- // `-d`), but it could be changed by the user..
+ // Name is the suffix part of the bugreport files - it's typically the date,
+ // but it could be changed by the user..
std::string name_;
std::string bugreport_internal_dir_ = DUMPSTATE_DIRECTORY;
@@ -567,6 +562,8 @@
// called by Shell.
RunStatus CopyBugreportIfUserConsented(int32_t calling_uid);
+ std::function<int(const char *)> open_socket_fn_;
+
// Used by GetInstance() only.
explicit Dumpstate(const std::string& version = VERSION_CURRENT);
@@ -600,16 +597,6 @@
int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
int (*dump_from_fd)(const char* title, const char* path, int fd));
-/** opens a socket and returns its file descriptor */
-int open_socket(const char *service);
-
-/*
- * Redirects 'redirect' to a service control socket.
- *
- * Returns true if redirect succeeds.
- */
-bool redirect_to_socket(FILE* redirect, const char* service);
-
/*
* Redirects 'redirect' to a file indicated by 'path', truncating it.
*
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index e491a4b..a80da4e 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -11,7 +11,7 @@
# dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
# it is finished.
-service dumpstatez /system/bin/dumpstate -S -d -z
+service dumpstatez /system/bin/dumpstate -S
socket dumpstate stream 0660 shell log
class main
disabled
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 70bdbcc..fe6a34a 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -209,9 +209,7 @@
static void GenerateBugreport() {
// clang-format off
char* argv[] = {
- (char*)"dumpstate",
- (char*)"-d",
- (char*)"-z"
+ (char*)"dumpstate"
};
// clang-format on
sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index fdeea24..b2518ad 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "dumpstate"
-#include <cutils/log.h>
+#define LOG_TAG "dumpstate_test"
#include "DumpstateInternal.h"
#include "DumpstateService.h"
@@ -24,6 +23,7 @@
#include "DumpPool.h"
#include <gmock/gmock.h>
+#include <gmock/gmock-matchers.h>
#include <gtest/gtest.h>
#include <fcntl.h>
@@ -39,7 +39,9 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/hardware/dumpstate/1.1/types.h>
+#include <cutils/log.h>
#include <cutils/properties.h>
+#include <ziparchive/zip_archive.h>
namespace android {
namespace os {
@@ -175,11 +177,9 @@
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_FALSE(options_.do_add_date);
- EXPECT_FALSE(options_.do_zip_file);
EXPECT_EQ("", options_.out_dir);
- EXPECT_FALSE(options_.use_socket);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_TRUE(options_.do_vibrate);
EXPECT_FALSE(options_.do_screenshot);
@@ -194,17 +194,13 @@
char* argv[] = {
const_cast<char*>("dumpstatez"),
const_cast<char*>("-S"),
- const_cast<char*>("-d"),
- const_cast<char*>("-z"),
};
// clang-format on
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
- EXPECT_TRUE(options_.use_control_socket);
+ EXPECT_TRUE(options_.progress_updates_to_socket);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -212,7 +208,7 @@
EXPECT_FALSE(options_.do_screenshot);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
@@ -228,13 +224,11 @@
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.use_socket);
+ EXPECT_TRUE(options_.stream_to_socket);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.do_add_date);
- EXPECT_FALSE(options_.do_zip_file);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_screenshot);
EXPECT_FALSE(options_.do_progress_updates);
@@ -245,105 +239,93 @@
TEST_F(DumpOptionsTest, InitializeFullBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_screenshot);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd, false);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.is_remote_mode);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_FALSE(options_.do_screenshot);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE);
// Other options retain default values
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_progress_updates);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeWearBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd, false);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_FALSE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.telephony_only);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_FALSE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.wifi_only);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
@@ -352,8 +334,6 @@
char* argv[] = {
const_cast<char*>("dumpstatez"),
const_cast<char*>("-S"),
- const_cast<char*>("-d"),
- const_cast<char*>("-z"),
const_cast<char*>("-q"),
const_cast<char*>("-L"),
const_cast<char*>("-o abc")
@@ -363,9 +343,7 @@
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
- EXPECT_TRUE(options_.use_control_socket);
+ EXPECT_TRUE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_TRUE(options_.limited_only);
EXPECT_EQ(" abc", std::string(options_.out_dir));
@@ -375,7 +353,7 @@
EXPECT_FALSE(options_.do_screenshot);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
@@ -392,18 +370,16 @@
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.wifi_only);
EXPECT_FALSE(options_.limited_only);
}
@@ -412,8 +388,6 @@
// clang-format off
char* argv[] = {
const_cast<char*>("dumpstate"),
- const_cast<char*>("-d"),
- const_cast<char*>("-z"),
const_cast<char*>("-s"),
const_cast<char*>("-S"),
@@ -423,11 +397,9 @@
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
// TODO: Maybe we should trim the filename
- EXPECT_TRUE(options_.use_socket);
- EXPECT_TRUE(options_.use_control_socket);
+ EXPECT_TRUE(options_.stream_to_socket);
+ EXPECT_TRUE(options_.progress_updates_to_socket);
// Other options retain default values
EXPECT_FALSE(options_.show_header_only);
@@ -461,10 +433,8 @@
EXPECT_TRUE(options_.is_remote_mode);
// Other options retain default values
- EXPECT_FALSE(options_.do_add_date);
- EXPECT_FALSE(options_.do_zip_file);
- EXPECT_FALSE(options_.use_socket);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.limited_only);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
@@ -497,40 +467,31 @@
EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
}
-TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
- options_.do_zip_file = true;
- // Writing to socket = !writing to file.
- options_.use_socket = true;
+TEST_F(DumpOptionsTest, ValidateOptionsSocketUsage1) {
+ options_.progress_updates_to_socket = true;
+ options_.stream_to_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.use_socket = false;
+ options_.stream_to_socket = false;
EXPECT_TRUE(options_.ValidateOptions());
}
-TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
+TEST_F(DumpOptionsTest, ValidateOptionsSocketUsage2) {
options_.do_progress_updates = true;
// Writing to socket = !writing to file.
- options_.use_socket = true;
+ options_.stream_to_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.use_socket = false;
- EXPECT_TRUE(options_.ValidateOptions());
-}
-
-TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) {
- options_.use_control_socket = true;
- EXPECT_FALSE(options_.ValidateOptions());
-
- options_.do_zip_file = true;
+ options_.stream_to_socket = false;
EXPECT_TRUE(options_.ValidateOptions());
}
TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
+ options_.do_progress_updates = true;
options_.is_remote_mode = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.do_zip_file = true;
- options_.do_add_date = true;
+ options_.do_progress_updates = false;
EXPECT_TRUE(options_.ValidateOptions());
}
@@ -1017,23 +978,13 @@
ds.listener_.clear();
}
-TEST_F(DumpstateTest, DumpPool_withOutputToFileAndParallelRunEnabled_notNull) {
- ds.options_->use_socket = false;
+TEST_F(DumpstateTest, DumpPool_withParallelRunEnabled_notNull) {
SetParallelRun(true);
EnableParallelRunIfNeeded();
- EXPECT_TRUE(ds.options_->OutputToFile());
EXPECT_TRUE(ds.zip_entry_tasks_);
EXPECT_TRUE(ds.dump_pool_);
}
-TEST_F(DumpstateTest, DumpPool_withNotOutputToFile_isNull) {
- ds.options_->use_socket = true;
- EnableParallelRunIfNeeded();
- EXPECT_FALSE(ds.options_->OutputToFile());
- EXPECT_FALSE(ds.zip_entry_tasks_);
- EXPECT_FALSE(ds.dump_pool_);
-}
-
TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) {
SetParallelRun(false);
EnableParallelRunIfNeeded();
@@ -1041,6 +992,69 @@
EXPECT_FALSE(ds.dump_pool_);
}
+class ZippedBugReportStreamTest : public DumpstateBaseTest {
+ public:
+ void SetUp() {
+ DumpstateBaseTest::SetUp();
+ ds_.options_.reset(new Dumpstate::DumpOptions());
+ }
+ void TearDown() {
+ CloseArchive(handle_);
+ }
+
+ // Set bugreport mode and options before here.
+ void GenerateBugreport() {
+ ds_.Initialize();
+ EXPECT_EQ(Dumpstate::RunStatus::OK, ds_.Run(/*calling_uid=*/-1, /*calling_package=*/""));
+ }
+
+ // Most bugreports droproot, ensure the file can be opened by shell to verify file content.
+ void CreateFd(const std::string& path, android::base::unique_fd* out_fd) {
+ out_fd->reset(TEMP_FAILURE_RETRY(open(path.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ ASSERT_GE(out_fd->get(), 0) << "could not create FD for path " << path;
+ }
+
+ void VerifyEntry(const ZipArchiveHandle archive, const std::string_view entry_name,
+ ZipEntry* data) {
+ int32_t e = FindEntry(archive, entry_name, data);
+ EXPECT_EQ(0, e) << ErrorCodeString(e) << " entry name: " << entry_name;
+ }
+
+ // While testing dumpstate in process, using STDOUT may get confused about
+ // the internal fd redirection. Redirect to a dedicate fd to save content.
+ void RedirectOutputToFd(android::base::unique_fd& ufd) {
+ ds_.open_socket_fn_ = [&](const char*) -> int { return ufd.release(); };
+ };
+
+ Dumpstate& ds_ = Dumpstate::GetInstance();
+ ZipArchiveHandle handle_;
+};
+
+// Generate a quick wifi report redirected to a file, open it and verify entry exist.
+TEST_F(ZippedBugReportStreamTest, StreamWifiReport) {
+ std::string out_path = kTestDataPath + "out.zip";
+ android::base::unique_fd out_fd;
+ CreateFd(out_path, &out_fd);
+ ds_.options_->wifi_only = true;
+ ds_.options_->stream_to_socket = true;
+ RedirectOutputToFd(out_fd);
+
+ GenerateBugreport();
+ OpenArchive(out_path.c_str(), &handle_);
+
+ ZipEntry entry;
+ VerifyEntry(handle_, "main_entry.txt", &entry);
+ std::string bugreport_txt_name;
+ bugreport_txt_name.resize(entry.uncompressed_length);
+ ExtractToMemory(handle_, &entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
+ entry.uncompressed_length);
+ EXPECT_THAT(bugreport_txt_name,
+ testing::ContainsRegex("(bugreport-.+-wifi(-[[:digit:]]+){6}\\.txt)"));
+ VerifyEntry(handle_, bugreport_txt_name, &entry);
+}
+
class DumpstateServiceTest : public DumpstateBaseTest {
public:
DumpstateService dss;
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
index e080291..6027139 100644
--- a/cmds/installd/QuotaUtils.cpp
+++ b/cmds/installd/QuotaUtils.cpp
@@ -35,7 +35,7 @@
/* Map of all quota mounts from target to source */
std::unordered_map<std::string, std::string> mQuotaReverseMounts;
-std::string& FindQuotaDeviceForUuid(const std::string& uuid) {
+std::string FindQuotaDeviceForUuid(const std::string& uuid) {
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str());
return mQuotaReverseMounts[path];
diff --git a/data/etc/android.hardware.uwb.xml b/data/etc/android.hardware.uwb.xml
new file mode 100644
index 0000000..794ba27
--- /dev/null
+++ b/data/etc/android.hardware.uwb.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<!-- Adds the feature indicating support for the Ultra Wideband API -->
+<permissions>
+ <feature name="android.hardware.uwb" />
+</permissions>
diff --git a/include/ftl/ArrayTraits.h b/include/ftl/ArrayTraits.h
index 28f717a..ff685c5 100644
--- a/include/ftl/ArrayTraits.h
+++ b/include/ftl/ArrayTraits.h
@@ -19,6 +19,7 @@
#include <algorithm>
#include <iterator>
#include <new>
+#include <type_traits>
#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U
@@ -40,11 +41,16 @@
using const_iterator = const_pointer;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- // TODO: Replace with std::construct_at in C++20.
template <typename... Args>
static pointer construct_at(const_iterator it, Args&&... args) {
void* const ptr = const_cast<void*>(static_cast<const void*>(it));
- return new (ptr) value_type{std::forward<Args>(args)...};
+ if constexpr (std::is_constructible_v<value_type, Args...>) {
+ // TODO: Replace with std::construct_at in C++20.
+ return new (ptr) value_type(std::forward<Args>(args)...);
+ } else {
+ // Fall back to list initialization.
+ return new (ptr) value_type{std::forward<Args>(args)...};
+ }
}
};
diff --git a/include/ftl/InitializerList.h b/include/ftl/InitializerList.h
new file mode 100644
index 0000000..bb99280
--- /dev/null
+++ b/include/ftl/InitializerList.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2020 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 <tuple>
+#include <utility>
+
+namespace android::ftl {
+
+// Compile-time counterpart of std::initializer_list<T> that stores per-element constructor
+// arguments with heterogeneous types. For a container with elements of type T, given Sizes
+// (S0, S1, ..., SN), N elements are initialized: the first element is initialized with the
+// first S0 arguments, the second element is initialized with the next S1 arguments, and so
+// on. The list of Types (T0, ..., TM) is flattened, so M is equal to the sum of the Sizes.
+//
+// The InitializerList is created using ftl::init::list, and is consumed by constructors of
+// containers. The function call operator is overloaded such that arguments are accumulated
+// in a tuple with each successive call. For instance, the following calls initialize three
+// strings using different constructors, i.e. string literal, default, and count/character:
+//
+// ... = ftl::init::list<std::string>("abc")()(3u, '?');
+//
+// The following syntax is a shorthand for key-value pairs, where the first argument is the
+// key, and the rest construct the value. The types of the key and value are deduced if the
+// first pair contains exactly two arguments:
+//
+// ... = ftl::init::map<int, std::string>(-1, "abc")(-2)(-3, 3u, '?');
+//
+// ... = ftl::init::map(0, 'a')(1, 'b')(2, 'c');
+//
+// WARNING: The InitializerList returned by an ftl::init::list expression must be consumed
+// immediately, since temporary arguments are destroyed after the full expression. Storing
+// an InitializerList results in dangling references.
+//
+template <typename T, typename Sizes = std::index_sequence<>, typename... Types>
+struct InitializerList;
+
+template <typename T, size_t... Sizes, typename... Types>
+struct InitializerList<T, std::index_sequence<Sizes...>, Types...> {
+ // Creates a superset InitializerList by appending the number of arguments to Sizes, and
+ // expanding Types with forwarding references for each argument.
+ template <typename... Args>
+ [[nodiscard]] constexpr auto operator()(Args&&... args) && -> InitializerList<
+ T, std::index_sequence<Sizes..., sizeof...(Args)>, Types..., Args&&...> {
+ return {std::tuple_cat(std::move(tuple),
+ std::forward_as_tuple(std::forward<Args>(args)...))};
+ }
+
+ // The temporary InitializerList returned by operator() is bound to an rvalue reference in
+ // container constructors, which extends the lifetime of any temporary arguments that this
+ // tuple refers to until the completion of the full expression containing the construction.
+ std::tuple<Types...> tuple;
+};
+
+template <typename K, typename V>
+struct KeyValue {};
+
+// Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the
+// value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works
+// with the latter.
+template <typename K, typename V, size_t... Sizes, typename... Types>
+struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> {
+ // Accumulate the three arguments to std::pair's piecewise constructor.
+ template <typename... Args>
+ [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList<
+ KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
+ std::tuple<K&&>, std::tuple<Args&&...>> {
+ return {std::tuple_cat(std::move(tuple),
+ std::forward_as_tuple(std::piecewise_construct,
+ std::forward_as_tuple(std::forward<K>(k)),
+ std::forward_as_tuple(
+ std::forward<Args>(args)...)))};
+ }
+
+ std::tuple<Types...> tuple;
+};
+
+namespace init {
+
+template <typename T, typename... Args>
+[[nodiscard]] constexpr auto list(Args&&... args) {
+ return InitializerList<T>{}(std::forward<Args>(args)...);
+}
+
+template <typename K, typename V, typename... Args>
+[[nodiscard]] constexpr auto map(Args&&... args) {
+ return list<KeyValue<K, V>>(std::forward<Args>(args)...);
+}
+
+template <typename K, typename V>
+[[nodiscard]] constexpr auto map(K&& k, V&& v) {
+ return list<KeyValue<K, V>>(std::forward<K>(k), std::forward<V>(v));
+}
+
+} // namespace init
+} // namespace android::ftl
diff --git a/include/ftl/SmallMap.h b/include/ftl/SmallMap.h
new file mode 100644
index 0000000..87ae99c
--- /dev/null
+++ b/include/ftl/SmallMap.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2020 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 <ftl/InitializerList.h>
+#include <ftl/SmallVector.h>
+
+#include <functional>
+#include <optional>
+#include <type_traits>
+#include <utility>
+
+namespace android::ftl {
+
+// Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are
+// stored in contiguous storage for cache efficiency. The map is allocated statically until its size
+// exceeds N, at which point mappings are relocated to dynamic memory.
+//
+// SmallMap<K, V, 0> unconditionally allocates on the heap.
+//
+// Example usage:
+//
+// ftl::SmallMap<int, std::string, 3> map;
+// assert(map.empty());
+// assert(!map.dynamic());
+//
+// map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+// assert(map.size() == 3u);
+// assert(!map.dynamic());
+//
+// assert(map.contains(123));
+// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u);
+//
+// const auto opt = map.find(-1);
+// assert(opt);
+//
+// std::string& ref = *opt;
+// assert(ref.empty());
+// ref = "xyz";
+//
+// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
+//
+template <typename K, typename V, size_t N>
+class SmallMap final {
+ using Map = SmallVector<std::pair<const K, V>, N>;
+
+public:
+ using key_type = K;
+ using mapped_type = V;
+
+ using value_type = typename Map::value_type;
+ using size_type = typename Map::size_type;
+ using difference_type = typename Map::difference_type;
+
+ using reference = typename Map::reference;
+ using iterator = typename Map::iterator;
+
+ using const_reference = typename Map::const_reference;
+ using const_iterator = typename Map::const_iterator;
+
+ // Creates an empty map.
+ SmallMap() = default;
+
+ // Constructs at most N key-value pairs in place by forwarding per-pair constructor arguments.
+ // The template arguments K, V, and N are inferred using the deduction guide defined below.
+ // The syntax for listing pairs is as follows:
+ //
+ // ftl::SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+ //
+ // static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, std::string, 3>>);
+ // assert(map.size() == 3u);
+ // assert(map.contains(-1) && map.find(-1)->get().empty());
+ // assert(map.contains(42) && map.find(42)->get() == "???");
+ // assert(map.contains(123) && map.find(123)->get() == "abc");
+ //
+ // The types of the key and value are deduced if the first pair contains exactly two arguments:
+ //
+ // ftl::SmallMap map = ftl::init::map(0, 'a')(1, 'b')(2, 'c');
+ // static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, char, 3>>);
+ //
+ template <typename U, size_t... Sizes, typename... Types>
+ SmallMap(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& init)
+ : mMap(std::move(init)) {
+ // TODO: Enforce unique keys.
+ }
+
+ size_type max_size() const { return mMap.max_size(); }
+ size_type size() const { return mMap.size(); }
+ bool empty() const { return mMap.empty(); }
+
+ // Returns whether the map is backed by static or dynamic storage.
+ bool dynamic() const { return mMap.dynamic(); }
+
+ iterator begin() { return mMap.begin(); }
+ const_iterator begin() const { return cbegin(); }
+ const_iterator cbegin() const { return mMap.cbegin(); }
+
+ iterator end() { return mMap.end(); }
+ const_iterator end() const { return cend(); }
+ const_iterator cend() const { return mMap.cend(); }
+
+ // Returns whether a mapping exists for the given key.
+ bool contains(const key_type& key) const {
+ return find(key, [](const mapped_type&) {});
+ }
+
+ // Returns a reference to the value for the given key, or std::nullopt if the key was not found.
+ //
+ // ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
+ //
+ // const auto opt = map.find('c');
+ // assert(opt == 'C');
+ //
+ // char d = 'd';
+ // const auto ref = map.find('d').value_or(std::ref(d));
+ // ref.get() = 'D';
+ // assert(d == 'D');
+ //
+ auto find(const key_type& key) const
+ -> std::optional<std::reference_wrapper<const mapped_type>> {
+ return find(key, [](const mapped_type& v) { return std::cref(v); });
+ }
+
+ auto find(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
+ return find(key, [](mapped_type& v) { return std::ref(v); });
+ }
+
+ // Returns the result R of a unary operation F on (a constant or mutable reference to) the value
+ // for the given key, or std::nullopt if the key was not found. If F has a return type of void,
+ // then the Boolean result indicates whether the key was found.
+ //
+ // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
+ //
+ // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z');
+ // assert(map.find('c', [](char& c) { c = std::toupper(c); }));
+ //
+ template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>>
+ auto find(const key_type& key, F f) const
+ -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> {
+ for (auto& [k, v] : *this) {
+ if (k == key) {
+ if constexpr (std::is_void_v<R>) {
+ f(v);
+ return true;
+ } else {
+ return f(v);
+ }
+ }
+ }
+
+ return {};
+ }
+
+ template <typename F>
+ auto find(const key_type& key, F f) {
+ return std::as_const(*this).find(key, [&f](const mapped_type& v) {
+ return f(const_cast<mapped_type&>(v));
+ });
+ }
+
+private:
+ Map mMap;
+};
+
+// Deduction guide for in-place constructor.
+template <typename K, typename V, size_t... Sizes, typename... Types>
+SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&)
+ -> SmallMap<K, V, sizeof...(Sizes)>;
+
+// Returns whether the key-value pairs of two maps are equal.
+template <typename K, typename V, size_t N, typename Q, typename W, size_t M>
+bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+ if (lhs.size() != rhs.size()) return false;
+
+ for (const auto& [k, v] : lhs) {
+ const auto& lv = v;
+ if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// TODO: Remove in C++20.
+template <typename K, typename V, size_t N, typename Q, typename W, size_t M>
+inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/SmallVector.h b/include/ftl/SmallVector.h
index cecec7f..2f05a9b 100644
--- a/include/ftl/SmallVector.h
+++ b/include/ftl/SmallVector.h
@@ -64,6 +64,16 @@
// assert(vector == (ftl::SmallVector{'h', 'i', '\0'}));
// assert(!vector.dynamic());
//
+// ftl::SmallVector strings = ftl::init::list<std::string>("abc")
+// ("123456", 3u)
+// (3u, '?');
+// assert(strings.size() == 3u);
+// assert(!strings.dynamic());
+//
+// assert(strings[0] == "abc");
+// assert(strings[1] == "123");
+// assert(strings[2] == "???");
+//
template <typename T, size_t N>
class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
using Static = StaticVector<T, N>;
@@ -365,8 +375,9 @@
SmallVector(T&&, Us&&...) -> SmallVector<V, 1 + sizeof...(Us)>;
// Deduction guide for in-place constructor.
-template <typename T, typename... Us>
-SmallVector(std::in_place_type_t<T>, Us&&...) -> SmallVector<T, sizeof...(Us)>;
+template <typename T, size_t... Sizes, typename... Types>
+SmallVector(InitializerList<T, std::index_sequence<Sizes...>, Types...>&&)
+ -> SmallVector<T, sizeof...(Sizes)>;
// Deduction guide for StaticVector conversion.
template <typename T, size_t N>
diff --git a/include/ftl/StaticVector.h b/include/ftl/StaticVector.h
index 457095d..c132556 100644
--- a/include/ftl/StaticVector.h
+++ b/include/ftl/StaticVector.h
@@ -17,6 +17,7 @@
#pragma once
#include <ftl/ArrayTraits.h>
+#include <ftl/InitializerList.h>
#include <algorithm>
#include <cassert>
@@ -32,7 +33,7 @@
// Fixed-capacity, statically allocated counterpart of std::vector. Akin to std::array, StaticVector
// allocates contiguous storage for N elements of type T at compile time, but stores at most (rather
// than exactly) N elements. Unlike std::array, its default constructor does not require T to have a
-// default constructor, since elements are constructed in-place as the vector grows. Operations that
+// default constructor, since elements are constructed in place as the vector grows. Operations that
// insert an element (emplace_back, push_back, etc.) fail when the vector is full. The API otherwise
// adheres to standard containers, except the unstable_erase operation that does not preserve order,
// and the replace operation that destructively emplaces.
@@ -63,6 +64,14 @@
// vector = ftl::StaticVector(array);
// assert(vector == (ftl::StaticVector{'h', 'i', '\0'}));
//
+// ftl::StaticVector strings = ftl::init::list<std::string>("abc")
+// ("123456", 3u)
+// (3u, '?');
+// assert(strings.size() == 3u);
+// assert(strings[0] == "abc");
+// assert(strings[1] == "123");
+// assert(strings[2] == "???");
+//
template <typename T, size_t N>
class StaticVector final : ArrayTraits<T>,
ArrayIterators<StaticVector<T, N>, T>,
@@ -153,15 +162,22 @@
static_assert(sizeof...(elements) < N, "Too many elements");
}
- // Constructs at most N elements. The template arguments T and N are inferred using the
- // deduction guide defined below. Element types must be convertible to the specified T:
+ // Constructs at most N elements in place by forwarding per-element constructor arguments. The
+ // template arguments T and N are inferred using the deduction guide defined below. The syntax
+ // for listing arguments is as follows:
//
- // ftl::StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+ // ftl::StaticVector vector = ftl::init::list<std::string>("abc")()(3u, '?');
+ //
// static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 3>>);
+ // assert(vector.full());
+ // assert(vector[0] == "abc");
+ // assert(vector[1].empty());
+ // assert(vector[2] == "???");
//
- template <typename... Es>
- explicit StaticVector(std::in_place_type_t<T>, Es... elements)
- : StaticVector(std::forward<Es>(elements)...) {}
+ template <typename U, size_t Size, size_t... Sizes, typename... Types>
+ StaticVector(InitializerList<U, std::index_sequence<Size, Sizes...>, Types...>&& init)
+ : StaticVector(std::index_sequence<0, 0, Size>{}, std::make_index_sequence<Size>{},
+ std::index_sequence<Sizes...>{}, init.tuple) {}
~StaticVector() { std::destroy(begin(), end()); }
@@ -292,6 +308,32 @@
template <size_t I>
explicit StaticVector(std::index_sequence<I>) : mSize(I) {}
+ // Recursion for in-place constructor.
+ //
+ // Construct element I by extracting its arguments from the InitializerList tuple. ArgIndex
+ // is the position of its first argument in Args, and ArgCount is the number of arguments.
+ // The Indices sequence corresponds to [0, ArgCount).
+ //
+ // The Sizes sequence lists the argument counts for elements after I, so Size is the ArgCount
+ // for the next element. The recursion stops when Sizes is empty for the last element.
+ //
+ template <size_t I, size_t ArgIndex, size_t ArgCount, size_t... Indices, size_t Size,
+ size_t... Sizes, typename... Args>
+ StaticVector(std::index_sequence<I, ArgIndex, ArgCount>, std::index_sequence<Indices...>,
+ std::index_sequence<Size, Sizes...>, std::tuple<Args...>& tuple)
+ : StaticVector(std::index_sequence<I + 1, ArgIndex + ArgCount, Size>{},
+ std::make_index_sequence<Size>{}, std::index_sequence<Sizes...>{}, tuple) {
+ construct_at(begin() + I, std::move(std::get<ArgIndex + Indices>(tuple))...);
+ }
+
+ // Base case for in-place constructor.
+ template <size_t I, size_t ArgIndex, size_t ArgCount, size_t... Indices, typename... Args>
+ StaticVector(std::index_sequence<I, ArgIndex, ArgCount>, std::index_sequence<Indices...>,
+ std::index_sequence<>, std::tuple<Args...>& tuple)
+ : mSize(I + 1) {
+ construct_at(begin() + I, std::move(std::get<ArgIndex + Indices>(tuple))...);
+ }
+
size_type mSize = 0;
std::aligned_storage_t<sizeof(value_type), alignof(value_type)> mData[N];
};
@@ -306,8 +348,9 @@
StaticVector(T&&, Us&&...) -> StaticVector<V, 1 + sizeof...(Us)>;
// Deduction guide for in-place constructor.
-template <typename T, typename... Us>
-StaticVector(std::in_place_type_t<T>, Us&&...) -> StaticVector<T, sizeof...(Us)>;
+template <typename T, size_t... Sizes, typename... Types>
+StaticVector(InitializerList<T, std::index_sequence<Sizes...>, Types...>&&)
+ -> StaticVector<T, sizeof...(Sizes)>;
template <typename T, size_t N>
template <typename E>
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 015954d..90feedd 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -145,6 +145,7 @@
cflags: [
"-Wall",
"-Wextra",
+ "-Wextra-semi",
"-Werror",
"-Wzero-as-null-pointer-constant",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 8264154..bf4387a 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -137,8 +137,8 @@
}
BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
- : mHandle(handle)
- , mStability(0)
+ : mStability(0)
+ , mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(nullptr)
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index cf9bb46..08169f5 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -135,6 +135,6 @@
// ------------------------------------------------------------------------------------
-IMPLEMENT_META_INTERFACE(ActivityManager, "android.app.IActivityManager");
+IMPLEMENT_META_INTERFACE(ActivityManager, "android.app.IActivityManager")
} // namespace android
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index b9eb281..2b3f462 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -43,7 +43,7 @@
}
};
-IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallback");
+IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallback")
// ----------------------------------------------------------------------
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index ee0cd62..1897969 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -162,7 +162,7 @@
}
};
-IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
+IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService")
// ----------------------------------------------------------------------
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index a47dbac..d0085df 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -130,7 +130,7 @@
};
-IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats");
+IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats")
// ----------------------------------------------------------------------
diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp
index 5f3d670..f5fa817 100644
--- a/libs/binder/IMediaResourceMonitor.cpp
+++ b/libs/binder/IMediaResourceMonitor.cpp
@@ -38,7 +38,7 @@
}
};
-IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMonitor");
+IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMonitor")
// ----------------------------------------------------------------------
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index d8b44f9..cca8f81 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -223,7 +223,7 @@
// ---------------------------------------------------------------------------
-IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
+IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory")
BnMemory::BnMemory() {
}
@@ -388,7 +388,7 @@
// ---------------------------------------------------------------------------
-IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
+IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap")
BnMemoryHeap::BnMemoryHeap() {
}
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index d9bf3cc..f94f413 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -103,7 +103,7 @@
}
};
-IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
+IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController")
// ----------------------------------------------------------------------
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
index a38a27a..570edb9 100644
--- a/libs/binder/IProcessInfoService.cpp
+++ b/libs/binder/IProcessInfoService.cpp
@@ -84,7 +84,7 @@
}
};
-IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService");
+IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService")
// ----------------------------------------------------------------------
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index 556288c..cd92217 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -42,7 +42,7 @@
}
};
-IMPLEMENT_META_INTERFACE(ResultReceiver, "com.android.internal.os.IResultReceiver");
+IMPLEMENT_META_INTERFACE(ResultReceiver, "com.android.internal.os.IResultReceiver")
// ----------------------------------------------------------------------
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index a3e2b67..86dd5c4 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -52,7 +52,7 @@
}
};
-IMPLEMENT_META_INTERFACE(ShellCallback, "com.android.internal.os.IShellCallback");
+IMPLEMENT_META_INTERFACE(ShellCallback, "com.android.internal.os.IShellCallback")
// ----------------------------------------------------------------------
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
index 4714234..a1b08db 100644
--- a/libs/binder/IUidObserver.cpp
+++ b/libs/binder/IUidObserver.cpp
@@ -71,7 +71,7 @@
// ----------------------------------------------------------------------
-IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver");
+IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver")
// ----------------------------------------------------------------------
diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp
index 75a6d22..6eae5ef 100644
--- a/libs/binder/PermissionCache.cpp
+++ b/libs/binder/PermissionCache.cpp
@@ -27,7 +27,7 @@
// ----------------------------------------------------------------------------
-ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ;
+ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache)
// ----------------------------------------------------------------------------
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
index 00d6eef..f75141e 100644
--- a/libs/binder/ProcessInfoService.cpp
+++ b/libs/binder/ProcessInfoService.cpp
@@ -99,6 +99,6 @@
}
}
-ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService);
+ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService)
} // namespace android
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index db0f1c7..565f2e2 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -33,7 +33,7 @@
{
public:
LogTextOutput() : BufferedTextOutput(MULTITHREADED) { }
- virtual ~LogTextOutput() { };
+ virtual ~LogTextOutput() { }
protected:
virtual status_t writeLines(const struct iovec& vec, size_t N)
@@ -49,7 +49,7 @@
{
public:
explicit FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
- virtual ~FdTextOutput() { };
+ virtual ~FdTextOutput() { }
protected:
virtual status_t writeLines(const struct iovec& vec, size_t N)
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index dafc879..1cfb560 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -53,9 +53,7 @@
},
{
"name": "libbinder_rs-internal_test"
- }
- ],
- "postsubmit": [
+ },
{
"name": "rustBinderTest"
}
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 64d0657..2735315 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -28,7 +28,7 @@
namespace internal {
class Stability;
-};
+}
using binder_proxy_limit_callback = void(*)(int);
@@ -109,19 +109,18 @@
KeyedVector<const void*, entry_t> mObjects;
};
-protected:
+private:
BpBinder(int32_t handle,int32_t trackedUid);
virtual ~BpBinder();
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
-private:
- const int32_t mHandle;
-
friend ::android::internal::Stability;
int32_t mStability;
+ const int32_t mHandle;
+
struct Obituary {
wp<DeathRecipient> recipient;
void* cookie;
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index 17e34db..6d3fe4a 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -25,7 +25,7 @@
class IShellCallback : public IInterface
{
public:
- DECLARE_META_INTERFACE(ShellCallback);
+ DECLARE_META_INTERFACE(ShellCallback)
virtual int openFile(const String16& path, const String16& seLinuxContext,
const String16& mode) = 0;
diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h
index c1cd3c2..a8faa3f 100644
--- a/libs/binder/include/binder/IpPrefix.h
+++ b/libs/binder/include/binder/IpPrefix.h
@@ -73,8 +73,8 @@
private:
union InternalUnion {
InternalUnion() = default;
- explicit InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { };
- explicit InternalUnion(const struct in_addr &addr):mInAddr(addr) { };
+ explicit InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { }
+ explicit InternalUnion(const struct in_addr &addr):mInAddr(addr) { }
struct in6_addr mIn6Addr;
struct in_addr mInAddr;
} mUnion;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 4b2d50d..cfe1f3a 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -131,7 +131,7 @@
status_t writeString8(const char* str, size_t len);
status_t writeString16(const String16& str);
status_t writeString16(const std::optional<String16>& str);
- status_t writeString16(const std::unique_ptr<String16>& str);
+ status_t writeString16(const std::unique_ptr<String16>& str) __attribute__((deprecated("use std::optional version instead")));
status_t writeString16(const char16_t* str, size_t len);
status_t writeStrongBinder(const sp<IBinder>& val);
status_t writeInt32Array(size_t len, const int32_t *val);
@@ -143,48 +143,48 @@
// Take a UTF8 encoded string, convert to UTF16, write it to the parcel.
status_t writeUtf8AsUtf16(const std::string& str);
status_t writeUtf8AsUtf16(const std::optional<std::string>& str);
- status_t writeUtf8AsUtf16(const std::unique_ptr<std::string>& str);
+ status_t writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) __attribute__((deprecated("use std::optional version instead")));
status_t writeByteVector(const std::optional<std::vector<int8_t>>& val);
- status_t writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val);
+ status_t writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeByteVector(const std::vector<int8_t>& val);
status_t writeByteVector(const std::optional<std::vector<uint8_t>>& val);
- status_t writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val);
+ status_t writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeByteVector(const std::vector<uint8_t>& val);
status_t writeInt32Vector(const std::optional<std::vector<int32_t>>& val);
- status_t writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val);
+ status_t writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeInt32Vector(const std::vector<int32_t>& val);
status_t writeInt64Vector(const std::optional<std::vector<int64_t>>& val);
- status_t writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val);
+ status_t writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeInt64Vector(const std::vector<int64_t>& val);
status_t writeUint64Vector(const std::optional<std::vector<uint64_t>>& val);
- status_t writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val);
+ status_t writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeUint64Vector(const std::vector<uint64_t>& val);
status_t writeFloatVector(const std::optional<std::vector<float>>& val);
- status_t writeFloatVector(const std::unique_ptr<std::vector<float>>& val);
+ status_t writeFloatVector(const std::unique_ptr<std::vector<float>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeFloatVector(const std::vector<float>& val);
status_t writeDoubleVector(const std::optional<std::vector<double>>& val);
- status_t writeDoubleVector(const std::unique_ptr<std::vector<double>>& val);
+ status_t writeDoubleVector(const std::unique_ptr<std::vector<double>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeDoubleVector(const std::vector<double>& val);
status_t writeBoolVector(const std::optional<std::vector<bool>>& val);
- status_t writeBoolVector(const std::unique_ptr<std::vector<bool>>& val);
+ status_t writeBoolVector(const std::unique_ptr<std::vector<bool>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeBoolVector(const std::vector<bool>& val);
status_t writeCharVector(const std::optional<std::vector<char16_t>>& val);
- status_t writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val);
+ status_t writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeCharVector(const std::vector<char16_t>& val);
status_t writeString16Vector(
const std::optional<std::vector<std::optional<String16>>>& val);
status_t writeString16Vector(
- const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val);
+ const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeString16Vector(const std::vector<String16>& val);
status_t writeUtf8VectorAsUtf16Vector(
const std::optional<std::vector<std::optional<std::string>>>& val);
status_t writeUtf8VectorAsUtf16Vector(
- const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val);
+ const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val);
status_t writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val);
- status_t writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val);
+ status_t writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
// Write an Enum vector with underlying type int8_t.
@@ -194,21 +194,21 @@
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
status_t writeEnumVector(const std::optional<std::vector<T>>& val);
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val);
+ status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
// Write an Enum vector with underlying type != int8_t.
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
status_t writeEnumVector(const std::vector<T>& val);
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
status_t writeEnumVector(const std::optional<std::vector<T>>& val);
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val);
+ status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
template<typename T>
status_t writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val);
template<typename T>
- status_t writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val);
+ status_t writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
template<typename T>
- status_t writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val);
+ status_t writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
template<typename T>
status_t writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val);
template<typename T>
@@ -217,7 +217,7 @@
template<typename T>
status_t writeNullableParcelable(const std::optional<T>& parcelable);
template<typename T>
- status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable);
+ status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")));
status_t writeParcelable(const Parcelable& parcelable);
@@ -232,7 +232,7 @@
template<typename T>
status_t writeVectorSize(const std::optional<std::vector<T>>& val);
template<typename T>
- status_t writeVectorSize(const std::unique_ptr<std::vector<T>>& val);
+ status_t writeVectorSize(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
// Place a native_handle into the parcel (the native_handle's file-
// descriptors are dup'ed, so it is safe to delete the native_handle
@@ -269,7 +269,7 @@
status_t writeUniqueFileDescriptorVector(
const std::optional<std::vector<base::unique_fd>>& val);
status_t writeUniqueFileDescriptorVector(
- const std::unique_ptr<std::vector<base::unique_fd>>& val);
+ const std::unique_ptr<std::vector<base::unique_fd>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeUniqueFileDescriptorVector(
const std::vector<base::unique_fd>& val);
@@ -317,7 +317,7 @@
// Read a UTF16 encoded string, convert to UTF8
status_t readUtf8FromUtf16(std::string* str) const;
status_t readUtf8FromUtf16(std::optional<std::string>* str) const;
- status_t readUtf8FromUtf16(std::unique_ptr<std::string>* str) const;
+ status_t readUtf8FromUtf16(std::unique_ptr<std::string>* str) const __attribute__((deprecated("use std::optional version instead")));
const char* readCString() const;
String8 readString8() const;
@@ -326,7 +326,7 @@
String16 readString16() const;
status_t readString16(String16* pArg) const;
status_t readString16(std::optional<String16>* pArg) const;
- status_t readString16(std::unique_ptr<String16>* pArg) const;
+ status_t readString16(std::unique_ptr<String16>* pArg) const __attribute__((deprecated("use std::optional version instead")));
const char16_t* readString16Inplace(size_t* outLen) const;
sp<IBinder> readStrongBinder() const;
status_t readStrongBinder(sp<IBinder>* val) const;
@@ -337,14 +337,14 @@
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
status_t readEnumVector(std::vector<T>* val) const;
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const;
+ status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
status_t readEnumVector(std::optional<std::vector<T>>* val) const;
// Read an Enum vector with underlying type != int8_t.
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
status_t readEnumVector(std::vector<T>* val) const;
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const;
+ status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
status_t readEnumVector(std::optional<std::vector<T>>* val) const;
@@ -353,7 +353,7 @@
std::optional<std::vector<std::optional<T>>>* val) const;
template<typename T>
status_t readParcelableVector(
- std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const;
+ std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")));
template<typename T>
status_t readParcelableVector(std::vector<T>* val) const;
@@ -362,7 +362,7 @@
template<typename T>
status_t readParcelable(std::optional<T>* parcelable) const;
template<typename T>
- status_t readParcelable(std::unique_ptr<T>* parcelable) const;
+ status_t readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")));
template<typename T>
status_t readStrongBinder(sp<T>* val) const;
@@ -371,45 +371,45 @@
status_t readNullableStrongBinder(sp<T>* val) const;
status_t readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const;
- status_t readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const;
+ status_t readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
status_t readByteVector(std::optional<std::vector<int8_t>>* val) const;
- status_t readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const;
+ status_t readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readByteVector(std::vector<int8_t>* val) const;
status_t readByteVector(std::optional<std::vector<uint8_t>>* val) const;
- status_t readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const;
+ status_t readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readByteVector(std::vector<uint8_t>* val) const;
status_t readInt32Vector(std::optional<std::vector<int32_t>>* val) const;
- status_t readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const;
+ status_t readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readInt32Vector(std::vector<int32_t>* val) const;
status_t readInt64Vector(std::optional<std::vector<int64_t>>* val) const;
- status_t readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const;
+ status_t readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readInt64Vector(std::vector<int64_t>* val) const;
status_t readUint64Vector(std::optional<std::vector<uint64_t>>* val) const;
- status_t readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const;
+ status_t readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readUint64Vector(std::vector<uint64_t>* val) const;
status_t readFloatVector(std::optional<std::vector<float>>* val) const;
- status_t readFloatVector(std::unique_ptr<std::vector<float>>* val) const;
+ status_t readFloatVector(std::unique_ptr<std::vector<float>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readFloatVector(std::vector<float>* val) const;
status_t readDoubleVector(std::optional<std::vector<double>>* val) const;
- status_t readDoubleVector(std::unique_ptr<std::vector<double>>* val) const;
+ status_t readDoubleVector(std::unique_ptr<std::vector<double>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readDoubleVector(std::vector<double>* val) const;
status_t readBoolVector(std::optional<std::vector<bool>>* val) const;
- status_t readBoolVector(std::unique_ptr<std::vector<bool>>* val) const;
+ status_t readBoolVector(std::unique_ptr<std::vector<bool>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readBoolVector(std::vector<bool>* val) const;
status_t readCharVector(std::optional<std::vector<char16_t>>* val) const;
- status_t readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const;
+ status_t readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readCharVector(std::vector<char16_t>* val) const;
status_t readString16Vector(
std::optional<std::vector<std::optional<String16>>>* val) const;
status_t readString16Vector(
- std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const;
+ std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readString16Vector(std::vector<String16>* val) const;
status_t readUtf8VectorFromUtf16Vector(
std::optional<std::vector<std::optional<std::string>>>* val) const;
status_t readUtf8VectorFromUtf16Vector(
- std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const;
+ std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const;
template<typename T>
@@ -423,7 +423,7 @@
template<typename T>
status_t resizeOutVector(std::optional<std::vector<T>>* val) const;
template<typename T>
- status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const;
+ status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
template<typename T>
status_t reserveOutVector(std::vector<T>* val, size_t* size) const;
template<typename T>
@@ -431,7 +431,7 @@
size_t* size) const;
template<typename T>
status_t reserveOutVector(std::unique_ptr<std::vector<T>>* val,
- size_t* size) const;
+ size_t* size) const __attribute__((deprecated("use std::optional version instead")));
// Like Parcel.java's readExceptionCode(). Reads the first int32
// off of a Parcel's header, returning 0 or the negative error
@@ -467,7 +467,7 @@
status_t readUniqueFileDescriptorVector(
std::optional<std::vector<base::unique_fd>>* val) const;
status_t readUniqueFileDescriptorVector(
- std::unique_ptr<std::vector<base::unique_fd>>* val) const;
+ std::unique_ptr<std::vector<base::unique_fd>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readUniqueFileDescriptorVector(
std::vector<base::unique_fd>* val) const;
@@ -561,7 +561,7 @@
status_t(Parcel::*read_func)(T*) const) const;
template<typename T>
status_t readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const;
+ status_t(Parcel::*read_func)(T*) const) const __attribute__((deprecated("use std::optional version instead")));
template<typename T>
status_t readTypedVector(std::vector<T>* val,
status_t(Parcel::*read_func)(T*) const) const;
@@ -573,13 +573,13 @@
status_t(Parcel::*write_func)(const T&));
template<typename T>
status_t writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&));
+ status_t(Parcel::*write_func)(const T&)) __attribute__((deprecated("use std::optional version instead")));
template<typename T>
status_t writeNullableTypedVector(const std::optional<std::vector<T>>& val,
status_t(Parcel::*write_func)(T));
template<typename T>
status_t writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T));
+ status_t(Parcel::*write_func)(T)) __attribute__((deprecated("use std::optional version instead")));
template<typename T>
status_t writeTypedVector(const std::vector<T>& val,
status_t(Parcel::*write_func)(const T&));
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 4ea3dd3..ce5027e 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -30,7 +30,7 @@
class ParcelableHolder : public android::Parcelable {
public:
ParcelableHolder() = delete;
- explicit ParcelableHolder(Stability stability) : mStability(stability){};
+ explicit ParcelableHolder(Stability stability) : mStability(stability){}
virtual ~ParcelableHolder() = default;
ParcelableHolder(const ParcelableHolder& other) {
mParcelable = other.mParcelable;
@@ -40,7 +40,7 @@
mParcelPtr->appendFrom(other.mParcelPtr.get(), 0, other.mParcelPtr->dataSize());
}
mStability = other.mStability;
- };
+ }
status_t writeToParcel(Parcel* parcel) const override;
status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 5e2e1bd..350c658 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -307,7 +307,8 @@
: onCreate(onCreate),
onDestroy(onDestroy),
onTransact(onTransact),
- mInterfaceDescriptor(interfaceDescriptor) {}
+ mInterfaceDescriptor(interfaceDescriptor),
+ mWideInterfaceDescriptor(interfaceDescriptor) {}
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
AIBinder_Class_onCreate onCreate,
@@ -335,6 +336,12 @@
clazz->handleShellCommand = handleShellCommand;
}
+const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) {
+ CHECK(clazz != nullptr) << "getDescriptor requires non-null clazz";
+
+ return clazz->getInterfaceDescriptorUtf8();
+}
+
void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
CHECK(who == mWho);
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 6236e81..6824306 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -112,7 +112,8 @@
AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact);
- const ::android::String16& getInterfaceDescriptor() const { return mInterfaceDescriptor; }
+ const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; }
+ const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); }
// required to be non-null, implemented for every class
const AIBinder_Class_onCreate onCreate = nullptr;
@@ -124,9 +125,11 @@
AIBinder_handleShellCommand handleShellCommand = nullptr;
private:
+ // Copy of the raw char string for when we don't have to return UTF-16
+ const std::string mInterfaceDescriptor;
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
// one.
- const ::android::String16 mInterfaceDescriptor;
+ const ::android::String16 mWideInterfaceDescriptor;
};
// Ownership is like this (when linked to death):
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index dfcf4dc..4858514 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -82,13 +82,13 @@
}
template <typename T>
- bool setParcelable(T* p) {
- if (p && this->mStability > T::_aidl_stability) {
+ bool setParcelable(const T& p) {
+ if (this->mStability > T::_aidl_stability) {
return false;
}
AParcel_reset(mParcel.get());
AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
- p->writeToParcel(mParcel.get());
+ p.writeToParcel(mParcel.get());
return true;
}
@@ -112,6 +112,8 @@
return std::move(ret);
}
+ void reset() { AParcel_reset(mParcel.get()); }
+
private:
mutable ndk::ScopedAParcel mParcel;
parcelable_stability_t mStability;
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index ce3d1db..5e1ed46 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -642,6 +642,23 @@
#endif //__ANDROID_API__ >= 30
+#if __ANDROID_API__ >= 31
+
+/**
+ * Retrieve the class descriptor for the class.
+ *
+ * Available since API level 31.
+ *
+ * \param clazz the class to fetch the descriptor from
+ *
+ * \return the class descriptor string. This pointer will never be null; a
+ * descriptor is required to define a class. The pointer is owned by the class
+ * and will remain valid as long as the class does.
+ */
+const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUCED_IN(31);
+
+#endif //__ANDROID_API__ >= 31
+
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 6962f86..e233ffd 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -121,6 +121,7 @@
AServiceManager_registerLazyService; # llndk
AServiceManager_waitForService; # apex llndk
+ AIBinder_Class_getDescriptor;
AParcel_appendFrom;
AParcel_create;
AParcel_getDataSize;
diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp
index a588985..2afe5d2 100644
--- a/libs/binder/ndk/tests/iface.cpp
+++ b/libs/binder/ndk/tests/iface.cpp
@@ -25,7 +25,7 @@
const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
-const char* kIFooDescriptor = "my-special-IFoo-class";
+const char* IFoo::kIFooDescriptor = "my-special-IFoo-class";
struct IFoo_Class_Data {
sp<IFoo> foo;
diff --git a/libs/binder/ndk/tests/include/iface/iface.h b/libs/binder/ndk/tests/include/iface/iface.h
index d9dd64b..7408d0c 100644
--- a/libs/binder/ndk/tests/include/iface/iface.h
+++ b/libs/binder/ndk/tests/include/iface/iface.h
@@ -27,6 +27,7 @@
public:
static const char* kSomeInstanceName;
static const char* kInstanceNameToDieFor;
+ static const char* kIFooDescriptor;
static AIBinder_Class* kClass;
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index f84d9d3..b7df115 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -39,6 +39,7 @@
#include <condition_variable>
#include <iostream>
#include <mutex>
+#include "android/binder_ibinder.h"
using namespace android;
@@ -543,6 +544,10 @@
EXPECT_EQ("CMD", shellCmdToString(testService, {"C", "M", "D"}));
}
+TEST(NdkBinder, GetClassInterfaceDescriptor) {
+ ASSERT_STREQ(IFoo::kIFooDescriptor, AIBinder_Class_getDescriptor(IFoo::kClass));
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/parcel_fuzzer/binder.cpp b/libs/binder/parcel_fuzzer/binder.cpp
index 96cd215..624def1 100644
--- a/libs/binder/parcel_fuzzer/binder.cpp
+++ b/libs/binder/parcel_fuzzer/binder.cpp
@@ -86,6 +86,8 @@
PARCEL_READ_WITH_STATUS(T, FUN), \
PARCEL_READ_NO_STATUS(T, FUN)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// clang-format off
std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
PARCEL_READ_NO_STATUS(size_t, dataSize),
@@ -296,3 +298,4 @@
PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
};
// clang-format on
+#pragma clang diagnostic pop
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index 09f58cc..2f9d85e 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -184,7 +184,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wexit-time-destructors"
-IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback");
+IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback")
#pragma clang diagnostic pop
class BnCallback : public SafeBnInterface<ICallback> {
@@ -373,7 +373,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wexit-time-destructors"
-IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest");
+IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest")
static sp<IBinder::DeathRecipient> getDeathRecipient() {
static sp<IBinder::DeathRecipient> recipient = new ExitOnDeath;
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index ab4c56a..56d958c 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -245,7 +245,7 @@
double best = (double)m_best / 1.0E6;
double worst = (double)m_worst / 1.0E6;
double average = (double)m_total_time / m_transactions / 1.0E6;
- // FIXME: libjson?
+ // TODO: libjson?
int W = DUMP_PRESICION + 2;
cout << setprecision(DUMP_PRESICION) << "{ \"avg\":" << setw(W) << left
<< average << ",\"wst\":" << setw(W) << left << worst
@@ -376,7 +376,7 @@
if (is_client(num)) {
int no_trans = iterations * 2;
double sync_ratio = (1.0 - (double)no_sync / no_trans);
- // FIXME: libjson?
+ // TODO: libjson?
cout << "\"P" << (num - server_count) << "\":{\"SYNC\":\""
<< ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
<< "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
@@ -466,7 +466,7 @@
}
vector<Pipe> pipes;
thread_dump("main");
- // FIXME: libjson?
+ // TODO: libjson?
cout << "{" << endl;
cout << "\"cfg\":{\"pair\":" << (no_process / 2)
<< ",\"iterations\":" << iterations << ",\"deadline_us\":" << deadline_us
@@ -495,7 +495,7 @@
// detected in the child process
no_inherent += status;
}
- // FIXME: libjson?
+ // TODO: libjson?
cout << "\"inheritance\": " << (no_inherent == 0 ? "\"PASS\"" : "\"FAIL\"")
<< endl;
cout << "}" << endl;
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index fb32382..eb8e57a 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -5,6 +5,7 @@
address: true,
},
srcs: [
+ "SmallMap_test.cpp",
"SmallVector_test.cpp",
"StaticVector_test.cpp",
],
diff --git a/libs/ftl/SmallMap_test.cpp b/libs/ftl/SmallMap_test.cpp
new file mode 100644
index 0000000..fa00c06
--- /dev/null
+++ b/libs/ftl/SmallMap_test.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2020 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 <ftl/SmallMap.h>
+#include <gtest/gtest.h>
+
+#include <cctype>
+
+namespace android::test {
+
+using ftl::SmallMap;
+
+// Keep in sync with example usage in header file.
+TEST(SmallMap, Example) {
+ ftl::SmallMap<int, std::string, 3> map;
+ EXPECT_TRUE(map.empty());
+ EXPECT_FALSE(map.dynamic());
+
+ map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_TRUE(map.contains(123));
+
+ EXPECT_EQ(map.find(42, [](const std::string& s) { return s.size(); }), 3u);
+
+ const auto opt = map.find(-1);
+ ASSERT_TRUE(opt);
+
+ std::string& ref = *opt;
+ EXPECT_TRUE(ref.empty());
+ ref = "xyz";
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
+}
+
+TEST(SmallMap, Construct) {
+ {
+ // Default constructor.
+ SmallMap<int, std::string, 2> map;
+
+ EXPECT_TRUE(map.empty());
+ EXPECT_FALSE(map.dynamic());
+ }
+ {
+ // In-place constructor with same types.
+ SmallMap<int, std::string, 5> map =
+ ftl::init::map<int, std::string>(123, "abc")(456, "def")(789, "ghi");
+
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_EQ(map.max_size(), 5u);
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(123, "abc")(456, "def")(789, "ghi")));
+ }
+ {
+ // In-place constructor with different types.
+ SmallMap<int, std::string, 5> map =
+ ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_EQ(map.max_size(), 5u);
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(42, "???")(123, "abc")(-1, "\0\0\0")));
+ }
+ {
+ // In-place constructor with implicit size.
+ SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+
+ static_assert(std::is_same_v<decltype(map), SmallMap<int, std::string, 3>>);
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_EQ(map.max_size(), 3u);
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "\0\0\0")(42, "???")(123, "abc")));
+ }
+}
+
+TEST(SmallMap, Find) {
+ {
+ // Constant reference.
+ const ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
+
+ const auto opt = map.find('b');
+ EXPECT_EQ(opt, 'B');
+
+ const char d = 'D';
+ const auto ref = map.find('d').value_or(std::cref(d));
+ EXPECT_EQ(ref.get(), 'D');
+ }
+ {
+ // Mutable reference.
+ ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
+
+ const auto opt = map.find('c');
+ EXPECT_EQ(opt, 'C');
+
+ char d = 'd';
+ const auto ref = map.find('d').value_or(std::ref(d));
+ ref.get() = 'D';
+ EXPECT_EQ(d, 'D');
+ }
+ {
+ // Constant unary operation.
+ const ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
+ EXPECT_EQ(map.find('c', [](char c) { return std::toupper(c); }), 'Z');
+ }
+ {
+ // Mutable unary operation.
+ ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
+ EXPECT_TRUE(map.find('c', [](char& c) { c = std::toupper(c); }));
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map('c', 'Z')('b', 'y')('a', 'x')));
+ }
+}
+
+} // namespace android::test
diff --git a/libs/ftl/SmallVector_test.cpp b/libs/ftl/SmallVector_test.cpp
index c41e622..d0c2858 100644
--- a/libs/ftl/SmallVector_test.cpp
+++ b/libs/ftl/SmallVector_test.cpp
@@ -52,6 +52,14 @@
vector = ftl::SmallVector(array);
EXPECT_EQ(vector, (ftl::SmallVector{'h', 'i', '\0'}));
EXPECT_FALSE(vector.dynamic());
+
+ ftl::SmallVector strings = ftl::init::list<std::string>("abc")("123456", 3u)(3u, '?');
+ ASSERT_EQ(strings.size(), 3u);
+ EXPECT_FALSE(strings.dynamic());
+
+ EXPECT_EQ(strings[0], "abc");
+ EXPECT_EQ(strings[1], "123");
+ EXPECT_EQ(strings[2], "???");
}
TEST(SmallVector, Construct) {
@@ -99,7 +107,8 @@
}
{
// In-place constructor with same types.
- SmallVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+ SmallVector vector =
+ ftl::init::list<std::string>("redolent", 3u)("velveteen", 6u)("cakewalk", 4u);
static_assert(std::is_same_v<decltype(vector), SmallVector<std::string, 3>>);
EXPECT_EQ(vector, (SmallVector{"red"s, "velvet"s, "cake"s}));
@@ -110,9 +119,10 @@
const auto copy = "red"s;
auto move = "velvet"s;
std::initializer_list<char> list = {'c', 'a', 'k', 'e'};
- SmallVector vector(std::in_place_type<std::string>, copy.c_str(), std::move(move), list);
+ SmallVector vector = ftl::init::list<std::string>(copy.c_str())(std::move(move))(list);
static_assert(std::is_same_v<decltype(vector), SmallVector<std::string, 3>>);
+ EXPECT_TRUE(move.empty());
EXPECT_EQ(vector, (SmallVector{"red"s, "velvet"s, "cake"s}));
EXPECT_FALSE(vector.dynamic());
}
@@ -206,9 +216,8 @@
}
TEST(SmallVector, MovableElement) {
- // Construct std::string elements in-place from C-style strings. Without std::in_place_type, the
- // element type would be deduced from the first element, i.e. const char*.
- SmallVector strings(std::in_place_type<std::string>, "", "", "", "cake", "velvet", "red", "");
+ // Construct std::string elements in place from per-element arguments.
+ SmallVector strings = ftl::init::list<std::string>()()()("cake")("velvet")("red")();
strings.pop_back();
EXPECT_EQ(strings.max_size(), 7u);
@@ -221,6 +230,7 @@
ASSERT_FALSE(it == strings.end());
EXPECT_EQ(*it, "cake");
+ // Construct std::string from first 4 characters of string literal.
strings.unstable_erase(it);
EXPECT_EQ(strings.emplace_back("cakewalk", 4u), "cake"s);
}
@@ -260,7 +270,7 @@
bool operator==(const Word& other) const { return other.str == str; }
};
- SmallVector words(std::in_place_type<Word>, "colored", "velour");
+ SmallVector words = ftl::init::list<Word>("colored")("velour");
// The replaced element can be referenced by the replacement.
{
@@ -301,7 +311,7 @@
}
TEST(SmallVector, Sort) {
- SmallVector strings(std::in_place_type<std::string>, "pie", "quince", "tart", "red", "velvet");
+ SmallVector strings = ftl::init::list<std::string>("pie")("quince")("tart")("red")("velvet");
strings.push_back("cake"s);
auto sorted = std::move(strings);
diff --git a/libs/ftl/StaticVector_test.cpp b/libs/ftl/StaticVector_test.cpp
index dd5ce35..db42d23 100644
--- a/libs/ftl/StaticVector_test.cpp
+++ b/libs/ftl/StaticVector_test.cpp
@@ -51,6 +51,13 @@
const char array[] = "hi";
vector = ftl::StaticVector(array);
EXPECT_EQ(vector, (ftl::StaticVector{'h', 'i', '\0'}));
+
+ ftl::StaticVector strings = ftl::init::list<std::string>("abc")("123456", 3u)(3u, '?');
+ ASSERT_EQ(strings.size(), 3u);
+
+ EXPECT_EQ(strings[0], "abc");
+ EXPECT_EQ(strings[1], "123");
+ EXPECT_EQ(strings[2], "???");
}
TEST(StaticVector, Construct) {
@@ -91,7 +98,8 @@
}
{
// In-place constructor with same types.
- StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+ StaticVector vector =
+ ftl::init::list<std::string>("redolent", 3u)("velveteen", 6u)("cakewalk", 4u);
static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
@@ -101,9 +109,10 @@
const auto copy = "red"s;
auto move = "velvet"s;
std::initializer_list<char> list = {'c', 'a', 'k', 'e'};
- StaticVector vector(std::in_place_type<std::string>, copy.c_str(), std::move(move), list);
+ StaticVector vector = ftl::init::list<std::string>(copy.c_str())(std::move(move))(list);
static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
+ EXPECT_TRUE(move.empty());
EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
}
{
@@ -204,9 +213,8 @@
}
TEST(StaticVector, MovableElement) {
- // Construct std::string elements in-place from C-style strings. Without std::in_place_type, the
- // element type would be deduced from the first element, i.e. const char*.
- StaticVector strings(std::in_place_type<std::string>, "", "", "", "cake", "velvet", "red", "");
+ // Construct std::string elements in place from per-element arguments.
+ StaticVector strings = ftl::init::list<std::string>()()()("cake")("velvet")("red")();
strings.pop_back();
EXPECT_EQ(strings.max_size(), 7u);
@@ -221,7 +229,7 @@
strings.unstable_erase(it);
- // Construct std::string from first 4 characters of C-style string.
+ // Construct std::string from first 4 characters of string literal.
it = strings.emplace_back("cakewalk", 4u);
ASSERT_NE(it, strings.end());
EXPECT_EQ(*it, "cake"s);
@@ -250,7 +258,7 @@
const std::string str;
};
- StaticVector words(std::in_place_type<Word>, "red", "velour", "cake");
+ StaticVector words = ftl::init::list<Word>("red")("velour")("cake");
// The replaced element can be referenced by the replacement.
const auto it = words.begin() + 1;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index a0e9cbf..af9ef06 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -237,6 +237,10 @@
"libnativebase_headers",
],
+ include_dirs: [
+ "frameworks/native/include",
+ ],
+
export_shared_lib_headers: [
"libEGL",
"libnativewindow",
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index abfee61..c6c9a8f 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -33,10 +33,10 @@
// using just a few large reads.
static const size_t EVENT_BUFFER_SIZE = 100;
-DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
- ISurfaceComposer::VsyncSource vsyncSource,
- ISurfaceComposer::ConfigChanged configChanged)
- : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
+DisplayEventDispatcher::DisplayEventDispatcher(
+ const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration)
+ : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
@@ -139,6 +139,7 @@
ssize_t n;
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
+ mFrameRateOverrides.reserve(n);
for (ssize_t i = 0; i < n; i++) {
const DisplayEventReceiver::Event& ev = buf[i];
switch (ev.header.type) {
@@ -162,6 +163,13 @@
case DisplayEventReceiver::DISPLAY_EVENT_NULL:
dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
break;
+ case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+ mFrameRateOverrides.emplace_back(ev.frameRateOverride);
+ break;
+ case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
+ dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId,
+ std::move(mFrameRateOverrides));
+ break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
break;
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index f2b0962..03b33c7 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -32,11 +32,12 @@
// ---------------------------------------------------------------------------
-DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource,
- ISurfaceComposer::ConfigChanged configChanged) {
+DisplayEventReceiver::DisplayEventReceiver(
+ ISurfaceComposer::VsyncSource vsyncSource,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr) {
- mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged);
+ mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
if (mEventConnection != nullptr) {
mDataChannel = std::make_unique<gui::BitTube>();
mEventConnection->stealReceiveChannel(mDataChannel.get());
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index a9fe5bf..e46a415 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -223,8 +223,8 @@
return NO_ERROR;
}
- virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource,
- ConfigChanged configChanged) {
+ virtual sp<IDisplayEventConnection> createDisplayEventConnection(
+ VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) {
Parcel data, reply;
sp<IDisplayEventConnection> result;
int err = data.writeInterfaceToken(
@@ -233,7 +233,7 @@
return result;
}
data.writeInt32(static_cast<int32_t>(vsyncSource));
- data.writeInt32(static_cast<int32_t>(configChanged));
+ data.writeUint32(eventRegistration.get());
err = remote()->transact(
BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
data, &reply);
@@ -1373,10 +1373,11 @@
case CREATE_DISPLAY_EVENT_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32());
- auto configChanged = static_cast<ISurfaceComposer::ConfigChanged>(data.readInt32());
+ EventRegistrationFlags eventRegistration =
+ static_cast<EventRegistration>(data.readUint32());
sp<IDisplayEventConnection> connection(
- createDisplayEventConnection(vsyncSource, configChanged));
+ createDisplayEventConnection(vsyncSource, eventRegistration));
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index c65618b..5587acf 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -19,6 +19,7 @@
#include <utils/Looper.h>
namespace android {
+using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
struct VsyncEventData {
// The Vsync Id corresponsing to this vsync event. This will be used to
@@ -36,8 +37,7 @@
explicit DisplayEventDispatcher(
const sp<Looper>& looper,
ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
- ISurfaceComposer::ConfigChanged configChanged =
- ISurfaceComposer::eConfigChangedSuppress);
+ ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
status_t initialize();
void dispose();
@@ -54,6 +54,8 @@
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
+ std::vector<FrameRateOverride> mFrameRateOverrides;
+
virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
VsyncEventData vsyncEventData) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
@@ -64,6 +66,9 @@
// can be properly poked.
virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
+ virtual void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
+ std::vector<FrameRateOverride> overrides) = 0;
+
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
uint32_t* outCount, VsyncEventData* outVsyncEventData);
};
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index df3118f..3191fc9 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -54,6 +54,8 @@
DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'),
DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
+ DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'),
+ DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'),
};
struct Event {
@@ -85,11 +87,17 @@
nsecs_t vsyncPeriod __attribute__((aligned(8)));
};
+ struct FrameRateOverride {
+ uid_t uid __attribute__((aligned(8)));
+ float frameRateHz __attribute__((aligned(8)));
+ };
+
Header header;
union {
VSync vsync;
Hotplug hotplug;
Config config;
+ FrameRateOverride frameRateOverride;
};
};
@@ -98,13 +106,12 @@
* DisplayEventReceiver creates and registers an event connection with
* SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
* or requestNextVsync to receive them.
- * To receive Config Changed events specify this in the constructor.
- * Other events start being delivered immediately.
+ * To receive ConfigChanged and/or FrameRateOverrides events specify this in
+ * the constructor. Other events start being delivered immediately.
*/
explicit DisplayEventReceiver(
ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
- ISurfaceComposer::ConfigChanged configChanged =
- ISurfaceComposer::eConfigChangedSuppress);
+ ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
/*
* ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 9e96b79..86e3a25 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -26,6 +26,8 @@
#include <gui/IScreenCaptureListener.h>
#include <gui/ITransactionCompletedListener.h>
+#include <input/Flags.h>
+
#include <math/vec4.h>
#include <ui/ConfigStoreTypes.h>
@@ -107,7 +109,12 @@
eVsyncSourceSurfaceFlinger = 1
};
- enum ConfigChanged { eConfigChangedSuppress = 0, eConfigChangedDispatch = 1 };
+ enum class EventRegistration {
+ configChanged = 1 << 0,
+ frameRateOverride = 1 << 1,
+ };
+
+ using EventRegistrationFlags = Flags<EventRegistration>;
// Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java
static constexpr int64_t INVALID_VSYNC_ID = -1;
@@ -120,7 +127,7 @@
/* return an IDisplayEventConnection */
virtual sp<IDisplayEventConnection> createDisplayEventConnection(
VsyncSource vsyncSource = eVsyncSourceApp,
- ConfigChanged configChanged = eConfigChangedSuppress) = 0;
+ EventRegistrationFlags eventRegistration = {}) = 0;
/* create a virtual display
* requires ACCESS_SURFACE_FLINGER permission.
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index 7210910..c5093e2 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -40,6 +40,9 @@
CHECK_OFFSET(DisplayEventReceiver::Event::Config, configId, 0);
CHECK_OFFSET(DisplayEventReceiver::Event::Config, vsyncPeriod, 8);
+
+ CHECK_OFFSET(DisplayEventReceiver::Event::FrameRateOverride, uid, 0);
+ CHECK_OFFSET(DisplayEventReceiver::Event::FrameRateOverride, frameRateHz, 8);
}
} // namespace android::test
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2392ae5..ce3afa2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -687,7 +687,7 @@
sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
sp<IDisplayEventConnection> createDisplayEventConnection(
- ISurfaceComposer::VsyncSource, ISurfaceComposer::ConfigChanged) override {
+ ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override {
return nullptr;
}
sp<IBinder> createDisplay(const String8& /*displayName*/,
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 9e515cd..6d91916 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -141,6 +141,8 @@
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
nsecs_t vsyncPeriod) override;
void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override;
+ void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
+ std::vector<FrameRateOverride> overrides) override;
void scheduleCallbacks();
@@ -175,8 +177,7 @@
}
Choreographer::Choreographer(const sp<Looper>& looper)
- : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp,
- ISurfaceComposer::ConfigChanged::eConfigChangedSuppress),
+ : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp),
mLooper(looper),
mThreadId(std::this_thread::get_id()) {
std::lock_guard<std::mutex> _l(gChoreographers.lock);
@@ -381,15 +382,13 @@
this, to_string(displayId).c_str(), toString(connected));
}
-// TODO(b/74619554): The PhysicalDisplayId is ignored because currently
-// Choreographer only supports dispatching VSYNC events for the internal
-// display, so as such Choreographer does not support the notion of multiple
-// displays. When multi-display choreographer is properly supported, then
-// PhysicalDisplayId should no longer be ignored.
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, int32_t configId,
- nsecs_t) {
- ALOGV("choreographer %p ~ received config change event (displayId=%s, configId=%d).",
- this, to_string(displayId).c_str(), configId);
+void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) {
+ LOG_ALWAYS_FATAL("dispatchConfigChanged was called but was never registered");
+}
+
+void Choreographer::dispatchFrameRateOverrides(nsecs_t, PhysicalDisplayId,
+ std::vector<FrameRateOverride>) {
+ LOG_ALWAYS_FATAL("dispatchFrameRateOverrides was called but was never registered");
}
void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) {
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index cd7f37b..b878150 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -31,6 +31,9 @@
"libui",
"libutils",
],
+ include_dirs: [
+ "external/skia/src/gpu",
+ ],
whole_static_libs: ["libskia"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
@@ -75,6 +78,7 @@
filegroup {
name: "librenderengine_skia_sources",
srcs: [
+ "skia/AutoBackendTexture.cpp",
"skia/SkiaRenderEngine.cpp",
"skia/SkiaGLRenderEngine.cpp",
"skia/filters/BlurFilter.cpp",
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index be83ebc..279e648 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -15,6 +15,7 @@
*/
//#define LOG_NDEBUG 0
+#include "EGL/egl.h"
#undef LOG_TAG
#define LOG_TAG "RenderEngine"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -446,19 +447,37 @@
mPlaceholderBuffer, attributes);
ALOGE_IF(mPlaceholderImage == EGL_NO_IMAGE_KHR, "Failed to create placeholder image: %#x",
eglGetError());
+
+ mShadowTexture = std::make_unique<GLShadowTexture>();
}
GLESRenderEngine::~GLESRenderEngine() {
// Destroy the image manager first.
mImageManager = nullptr;
+ mShadowTexture = nullptr;
cleanFramebufferCache();
+ ProgramCache::getInstance().purgeCaches();
std::lock_guard<std::mutex> lock(mRenderingMutex);
+ glDisableVertexAttribArray(Program::position);
unbindFrameBuffer(mDrawingBuffer.get());
mDrawingBuffer = nullptr;
eglDestroyImageKHR(mEGLDisplay, mPlaceholderImage);
mImageCache.clear();
+ if (mStubSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEGLDisplay, mStubSurface);
+ }
+ if (mProtectedStubSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEGLDisplay, mProtectedStubSurface);
+ }
+ if (mEGLContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEGLDisplay, mEGLContext);
+ }
+ if (mProtectedEGLContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEGLDisplay, mProtectedEGLContext);
+ }
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mEGLDisplay);
+ eglReleaseThread();
}
std::unique_ptr<Framebuffer> GLESRenderEngine::createFramebuffer() {
@@ -1800,7 +1819,7 @@
mState.cornerRadius = 0.0f;
mState.drawShadows = true;
- setupLayerTexturing(mShadowTexture.getTexture());
+ setupLayerTexturing(mShadowTexture->getTexture());
drawMesh(mesh);
mState.drawShadows = false;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index c0449a1..92e1529 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -193,7 +193,7 @@
GLuint mVpWidth;
GLuint mVpHeight;
Description mState;
- GLShadowTexture mShadowTexture;
+ std::unique_ptr<GLShadowTexture> mShadowTexture = nullptr;
mat4 mSrgbToXyz;
mat4 mDisplayP3ToXyz;
@@ -294,7 +294,7 @@
friend class BlurFilter;
friend class GenericProgram;
std::unique_ptr<FlushTracer> mFlushTracer;
- std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
+ std::unique_ptr<ImageManager> mImageManager;
};
} // namespace gl
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 383486b..58d6caa 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -38,6 +38,7 @@
}
GLFramebuffer::~GLFramebuffer() {
+ setNativeWindowBuffer(nullptr, false, false);
glDeleteFramebuffers(1, &mFramebufferName);
glDeleteTextures(1, &mTextureName);
}
diff --git a/libs/renderengine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp
index a172c56..26f6166 100644
--- a/libs/renderengine/gl/Program.cpp
+++ b/libs/renderengine/gl/Program.cpp
@@ -82,6 +82,14 @@
}
}
+Program::~Program() {
+ glDetachShader(mProgram, mVertexShader);
+ glDetachShader(mProgram, mFragmentShader);
+ glDeleteShader(mVertexShader);
+ glDeleteShader(mFragmentShader);
+ glDeleteProgram(mProgram);
+}
+
bool Program::isValid() const {
return mInitialized;
}
diff --git a/libs/renderengine/gl/Program.h b/libs/renderengine/gl/Program.h
index 4292645..41f1bf8 100644
--- a/libs/renderengine/gl/Program.h
+++ b/libs/renderengine/gl/Program.h
@@ -54,7 +54,7 @@
};
Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
- ~Program() = default;
+ ~Program();
/* whether this object is usable */
bool isValid() const;
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index 37bb651..535d21c 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -203,6 +203,8 @@
// if none can be found.
void useProgram(const EGLContext context, const Description& description);
+ void purgeCaches() { mCaches.clear(); }
+
private:
// compute a cache Key from a Description
static Key computeKey(const Description& description);
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
new file mode 100644
index 0000000..d126c27
--- /dev/null
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 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 "AutoBackendTexture.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <utils/Trace.h>
+
+#include "log/log_main.h"
+#include "utils/Trace.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+// Converts an android dataspace to a supported SkColorSpace
+// Supported dataspaces are
+// 1. sRGB
+// 2. Display P3
+// 3. BT2020 PQ
+// 4. BT2020 HLG
+// Unknown primaries are mapped to BT709, and unknown transfer functions
+// are mapped to sRGB.
+static sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) {
+ skcms_Matrix3x3 gamut;
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ gamut = SkNamedGamut::kSRGB;
+ break;
+ case HAL_DATASPACE_STANDARD_BT2020:
+ gamut = SkNamedGamut::kRec2020;
+ break;
+ case HAL_DATASPACE_STANDARD_DCI_P3:
+ gamut = SkNamedGamut::kDisplayP3;
+ break;
+ default:
+ ALOGV("Unsupported Gamut: %d, defaulting to sRGB", dataspace);
+ gamut = SkNamedGamut::kSRGB;
+ break;
+ }
+
+ switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_LINEAR:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
+ case HAL_DATASPACE_TRANSFER_SRGB:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ case HAL_DATASPACE_TRANSFER_HLG:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
+ default:
+ ALOGV("Unsupported Gamma: %d, defaulting to sRGB transfer", dataspace);
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ }
+}
+
+AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer,
+ bool isRender) {
+ AHardwareBuffer_Desc desc;
+ AHardwareBuffer_describe(buffer, &desc);
+ bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
+ GrBackendFormat backendFormat =
+ GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false);
+ mBackendTexture =
+ GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height,
+ &mDeleteProc, &mUpdateProc, &mImageCtx,
+ createProtectedImage, backendFormat,
+ isRender);
+ mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
+}
+
+void AutoBackendTexture::unref(bool releaseLocalResources) {
+ if (releaseLocalResources) {
+ mSurface = nullptr;
+ mImage = nullptr;
+ }
+
+ mUsageCount--;
+ if (mUsageCount <= 0) {
+ if (mBackendTexture.isValid()) {
+ mDeleteProc(mImageCtx);
+ mBackendTexture = {};
+ }
+ delete this;
+ }
+}
+
+// releaseSurfaceProc is invoked by SkSurface, when the texture is no longer in use.
+// "releaseContext" contains an "AutoBackendTexture*".
+void AutoBackendTexture::releaseSurfaceProc(SkSurface::ReleaseContext releaseContext) {
+ AutoBackendTexture* textureRelease = reinterpret_cast<AutoBackendTexture*>(releaseContext);
+ textureRelease->unref(false);
+}
+
+// releaseImageProc is invoked by SkImage, when the texture is no longer in use.
+// "releaseContext" contains an "AutoBackendTexture*".
+void AutoBackendTexture::releaseImageProc(SkImage::ReleaseContext releaseContext) {
+ AutoBackendTexture* textureRelease = reinterpret_cast<AutoBackendTexture*>(releaseContext);
+ textureRelease->unref(false);
+}
+
+sk_sp<SkImage> AutoBackendTexture::makeImage(ui::Dataspace dataspace, SkAlphaType alphaType,
+ GrDirectContext* context) {
+ ATRACE_CALL();
+
+ if (mBackendTexture.isValid()) {
+ mUpdateProc(mImageCtx, context);
+ }
+
+ sk_sp<SkImage> image =
+ SkImage::MakeFromTexture(context, mBackendTexture, kTopLeft_GrSurfaceOrigin, mColorType,
+ alphaType, toSkColorSpace(dataspace), releaseImageProc, this);
+ if (image.get()) {
+ // The following ref will be counteracted by releaseProc, when SkImage is discarded.
+ ref();
+ }
+
+ mImage = image;
+ mDataspace = dataspace;
+ LOG_ALWAYS_FATAL_IF(mImage == nullptr, "Unable to generate SkImage from buffer");
+ return mImage;
+}
+
+sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace,
+ GrDirectContext* context) {
+ ATRACE_CALL();
+ if (!mSurface.get() || mDataspace != dataspace) {
+ sk_sp<SkSurface> surface =
+ SkSurface::MakeFromBackendTexture(context, mBackendTexture,
+ kTopLeft_GrSurfaceOrigin, 0, mColorType,
+ toSkColorSpace(dataspace), nullptr,
+ releaseSurfaceProc, this);
+ if (surface.get()) {
+ // The following ref will be counteracted by releaseProc, when SkSurface is discarded.
+ ref();
+ }
+ mSurface = surface;
+ }
+
+ mDataspace = dataspace;
+ LOG_ALWAYS_FATAL_IF(mSurface == nullptr, "Unable to generate SkSurface");
+ return mSurface;
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
new file mode 100644
index 0000000..30f4b77
--- /dev/null
+++ b/libs/renderengine/skia/AutoBackendTexture.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 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 <GrAHardwareBufferUtils.h>
+#include <GrDirectContext.h>
+#include <SkImage.h>
+#include <SkSurface.h>
+#include <sys/types.h>
+
+#include "android-base/macros.h"
+#include "ui/GraphicTypes.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+/**
+ * AutoBackendTexture manages GPU image lifetime. It is a ref-counted object
+ * that keeps GPU resources alive until the last SkImage or SkSurface object using them is
+ * destroyed.
+ */
+class AutoBackendTexture {
+public:
+ // Local reference that supports RAII-style management of an AutoBackendTexture
+ // AutoBackendTexture by itself can't be managed in a similar fashion because
+ // of shared ownership with Skia objects, so we wrap it here instead.
+ class LocalRef {
+ public:
+ LocalRef() {}
+
+ ~LocalRef() {
+ // Destroying the texture is the same as setting it to null
+ setTexture(nullptr);
+ }
+
+ // Sets the texture to locally ref-track.
+ void setTexture(AutoBackendTexture* texture) {
+ if (mTexture != nullptr) {
+ mTexture->unref(true);
+ }
+
+ mTexture = texture;
+ if (mTexture != nullptr) {
+ mTexture->ref();
+ }
+ }
+
+ AutoBackendTexture* getTexture() const { return mTexture; }
+
+ DISALLOW_COPY_AND_ASSIGN(LocalRef);
+
+ private:
+ AutoBackendTexture* mTexture = nullptr;
+ };
+
+ // Creates a GrBackendTexture whose contents come from the provided buffer.
+ AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isRender);
+
+ void ref() { mUsageCount++; }
+
+ // releaseLocalResources is true if the underlying SkImage and SkSurface
+ // should be deleted from local tracking.
+ void unref(bool releaseLocalResources);
+
+ // Makes a new SkImage from the texture content.
+ // As SkImages are immutable but buffer content is not, we create
+ // a new SkImage every time.
+ sk_sp<SkImage> makeImage(ui::Dataspace dataspace, SkAlphaType alphaType,
+ GrDirectContext* context);
+
+ // Makes a new SkSurface from the texture content, if needed.
+ sk_sp<SkSurface> getOrCreateSurface(ui::Dataspace dataspace, GrDirectContext* context);
+
+private:
+ // The only way to invoke dtor is with unref, when mUsageCount is 0.
+ ~AutoBackendTexture() {}
+
+ GrBackendTexture mBackendTexture;
+ GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
+ GrAHardwareBufferUtils::UpdateImageProc mUpdateProc;
+ GrAHardwareBufferUtils::TexImageCtx mImageCtx;
+
+ static void releaseSurfaceProc(SkSurface::ReleaseContext releaseContext);
+ static void releaseImageProc(SkImage::ReleaseContext releaseContext);
+
+ int mUsageCount = 0;
+
+ sk_sp<SkImage> mImage = nullptr;
+ sk_sp<SkSurface> mSurface = nullptr;
+ ui::Dataspace mDataspace = ui::Dataspace::UNKNOWN;
+ SkColorType mColorType = kUnknown_SkColorType;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 07be0b6..a0660fb 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -16,8 +16,10 @@
//#define LOG_NDEBUG 0
#include <cstdint>
+#include <memory>
#include "SkImageInfo.h"
+#include "log/log_main.h"
#include "system/graphics-base-v1.0.h"
#undef LOG_TAG
#define LOG_TAG "RenderEngine"
@@ -145,47 +147,6 @@
return err;
}
-// Converts an android dataspace to a supported SkColorSpace
-// Supported dataspaces are
-// 1. sRGB
-// 2. Display P3
-// 3. BT2020 PQ
-// 4. BT2020 HLG
-// Unknown primaries are mapped to BT709, and unknown transfer functions
-// are mapped to sRGB.
-static sk_sp<SkColorSpace> toColorSpace(ui::Dataspace dataspace) {
- skcms_Matrix3x3 gamut;
- switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
- case HAL_DATASPACE_STANDARD_BT709:
- gamut = SkNamedGamut::kSRGB;
- break;
- case HAL_DATASPACE_STANDARD_BT2020:
- gamut = SkNamedGamut::kRec2020;
- break;
- case HAL_DATASPACE_STANDARD_DCI_P3:
- gamut = SkNamedGamut::kDisplayP3;
- break;
- default:
- ALOGV("Unsupported Gamut: %d, defaulting to sRGB", dataspace);
- gamut = SkNamedGamut::kSRGB;
- break;
- }
-
- switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_LINEAR:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
- case HAL_DATASPACE_TRANSFER_SRGB:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
- case HAL_DATASPACE_TRANSFER_ST2084:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
- case HAL_DATASPACE_TRANSFER_HLG:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
- default:
- ALOGV("Unsupported Gamma: %d, defaulting to sRGB transfer", dataspace);
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
- }
-}
-
std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create(
const RenderEngineCreationArgs& args) {
// initialize EGL for the default display
@@ -455,9 +416,15 @@
sourceTransfer != destTransfer;
}
+static bool needsLinearEffect(const mat4& colorTransform, ui::Dataspace sourceDataspace,
+ ui::Dataspace destinationDataspace) {
+ return colorTransform != mat4() || needsToneMapping(sourceDataspace, destinationDataspace);
+}
+
void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
std::lock_guard<std::mutex> lock(mRenderingMutex);
- mImageCache.erase(bufferId);
+ mTextureCache.erase(bufferId);
+ mProtectedTextureCache.erase(bufferId);
}
status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
@@ -486,36 +453,36 @@
}
auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext;
- auto& cache = mInProtectedContext ? mProtectedSurfaceCache : mSurfaceCache;
+ auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache;
AHardwareBuffer_Desc bufferDesc;
AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc);
LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE),
"missing usage");
- sk_sp<SkSurface> surface;
+ std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef = nullptr;
if (useFramebufferCache) {
auto iter = cache.find(buffer->getId());
if (iter != cache.end()) {
ALOGV("Cache hit!");
- surface = iter->second;
+ surfaceTextureRef = iter->second;
}
}
- if (!surface) {
- surface = SkSurface::MakeFromAHardwareBuffer(grContext.get(), buffer->toAHardwareBuffer(),
- GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
- mUseColorManagement
- ? toColorSpace(display.outputDataspace)
- : SkColorSpace::MakeSRGB(),
- nullptr);
- if (useFramebufferCache && surface) {
+
+ if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) {
+ surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
+ surfaceTextureRef->setTexture(
+ new AutoBackendTexture(mGrContext.get(), buffer->toAHardwareBuffer(), true));
+ if (useFramebufferCache) {
ALOGD("Adding to cache");
- cache.insert({buffer->getId(), surface});
+ cache.insert({buffer->getId(), surfaceTextureRef});
}
}
- if (!surface) {
- ALOGE("Failed to make surface");
- return BAD_VALUE;
- }
+
+ sk_sp<SkSurface> surface =
+ surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement
+ ? display.outputDataspace
+ : ui::Dataspace::SRGB,
+ mGrContext.get());
auto canvas = surface->getCanvas();
// Clear the entire canvas with a transparent black to prevent ghost images.
@@ -586,28 +553,37 @@
const auto& item = layer->source.buffer;
const auto bufferWidth = item.buffer->getBounds().width();
const auto bufferHeight = item.buffer->getBounds().height();
- sk_sp<SkImage> image;
- auto iter = mImageCache.find(item.buffer->getId());
- if (iter != mImageCache.end()) {
- image = iter->second;
+ std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
+ auto iter = mTextureCache.find(item.buffer->getId());
+ if (iter != mTextureCache.end()) {
+ imageTextureRef = iter->second;
} else {
- image = SkImage::MakeFromAHardwareBuffer(
- item.buffer->toAHardwareBuffer(),
- item.isOpaque ? kOpaque_SkAlphaType
- : (item.usePremultipliedAlpha ? kPremul_SkAlphaType
- : kUnpremul_SkAlphaType),
- mUseColorManagement
- ? (needsToneMapping(layer->sourceDataspace, display.outputDataspace)
- // If we need to map to linear space, then
- // mark the source image with the same
- // colorspace as the destination surface so
- // that Skia's color management is a no-op.
- ? toColorSpace(display.outputDataspace)
- : toColorSpace(layer->sourceDataspace))
- : SkColorSpace::MakeSRGB());
- mImageCache.insert({item.buffer->getId(), image});
+ imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
+ imageTextureRef->setTexture(new AutoBackendTexture(mGrContext.get(),
+ item.buffer->toAHardwareBuffer(),
+ false));
+ mTextureCache.insert({buffer->getId(), imageTextureRef});
}
+ sk_sp<SkImage> image =
+ imageTextureRef->getTexture()
+ ->makeImage(mUseColorManagement
+ ? (needsLinearEffect(layer->colorTransform,
+ layer->sourceDataspace,
+ display.outputDataspace)
+ // If we need to map to linear space,
+ // then mark the source image with the
+ // same colorspace as the destination
+ // surface so that Skia's color
+ // management is a no-op.
+ ? display.outputDataspace
+ : layer->sourceDataspace)
+ : ui::Dataspace::SRGB,
+ item.isOpaque ? kOpaque_SkAlphaType
+ : (item.usePremultipliedAlpha
+ ? kPremul_SkAlphaType
+ : kUnpremul_SkAlphaType),
+ mGrContext.get());
SkMatrix matrix;
if (layer->geometry.roundedCornersRadius > 0) {
const auto roundedRect = getRoundedRect(layer);
@@ -652,22 +628,44 @@
matrix.postConcat(texMatrix);
matrix.postScale(rotatedBufferWidth, rotatedBufferHeight);
- sk_sp<SkShader> shader = image->makeShader(matrix);
+ sk_sp<SkShader> shader;
+
+ if (layer->source.buffer.useTextureFiltering) {
+ shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
+ SkSamplingOptions(
+ {SkFilterMode::kLinear, SkMipmapMode::kNone}),
+ &matrix);
+ } else {
+ shader = image->makeShader(matrix);
+ }
if (mUseColorManagement &&
- needsToneMapping(layer->sourceDataspace, display.outputDataspace)) {
+ needsLinearEffect(layer->colorTransform, layer->sourceDataspace,
+ display.outputDataspace)) {
LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace,
.outputDataspace = display.outputDataspace,
.undoPremultipliedAlpha = !item.isOpaque &&
item.usePremultipliedAlpha};
- sk_sp<SkRuntimeEffect> runtimeEffect = buildRuntimeEffect(effect);
+
+ auto effectIter = mRuntimeEffects.find(effect);
+ sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
+ if (effectIter == mRuntimeEffects.end()) {
+ runtimeEffect = buildRuntimeEffect(effect);
+ mRuntimeEffects.insert({effect, runtimeEffect});
+ } else {
+ runtimeEffect = effectIter->second;
+ }
+
paint.setShader(createLinearEffectShader(shader, effect, runtimeEffect,
+ layer->colorTransform,
display.maxLuminance,
layer->source.buffer.maxMasteringLuminance,
layer->source.buffer.maxContentLuminance));
} else {
paint.setShader(shader);
}
+ // Make sure to take into the account the alpha set on the layer.
+ paint.setAlphaf(layer->alpha);
} else {
ATRACE_NAME("DrawColor");
const auto color = layer->source.solidColor;
@@ -910,10 +908,7 @@
return eglCreatePbufferSurface(display, placeholderConfig, attributes.data());
}
-void SkiaGLRenderEngine::cleanFramebufferCache() {
- mSurfaceCache.clear();
- mProtectedSurfaceCache.clear();
-}
+void SkiaGLRenderEngine::cleanFramebufferCache() {}
} // namespace skia
} // namespace renderengine
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 965cb41..f5eed1e 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -29,9 +29,13 @@
#include <mutex>
#include <unordered_map>
+#include "AutoBackendTexture.h"
#include "EGL/egl.h"
+#include "SkImageInfo.h"
#include "SkiaRenderEngine.h"
+#include "android-base/macros.h"
#include "filters/BlurFilter.h"
+#include "skia/filters/LinearEffect.h"
namespace android {
namespace renderengine {
@@ -92,8 +96,12 @@
const bool mUseColorManagement;
- // Cache of GL images that we'll store per GraphicBuffer ID
- std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex);
+ // Cache of GL textures that we'll store per GraphicBuffer ID
+ std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
+ GUARDED_BY(mRenderingMutex);
+ std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>>
+ mProtectedTextureCache GUARDED_BY(mRenderingMutex);
+ std::unordered_map<LinearEffect, sk_sp<SkRuntimeEffect>, LinearEffectHasher> mRuntimeEffects;
// Mutex guarding rendering operations, so that:
// 1. GL operations aren't interleaved, and
// 2. Internal state related to rendering that is potentially modified by
@@ -107,8 +115,6 @@
// Same as above, but for protected content (eg. DRM)
sk_sp<GrDirectContext> mProtectedGrContext;
- std::unordered_map<uint64_t, sk_sp<SkSurface>> mSurfaceCache;
- std::unordered_map<uint64_t, sk_sp<SkSurface>> mProtectedSurfaceCache;
bool mInProtectedContext = false;
};
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index a514825..f19b64a 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "BlurFilter.h"
#include <SkCanvas.h>
#include <SkData.h>
@@ -38,11 +40,11 @@
half4 main(float2 xy) {
float2 scaled_xy = float2(xy.x * in_inverseScale, xy.y * in_inverseScale);
- float4 c = float4(sample(input, scaled_xy));
- c += float4(sample(input, scaled_xy + float2( in_blurOffset.x, in_blurOffset.y)));
- c += float4(sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y)));
- c += float4(sample(input, scaled_xy + float2(-in_blurOffset.x, in_blurOffset.y)));
- c += float4(sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y)));
+ half4 c = sample(input, scaled_xy);
+ c += sample(input, scaled_xy + float2( in_blurOffset.x, in_blurOffset.y));
+ c += sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y));
+ c += sample(input, scaled_xy + float2(-in_blurOffset.x, in_blurOffset.y));
+ c += sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y));
return half4(c.rgb * 0.2, 1.0);
}
@@ -57,8 +59,6 @@
sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
const uint32_t blurRadius, SkRect rect) const {
- ATRACE_CALL();
-
// Kawase is an approximation of Gaussian, but it behaves differently from it.
// A radius transformation is required for approximating them, and also to introduce
// non-integer steps, necessary to smoothly interpolate large radii.
@@ -77,7 +77,7 @@
const float stepY = radiusByPasses;
// start by drawing and downscaling and doing the first blur pass
- SkFilterOptions linear = {SkSamplingMode::kLinear, SkMipmapMode::kNone};
+ SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
blurBuilder.child("input") =
input->makeImageSnapshot()->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
@@ -126,12 +126,16 @@
}
lastDrawTarget = readSurface;
}
- lastDrawTarget->flushAndSubmit();
+
+ {
+ ATRACE_NAME("Flush Offscreen Surfaces");
+ lastDrawTarget->flushAndSubmit();
+ }
return lastDrawTarget;
}
SkMatrix BlurFilter::getShaderMatrix() const {
- return SkMatrix::MakeScale(kInverseInputScale);
+ return SkMatrix::Scale(kInverseInputScale, kInverseInputScale);
}
} // namespace skia
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 376abdf..7680649 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -16,12 +16,16 @@
#include "LinearEffect.h"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <SkString.h>
+#include <utils/Trace.h>
#include <optional>
#include "log/log.h"
#include "math/mat4.h"
+#include "system/graphics-base-v1.0.h"
#include "ui/ColorSpace.h"
namespace android {
@@ -46,6 +50,30 @@
}
)");
break;
+ case HAL_DATASPACE_TRANSFER_HLG:
+ shader.append(R"(
+ float EOTF_channel(float channel) {
+ const float a = 0.17883277;
+ const float b = 0.28466892;
+ const float c = 0.55991073;
+ return channel <= 0.5 ? channel * channel / 3.0 :
+ (exp((channel - c) / a) + b) / 12.0;
+ }
+
+ float3 EOTF(float3 color) {
+ return float3(EOTF_channel(color.r), EOTF_channel(color.g),
+ EOTF_channel(color.b));
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_LINEAR:
+ shader.append(R"(
+ float3 EOTF(float3 color) {
+ return color;
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_SRGB:
default:
shader.append(R"(
@@ -79,13 +107,8 @@
)");
}
-static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
- SkString& shader) {
- shader.append(R"(
- uniform float in_displayMaxLuminance;
- uniform float in_inputMaxLuminance;
- uniform float in_maxContentLuminance;
- )");
+// Conversion from relative light to absolute light (maps from [0, 1] to [0, maxNits])
+static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, SkString& shader) {
switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
shader.append(R"(
@@ -93,9 +116,50 @@
return xyz * 10000.0;
}
)");
+ break;
+ case HAL_DATASPACE_TRANSFER_HLG:
+ shader.append(R"(
+ float3 ScaleLuminance(float3 xyz) {
+ return xyz * 1000.0 * pow(xyz.y, 0.2);
+ }
+ )");
+ break;
+ default:
+ shader.append(R"(
+ float3 ScaleLuminance(float3 xyz) {
+ return xyz * in_displayMaxLuminance;
+ }
+ )");
+ break;
+ }
+}
+static void generateToneMapInterpolation(ui::Dataspace inputDataspace,
+ ui::Dataspace outputDataspace, SkString& shader) {
+ switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ case HAL_DATASPACE_TRANSFER_HLG:
switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ shader.append(R"(
+ float3 ToneMap(float3 xyz) {
+ return xyz;
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_HLG:
+ // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
+ // we'll clamp the luminance range in case we're mapping from PQ input to HLG
+ // output.
+ shader.append(R"(
+ float3 ToneMap(float3 xyz) {
+ return clamp(xyz, 0.0, 1000.0);
+ }
+ )");
+ break;
default:
+ // Here we're mapping from HDR to SDR content, so interpolate using a Hermitian
+ // polynomial onto the smaller luminance range.
shader.append(R"(
float3 ToneMap(float3 xyz) {
float maxInLumi = in_inputMaxLuminance;
@@ -155,18 +219,70 @@
}
break;
default:
- shader.append(R"(
- float3 ScaleLuminance(float3 xyz) {
- return xyz * in_displayMaxLuminance;
- }
+ switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ case HAL_DATASPACE_TRANSFER_HLG:
+ // Map from SDR onto an HDR output buffer
+ // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto
+ // [0, maxOutLumi] which is hard-coded to be 3000 nits.
+ shader.append(R"(
+ float3 ToneMap(float3 xyz) {
+ const float maxOutLumi = 3000.0;
- float3 ToneMap(float3 xyz) {
- return xyz;
- }
- )");
+ const float x0 = 5.0;
+ const float y0 = 2.5;
+ float x1 = in_displayMaxLuminance * 0.7;
+ float y1 = maxOutLumi * 0.15;
+ float x2 = in_displayMaxLuminance * 0.9;
+ float y2 = maxOutLumi * 0.45;
+ float x3 = in_displayMaxLuminance;
+ float y3 = maxOutLumi;
+
+ float c1 = y1 / 3.0;
+ float c2 = y2 / 2.0;
+ float c3 = y3 / 1.5;
+
+ float nits = xyz.y;
+
+ if (nits <= x0) {
+ // scale [0.0, x0] to [0.0, y0] linearly
+ float slope = y0 / x0;
+ return xyz * slope;
+ } else if (nits <= x1) {
+ // scale [x0, x1] to [y0, y1] using a curve
+ float t = (nits - x0) / (x1 - x0);
+ nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1;
+ } else if (nits <= x2) {
+ // scale [x1, x2] to [y1, y2] using a curve
+ float t = (nits - x1) / (x2 - x1);
+ nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2;
+ } else {
+ // scale [x2, x3] to [y2, y3] using a curve
+ float t = (nits - x2) / (x3 - x2);
+ nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3;
+ }
+
+ // xyz.y is greater than x0 and is thus non-zero
+ return xyz * (nits / xyz.y);
+ }
+ )");
+ break;
+ default:
+ // For completeness, this is tone-mapping from SDR to SDR, where this is just a
+ // no-op.
+ shader.append(R"(
+ float3 ToneMap(float3 xyz) {
+ return xyz;
+ }
+ )");
+ break;
+ }
break;
}
+}
+// Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1])
+static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, SkString& shader) {
switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
shader.append(R"(
@@ -175,6 +291,13 @@
}
)");
break;
+ case HAL_DATASPACE_TRANSFER_HLG:
+ shader.append(R"(
+ float3 NormalizeLuminance(float3 xyz) {
+ return xyz / 1000.0 * pow(xyz.y / 1000.0, -0.2 / 1.2);
+ }
+ )");
+ break;
default:
shader.append(R"(
float3 NormalizeLuminance(float3 xyz) {
@@ -183,6 +306,19 @@
)");
break;
}
+}
+
+static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
+ SkString& shader) {
+ // Input uniforms
+ shader.append(R"(
+ uniform float in_displayMaxLuminance;
+ uniform float in_inputMaxLuminance;
+ )");
+
+ generateLuminanceScalesForOOTF(inputDataspace, shader);
+ generateToneMapInterpolation(inputDataspace, outputDataspace, shader);
+ generateLuminanceNormalizationForOOTF(outputDataspace, shader);
shader.append(R"(
float3 OOTF(float3 xyz) {
@@ -209,6 +345,30 @@
}
)");
break;
+ case HAL_DATASPACE_TRANSFER_HLG:
+ shader.append(R"(
+ float OETF_channel(float channel) {
+ const float a = 0.17883277;
+ const float b = 0.28466892;
+ const float c = 0.55991073;
+ return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
+ a * log(12.0 * channel - b) + c;
+ }
+
+ float3 OETF(float3 linear) {
+ return float3(OETF_channel(linear.r), OETF_channel(linear.g),
+ OETF_channel(linear.b));
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_LINEAR:
+ shader.append(R"(
+ float3 OETF(float3 linear) {
+ return linear;
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_SRGB:
default:
shader.append(R"(
float OETF_sRGB(float linear) {
@@ -270,6 +430,7 @@
}
sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect) {
+ ATRACE_CALL();
SkString shaderString;
generateEOTF(linearEffect.inputDataspace, shaderString);
generateXYZTransforms(shaderString);
@@ -286,8 +447,9 @@
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
- float maxDisplayLuminance, float maxMasteringLuminance,
- float maxContentLuminance) {
+ const mat4& colorTransform, float maxDisplayLuminance,
+ float maxMasteringLuminance, float maxContentLuminance) {
+ ATRACE_CALL();
SkRuntimeShaderBuilder effectBuilder(runtimeEffect);
effectBuilder.child("input") = shader;
@@ -296,7 +458,7 @@
ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ());
- effectBuilder.uniform("in_xyzToRgb") = mat4(outputColorSpace.getXYZtoRGB());
+ effectBuilder.uniform("in_xyzToRgb") = colorTransform * mat4(outputColorSpace.getXYZtoRGB());
effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance;
effectBuilder.uniform("in_inputMaxLuminance") =
std::min(maxMasteringLuminance, maxContentLuminance);
diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h
index 2615669..20b8338 100644
--- a/libs/renderengine/skia/filters/LinearEffect.h
+++ b/libs/renderengine/skia/filters/LinearEffect.h
@@ -16,9 +16,10 @@
#pragma once
+#include <math/mat4.h>
+
#include <optional>
-#include "SkColorMatrix.h"
#include "SkRuntimeEffect.h"
#include "SkShader.h"
#include "ui/GraphicTypes.h"
@@ -63,11 +64,31 @@
const bool undoPremultipliedAlpha = false;
};
+static inline bool operator==(const LinearEffect& lhs, const LinearEffect& rhs) {
+ return lhs.inputDataspace == rhs.inputDataspace && lhs.outputDataspace == rhs.outputDataspace &&
+ lhs.undoPremultipliedAlpha == rhs.undoPremultipliedAlpha;
+}
+
+struct LinearEffectHasher {
+ // Inspired by art/runtime/class_linker.cc
+ // Also this is what boost:hash_combine does
+ static size_t HashCombine(size_t seed, size_t val) {
+ return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2));
+ }
+ size_t operator()(const LinearEffect& le) const {
+ size_t result = std::hash<ui::Dataspace>{}(le.inputDataspace);
+ result = HashCombine(result, std::hash<ui::Dataspace>{}(le.outputDataspace));
+ return HashCombine(result, std::hash<bool>{}(le.undoPremultipliedAlpha));
+ }
+};
+
sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect);
// Generates a shader resulting from applying the a linear effect created from
-// LinearEffectARgs::buildEffect to an inputShader. We also provide additional HDR metadata upon
-// creating the shader:
+// LinearEffectArgs::buildEffect to an inputShader.
+// Optionally, a color transform may also be provided, which combines with the
+// matrix transforming from linear XYZ to linear RGB immediately before OETF.
+// We also provide additional HDR metadata upon creating the shader:
// * The max display luminance is the max luminance of the physical display in nits
// * The max mastering luminance is provided as the max luminance from the SMPTE 2086
// standard.
@@ -76,8 +97,8 @@
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader,
const LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
- float maxDisplayLuminance, float maxMasteringLuminance,
- float maxContentLuminance);
+ const mat4& colorTransform, float maxDisplayLuminance,
+ float maxMasteringLuminance, float maxContentLuminance);
} // namespace skia
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index d20fcc4..0e11c99 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#undef LOG_TAG
+#define LOG_TAG "RenderEngineTest"
+
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
@@ -37,8 +40,19 @@
namespace android {
-struct RenderEngineTest : public ::testing::Test {
- static void SetUpTestSuite() {
+class RenderEngineFactory {
+public:
+ virtual ~RenderEngineFactory() = default;
+
+ virtual std::string name() = 0;
+ virtual std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() = 0;
+};
+
+class GLESRenderEngineFactory : public RenderEngineFactory {
+public:
+ std::string name() override { return "GLESRenderEngineFactory"; }
+
+ std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
renderengine::RenderEngineCreationArgs reCreationArgs =
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -50,20 +64,32 @@
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
.setRenderEngineType(renderengine::RenderEngine::RenderEngineType::GLES)
.build();
- sRE = renderengine::gl::GLESRenderEngine::create(reCreationArgs);
-
- reCreationArgs.useColorManagement = true;
- sRECM = renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+ return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
}
+};
- static void TearDownTestSuite() {
- // The ordering here is important - sCurrentBuffer must live longer
- // than RenderEngine to avoid a null reference on tear-down.
- sRE = nullptr;
- sRECM = nullptr;
- sCurrentBuffer = nullptr;
+class GLESCMRenderEngineFactory : public RenderEngineFactory {
+public:
+ std::string name() override { return "GLESCMRenderEngineFactory"; }
+
+ std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+ renderengine::RenderEngineCreationArgs reCreationArgs =
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(1)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setSupportsBackgroundBlur(true)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+ .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::GLES)
+ .setUseColorManagerment(true)
+ .build();
+ return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
}
+};
+class RenderEngineTest : public ::testing::TestWithParam<std::shared_ptr<RenderEngineFactory>> {
+public:
static sp<GraphicBuffer> allocateDefaultBuffer() {
return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
HAL_PIXEL_FORMAT_RGBA_8888, 1,
@@ -80,19 +106,24 @@
"input");
}
- RenderEngineTest() { mBuffer = allocateDefaultBuffer(); }
+ RenderEngineTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ mBuffer = allocateDefaultBuffer();
+ }
~RenderEngineTest() {
if (WRITE_BUFFER_TO_FILE_ON_FAILURE && ::testing::Test::HasFailure()) {
writeBufferToFile("/data/texture_out_");
}
for (uint32_t texName : mTexNames) {
- sRE->deleteTextures(1, &texName);
- EXPECT_FALSE(sRE->isTextureNameKnownForTesting(texName));
+ mRE->deleteTextures(1, &texName);
+ EXPECT_FALSE(mRE->isTextureNameKnownForTesting(texName));
}
- for (uint32_t texName : mTexNamesCM) {
- sRECM->deleteTextures(1, &texName);
- }
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
void writeBufferToFile(const char* basename) {
@@ -261,12 +292,11 @@
void invokeDraw(renderengine::DisplaySettings settings,
std::vector<const renderengine::LayerSettings*> layers,
- sp<GraphicBuffer> buffer, bool useColorManagement = false) {
+ sp<GraphicBuffer> buffer) {
base::unique_fd fence;
- status_t status = useColorManagement
- ? sRECM->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence)
- : sRE->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence);
- sCurrentBuffer = buffer;
+ status_t status =
+ mRE->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence);
+ mCurrentBuffer = buffer;
int fd = fence.release();
if (fd >= 0) {
@@ -276,11 +306,7 @@
ASSERT_EQ(NO_ERROR, status);
if (layers.size() > 0) {
- if (useColorManagement) {
- ASSERT_TRUE(sRECM->isFramebufferImageCachedForTesting(buffer->getId()));
- } else {
- ASSERT_TRUE(sRE->isFramebufferImageCachedForTesting(buffer->getId()));
- }
+ ASSERT_TRUE(mRE->isFramebufferImageCachedForTesting(buffer->getId()));
}
}
@@ -335,15 +361,12 @@
void fillBufferLayerTransform();
template <typename SourceVariant>
- void fillBufferWithColorTransform(bool useColorManagement = false);
+ void fillBufferWithColorTransform();
template <typename SourceVariant>
void fillBufferColorTransform();
template <typename SourceVariant>
- void fillBufferColorTransformCM();
-
- template <typename SourceVariant>
void fillRedBufferWithRoundedCorners();
template <typename SourceVariant>
@@ -378,38 +401,30 @@
const renderengine::ShadowSettings& shadow, const ubyte4& casterColor,
const ubyte4& backgroundColor);
- // Keep around the same renderengine object to save on initialization time.
- // For now, exercise the GL backend directly so that some caching specifics
- // can be tested without changing the interface.
- static std::unique_ptr<renderengine::gl::GLESRenderEngine> sRE;
- // renderengine object with Color Management enabled
- static std::unique_ptr<renderengine::gl::GLESRenderEngine> sRECM;
+ std::unique_ptr<renderengine::gl::GLESRenderEngine> mRE;
+
// Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
// be freed *after* RenderEngine is destroyed, so that the EGL image is
// destroyed first.
- static sp<GraphicBuffer> sCurrentBuffer;
+ sp<GraphicBuffer> mCurrentBuffer;
sp<GraphicBuffer> mBuffer;
std::vector<uint32_t> mTexNames;
- std::vector<uint32_t> mTexNamesCM;
};
-std::unique_ptr<renderengine::gl::GLESRenderEngine> RenderEngineTest::sRE = nullptr;
-std::unique_ptr<renderengine::gl::GLESRenderEngine> RenderEngineTest::sRECM = nullptr;
-
-sp<GraphicBuffer> RenderEngineTest::sCurrentBuffer = nullptr;
-
struct ColorSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
- RenderEngineTest* /*fixture*/, bool /*useColorManagement*/ = false) {
+ RenderEngineTest* /*fixture*/) {
layer.source.solidColor = half3(r, g, b);
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
}
};
struct RelaxOpaqueBufferVariant {
static void setOpaqueBit(renderengine::LayerSettings& layer) {
layer.source.buffer.isOpaque = false;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
}
static uint8_t getAlphaChannel() { return 255; }
@@ -418,6 +433,7 @@
struct ForceOpaqueBufferVariant {
static void setOpaqueBit(renderengine::LayerSettings& layer) {
layer.source.buffer.isOpaque = true;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
}
static uint8_t getAlphaChannel() {
@@ -430,16 +446,11 @@
template <typename OpaquenessVariant>
struct BufferSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
- RenderEngineTest* fixture, bool useColorManagement = false) {
+ RenderEngineTest* fixture) {
sp<GraphicBuffer> buf = RenderEngineTest::allocateSourceBuffer(1, 1);
uint32_t texName;
- if (useColorManagement) {
- fixture->sRECM->genTextures(1, &texName);
- fixture->mTexNamesCM.push_back(texName);
- } else {
- fixture->sRE->genTextures(1, &texName);
- fixture->mTexNames.push_back(texName);
- }
+ fixture->mRE->genTextures(1, &texName);
+ fixture->mTexNames.push_back(texName);
uint8_t* pixels;
buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
@@ -460,6 +471,7 @@
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
OpaquenessVariant::setOpaqueBit(layer);
}
};
@@ -469,10 +481,12 @@
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(layer, r, g, b, this);
layer.alpha = a;
@@ -509,12 +523,14 @@
template <typename SourceVariant>
void RenderEngineTest::fillRedOffsetBuffer() {
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = offsetRect();
settings.clip = offsetRectAtZero();
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
layer.geometry.boundaries = offsetRectAtZero().toFloatRect();
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
@@ -540,6 +556,7 @@
template <typename SourceVariant>
void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) {
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = fullscreenRect();
// Here logical space is 2x2
settings.clip = Rect(2, 2);
@@ -548,18 +565,21 @@
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layerOne;
+ layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
Rect rectOne(0, 0, 1, 1);
layerOne.geometry.boundaries = rectOne.toFloatRect();
SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
layerOne.alpha = 1.0f;
renderengine::LayerSettings layerTwo;
+ layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
Rect rectTwo(0, 1, 1, 2);
layerTwo.geometry.boundaries = rectTwo.toFloatRect();
SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
layerTwo.alpha = 1.0f;
renderengine::LayerSettings layerThree;
+ layerThree.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
Rect rectThree(1, 0, 2, 1);
layerThree.geometry.boundaries = rectThree.toFloatRect();
SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this);
@@ -642,10 +662,12 @@
settings.physicalDisplay = fullscreenRect();
// Here logical space is 2x2
settings.clip = Rect(2, 2);
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
// Translate one pixel diagonally
layer.geometry.positionTransform = mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1);
@@ -669,16 +691,18 @@
}
template <typename SourceVariant>
-void RenderEngineTest::fillBufferWithColorTransform(bool useColorManagement) {
+void RenderEngineTest::fillBufferWithColorTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this, useColorManagement);
+ SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
layer.alpha = 1.0f;
// construct a fake color matrix
@@ -692,7 +716,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer, useColorManagement);
+ invokeDraw(settings, layers, mBuffer);
}
template <typename SourceVariant>
@@ -702,20 +726,16 @@
}
template <typename SourceVariant>
-void RenderEngineTest::fillBufferColorTransformCM() {
- fillBufferWithColorTransform<SourceVariant>(true);
- expectBufferColor(fullscreenRect(), 126, 0, 0, 255, 1);
-}
-
-template <typename SourceVariant>
void RenderEngineTest::fillRedBufferWithRoundedCorners() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
layer.geometry.roundedCornersRadius = 5.0f;
layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
@@ -756,18 +776,21 @@
auto center = DEFAULT_DISPLAY_WIDTH / 2;
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings backgroundLayer;
+ backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this);
backgroundLayer.alpha = 1.0f;
layers.push_back(&backgroundLayer);
renderengine::LayerSettings leftLayer;
+ leftLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
leftLayer.geometry.boundaries =
Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect();
SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this);
@@ -775,6 +798,7 @@
layers.push_back(&leftLayer);
renderengine::LayerSettings blurLayer;
+ blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
blurLayer.backgroundBlurRadius = blurRadius;
blurLayer.alpha = 0;
@@ -793,10 +817,12 @@
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
std::vector<const renderengine::LayerSettings*> layersFirst;
renderengine::LayerSettings layerOne;
+ layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
layerOne.geometry.boundaries =
FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0);
SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
@@ -811,6 +837,7 @@
std::vector<const renderengine::LayerSettings*> layersSecond;
renderengine::LayerSettings layerTwo;
+ layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
layerTwo.geometry.boundaries =
FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
@@ -830,15 +857,17 @@
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
// Here will allocate a checker board texture, but transform texture
// coordinates so that only the upper left is applied.
sp<GraphicBuffer> buf = allocateSourceBuffer(2, 2);
uint32_t texName;
- RenderEngineTest::sRE->genTextures(1, &texName);
+ RenderEngineTest::mRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
@@ -887,7 +916,7 @@
renderengine::LayerSettings layer;
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint32_t texName;
- RenderEngineTest::sRE->genTextures(1, &texName);
+ RenderEngineTest::mRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
@@ -926,7 +955,7 @@
renderengine::LayerSettings layer;
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint32_t texName;
- RenderEngineTest::sRE->genTextures(1, &texName);
+ RenderEngineTest::mRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
@@ -981,6 +1010,7 @@
const renderengine::ShadowSettings& shadow,
const ubyte4& casterColor, const ubyte4& backgroundColor) {
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
@@ -988,6 +1018,7 @@
// add background layer
renderengine::LayerSettings bgLayer;
+ bgLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
bgLayer.geometry.boundaries = fullscreenRect().toFloatRect();
ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
backgroundColor.b / 255.0f, this);
@@ -996,6 +1027,7 @@
// add shadow layer
renderengine::LayerSettings shadowLayer;
+ shadowLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries;
shadowLayer.alpha = castingLayer.alpha;
shadowLayer.shadow = shadow;
@@ -1003,6 +1035,7 @@
// add layer casting the shadow
renderengine::LayerSettings layer = castingLayer;
+ layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f,
casterColor.b / 255.0f, this);
layers.push_back(&layer);
@@ -1010,25 +1043,39 @@
invokeDraw(settings, layers, mBuffer);
}
-TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
+INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
+ testing::Values(std::make_shared<GLESRenderEngineFactory>(),
+ std::make_shared<GLESCMRenderEngineFactory>()));
+
+TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
drawEmptyLayers();
}
-TEST_F(RenderEngineTest, drawLayers_nullOutputBuffer) {
+TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layers.push_back(&layer);
base::unique_fd fence;
- status_t status = sRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
+ status_t status = mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
ASSERT_EQ(BAD_VALUE, status);
}
-TEST_F(RenderEngineTest, drawLayers_nullOutputFence) {
+TEST_P(RenderEngineTest, drawLayers_nullOutputFence) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
@@ -1039,14 +1086,18 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- status_t status = sRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr);
- sCurrentBuffer = mBuffer;
+ status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr);
+ mCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
-TEST_F(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
+TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
@@ -1057,211 +1108,341 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- status_t status = sRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr);
- sCurrentBuffer = mBuffer;
+ status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr);
+ mCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
- ASSERT_FALSE(sRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
+ ASSERT_FALSE(mRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
-TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillRedBuffer<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillGreenBuffer<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBlueBuffer<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillRedTransparentBuffer<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferPhysicalOffset<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate0<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate90<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate180<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate270<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferLayerTransform<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferColorTransform<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_colorSource) {
- fillBufferColorTransformCM<ColorSourceVariant>();
-}
+TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
-TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
fillBufferWithRoundedCorners<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferAndBlurBackground<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
overlayCorners<ColorSourceVariant>();
}
-TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillGreenBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBlueBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillRedTransparentBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferPhysicalOffset<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate0<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate90<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate180<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate270<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferColorTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_opaqueBufferSource) {
- fillBufferColorTransformCM<BufferSourceVariant<ForceOpaqueBufferVariant>>();
-}
+TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
-TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillGreenBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBlueBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillRedTransparentBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferPhysicalOffset<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate0<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate90<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate180<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferCheckersRotate270<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferColorTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_bufferSource) {
- fillBufferColorTransformCM<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
-}
+TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
-TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferTextureTransform();
}
-TEST_F(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
+TEST_P(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferWithPremultiplyAlpha();
}
-TEST_F(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
+TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
fillBufferWithoutPremultiplyAlpha();
}
-TEST_F(RenderEngineTest, drawLayers_clearRegion) {
+TEST_P(RenderEngineTest, drawLayers_clearRegion) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
clearRegion();
}
-TEST_F(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) {
+TEST_P(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
@@ -1274,21 +1455,24 @@
layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
uint64_t bufferId = layer.source.buffer.buffer->getId();
- EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
+ EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- sRE->unbindExternalTextureBufferForTesting(bufferId);
+ mRE->unbindExternalTextureBufferForTesting(bufferId);
std::lock_guard<std::mutex> lock(barrier->mutex);
ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
[&]() REQUIRES(barrier->mutex) {
return barrier->isOpen;
}));
- EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+ EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
EXPECT_EQ(NO_ERROR, barrier->result);
}
-TEST_F(RenderEngineTest, cacheExternalBuffer_withNullBuffer) {
+TEST_P(RenderEngineTest, cacheExternalBuffer_withNullBuffer) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- sRE->cacheExternalTextureBufferForTesting(nullptr);
+ mRE->cacheExternalTextureBufferForTesting(nullptr);
std::lock_guard<std::mutex> lock(barrier->mutex);
ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
[&]() REQUIRES(barrier->mutex) {
@@ -1298,11 +1482,14 @@
EXPECT_EQ(BAD_VALUE, barrier->result);
}
-TEST_F(RenderEngineTest, cacheExternalBuffer_cachesImages) {
+TEST_P(RenderEngineTest, cacheExternalBuffer_cachesImages) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint64_t bufferId = buf->getId();
std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- sRE->cacheExternalTextureBufferForTesting(buf);
+ mRE->cacheExternalTextureBufferForTesting(buf);
{
std::lock_guard<std::mutex> lock(barrier->mutex);
ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
@@ -1311,8 +1498,8 @@
}));
EXPECT_EQ(NO_ERROR, barrier->result);
}
- EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- barrier = sRE->unbindExternalTextureBufferForTesting(bufferId);
+ EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
+ barrier = mRE->unbindExternalTextureBufferForTesting(bufferId);
{
std::lock_guard<std::mutex> lock(barrier->mutex);
ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
@@ -1321,10 +1508,13 @@
}));
EXPECT_EQ(NO_ERROR, barrier->result);
}
- EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+ EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
}
-TEST_F(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
+TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
const float shadowLength = 5.0f;
@@ -1341,13 +1531,17 @@
expectShadowColor(castingLayer, settings, casterColor, backgroundColor);
}
-TEST_F(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) {
+TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
const float shadowLength = 5.0f;
Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f);
casterBounds.offsetBy(shadowLength + 1, shadowLength + 1);
renderengine::LayerSettings castingLayer;
+ castingLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
castingLayer.geometry.boundaries = casterBounds.toFloatRect();
castingLayer.alpha = 1.0f;
renderengine::ShadowSettings settings =
@@ -1358,13 +1552,17 @@
expectShadowColor(castingLayer, settings, casterColor, backgroundColor);
}
-TEST_F(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) {
+TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
const float shadowLength = 5.0f;
Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f);
casterBounds.offsetBy(shadowLength + 1, shadowLength + 1);
renderengine::LayerSettings castingLayer;
+ castingLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
castingLayer.geometry.boundaries = casterBounds.toFloatRect();
castingLayer.alpha = 1.0f;
renderengine::ShadowSettings settings =
@@ -1376,7 +1574,10 @@
expectShadowColor(castingLayer, settings, casterColor, backgroundColor);
}
-TEST_F(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) {
+TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
const float shadowLength = 5.0f;
@@ -1396,7 +1597,10 @@
expectShadowColor(castingLayer, settings, casterColor, backgroundColor);
}
-TEST_F(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) {
+TEST_P(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
const float shadowLength = 5.0f;
@@ -1421,10 +1625,14 @@
backgroundColor.a);
}
-TEST_F(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
+TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
@@ -1434,23 +1642,27 @@
layers.push_back(&layer);
base::unique_fd fenceOne;
- sRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fenceOne);
+ mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fenceOne);
base::unique_fd fenceTwo;
- sRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne), &fenceTwo);
+ mRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne), &fenceTwo);
const int fd = fenceTwo.get();
if (fd >= 0) {
sync_wait(fd, -1);
}
// Only cleanup the first time.
- EXPECT_TRUE(sRE->cleanupPostRender(
+ EXPECT_TRUE(mRE->cleanupPostRender(
renderengine::RenderEngine::CleanupMode::CLEAN_OUTPUT_RESOURCES));
- EXPECT_FALSE(sRE->cleanupPostRender(
+ EXPECT_FALSE(mRE->cleanupPostRender(
renderengine::RenderEngine::CleanupMode::CLEAN_OUTPUT_RESOURCES));
}
-TEST_F(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory) {
+TEST_P(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
@@ -1462,7 +1674,7 @@
layers.push_back(&layer);
base::unique_fd fence;
- sRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence);
+ mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence);
const int fd = fence.get();
if (fd >= 0) {
@@ -1471,15 +1683,15 @@
uint64_t bufferId = layer.source.buffer.buffer->getId();
uint32_t texName = layer.source.buffer.textureName;
- EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- EXPECT_EQ(bufferId, sRE->getBufferIdForTextureNameForTesting(texName));
+ EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
+ EXPECT_EQ(bufferId, mRE->getBufferIdForTextureNameForTesting(texName));
- EXPECT_TRUE(sRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL));
+ EXPECT_TRUE(mRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL));
// Now check that our view of memory is good.
- EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
- EXPECT_EQ(std::nullopt, sRE->getBufferIdForTextureNameForTesting(bufferId));
- EXPECT_TRUE(sRE->isTextureNameKnownForTesting(texName));
+ EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
+ EXPECT_EQ(std::nullopt, mRE->getBufferIdForTextureNameForTesting(bufferId));
+ EXPECT_TRUE(mRE->isTextureNameKnownForTesting(texName));
}
} // namespace android
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index 1681fe2..49bc6bf 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_library_shared {
+cc_library {
name: "libvibrator",
vendor_available: true,
double_loadable: true,
@@ -47,4 +47,11 @@
],
export_include_dirs: ["include"],
+
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
diff --git a/libs/vibrator/fuzzer/Android.bp b/libs/vibrator/fuzzer/Android.bp
new file mode 100644
index 0000000..8020151
--- /dev/null
+++ b/libs/vibrator/fuzzer/Android.bp
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+
+cc_fuzz {
+ name: "vibrator_fuzzer",
+
+ host_supported: true,
+
+ srcs: [
+ "vibrator_fuzzer.cpp",
+ ],
+
+ static_libs: [
+ "liblog",
+ "libvibrator",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libbase",
+ "libutils",
+ ],
+
+ fuzz_config: {
+ componentid: 155276,
+ },
+}
diff --git a/libs/vibrator/fuzzer/README.md b/libs/vibrator/fuzzer/README.md
new file mode 100644
index 0000000..43eb2d2
--- /dev/null
+++ b/libs/vibrator/fuzzer/README.md
@@ -0,0 +1,65 @@
+# Fuzzer for libvibrator
+
+## Plugin Design Considerations
+This fuzzer fuzzes native code present in libvibrator and does not cover the Java implementation ExternalVibration
+The fuzzer plugin is designed based on the understanding of the
+library and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+libvibrator supports the following parameters:
+1. Uid (parameter name: `uid`)
+2. Package Name (parameter name: `pkg`)
+3. Audio Content Type (parameter name: `content_type`)
+4. Audio Usage (parameter name: `usage`)
+5. Audio Source (parameter name: `source`)
+6. Audio flags (parameter name: `flags`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `uid` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider |
+| `pkg` | Any std::string value | Value obtained from FuzzedDataProvider |
+| `content_type` | 0.`AUDIO_CONTENT_TYPE_UNKNOWN` 1.`AUDIO_CONTENT_TYPE_SPEECH` 2.`AUDIO_CONTENT_TYPE_MUSIC` 3.`AUDIO_CONTENT_TYPE_MOVIE` 4.`AUDIO_CONTENT_TYPE_SONIFICATION`| Value obtained from FuzzedDataProvider in the range 0 to 4|
+| `usage` | 0.`AUDIO_USAGE_UNKNOWN` 1.`AUDIO_USAGE_MEDIA` 2.`AUDIO_USAGE_VOICE_COMMUNICATION` 3.`AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING` 4.`AUDIO_USAGE_ALARM` 5.`AUDIO_USAGE_NOTIFICATION` 6.`AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE` 7.`AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST` 8.`AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT` 9.`AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED` 10.`AUDIO_USAGE_NOTIFICATION_EVENT` 11.`AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY` 12.`AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE` 13.`AUDIO_USAGE_ASSISTANCE_SONIFICATION` 14.`AUDIO_USAGE_GAME` 15.`AUDIO_USAGE_VIRTUAL_SOURCE` 16.`AUDIO_USAGE_ASSISTANT` 17.`AUDIO_USAGE_CALL_ASSISTANT` 18.`AUDIO_USAGE_EMERGENCY` 19.`AUDIO_USAGE_SAFETY` 20.`AUDIO_USAGE_VEHICLE_STATUS` 21.`AUDIO_USAGE_ANNOUNCEMENT`| Value obtained from FuzzedDataProvider in the range 0 to 21|
+| `source` | 0.`AUDIO_SOURCE_DEFAULT` 1.`AUDIO_SOURCE_MIC` 2.`AUDIO_SOURCE_VOICE_UPLINK` 3.`AUDIO_SOURCE_VOICE_DOWNLINK` 4.`AUDIO_SOURCE_VOICE_CALL` 5.`AUDIO_SOURCE_CAMCORDER` 6.`AUDIO_SOURCE_VOICE_RECOGNITION` 7.`AUDIO_SOURCE_VOICE_COMMUNICATION` 8.`AUDIO_SOURCE_REMOTE_SUBMIX` 9.`AUDIO_SOURCE_UNPROCESSED` 10.`AUDIO_SOURCE_VOICE_PERFORMANCE` 11.`AUDIO_SOURCE_ECHO_REFERENCE` 12.`AUDIO_SOURCE_FM_TUNER` | Value obtained from FuzzedDataProvider in the range 0 to 12 |
+| `flags` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesn't `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build vibrator_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) vibrator_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/vibrator_fuzzer/vibrator_fuzzer CORPUS_DIR
+```
+
+To run on host
+```
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/vibrator_fuzzer/vibrator_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/libs/vibrator/fuzzer/vibrator_fuzzer.cpp b/libs/vibrator/fuzzer/vibrator_fuzzer.cpp
new file mode 100644
index 0000000..68b3ca6
--- /dev/null
+++ b/libs/vibrator/fuzzer/vibrator_fuzzer.cpp
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+
+#include <binder/Parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <vibrator/ExternalVibration.h>
+
+using namespace android;
+
+constexpr size_t MAX_STRING_LENGTH = 100;
+constexpr audio_content_type_t AUDIO_CONTENT_TYPE[] = {AUDIO_CONTENT_TYPE_UNKNOWN,
+ AUDIO_CONTENT_TYPE_SPEECH,
+ AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_CONTENT_TYPE_MOVIE,
+ AUDIO_CONTENT_TYPE_SONIFICATION};
+constexpr audio_usage_t AUDIO_USAGE[] = {
+ AUDIO_USAGE_UNKNOWN,
+ AUDIO_USAGE_MEDIA,
+ AUDIO_USAGE_VOICE_COMMUNICATION,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AUDIO_USAGE_ALARM,
+ AUDIO_USAGE_NOTIFICATION,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+ AUDIO_USAGE_NOTIFICATION_EVENT,
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AUDIO_USAGE_GAME,
+ AUDIO_USAGE_VIRTUAL_SOURCE,
+ AUDIO_USAGE_ASSISTANT,
+ AUDIO_USAGE_CALL_ASSISTANT,
+ AUDIO_USAGE_EMERGENCY,
+ AUDIO_USAGE_SAFETY,
+ AUDIO_USAGE_VEHICLE_STATUS,
+ AUDIO_USAGE_ANNOUNCEMENT,
+};
+constexpr audio_source_t AUDIO_SOURCE[] = {
+ AUDIO_SOURCE_DEFAULT, AUDIO_SOURCE_MIC,
+ AUDIO_SOURCE_VOICE_UPLINK, AUDIO_SOURCE_VOICE_DOWNLINK,
+ AUDIO_SOURCE_VOICE_CALL, AUDIO_SOURCE_CAMCORDER,
+ AUDIO_SOURCE_VOICE_RECOGNITION, AUDIO_SOURCE_VOICE_COMMUNICATION,
+ AUDIO_SOURCE_REMOTE_SUBMIX, AUDIO_SOURCE_UNPROCESSED,
+ AUDIO_SOURCE_VOICE_PERFORMANCE, AUDIO_SOURCE_ECHO_REFERENCE,
+ AUDIO_SOURCE_FM_TUNER,
+};
+constexpr size_t NUM_AUDIO_CONTENT_TYPE = std::size(AUDIO_CONTENT_TYPE);
+constexpr size_t NUM_AUDIO_USAGE = std::size(AUDIO_USAGE);
+constexpr size_t NUM_AUDIO_SOURCE = std::size(AUDIO_SOURCE);
+
+class TestVibrationController : public os::IExternalVibrationController {
+public:
+ explicit TestVibrationController() {}
+ IBinder *onAsBinder() override { return nullptr; }
+ binder::Status mute(/*out*/ bool *ret) override {
+ *ret = false;
+ return binder::Status::ok();
+ };
+ binder::Status unmute(/*out*/ bool *ret) override {
+ *ret = false;
+ return binder::Status::ok();
+ };
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < 1) {
+ return 0;
+ }
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ // Initialize the parameters using FuzzedDataProvider
+ int32_t uid = fdp.ConsumeIntegral<int32_t>();
+ std::string pkg = fdp.ConsumeRandomLengthString(MAX_STRING_LENGTH);
+ audio_attributes_t attributes;
+ attributes.content_type =
+ AUDIO_CONTENT_TYPE[fdp.ConsumeIntegralInRange<uint32_t>(0, NUM_AUDIO_CONTENT_TYPE - 1)];
+ attributes.usage = AUDIO_USAGE[fdp.ConsumeIntegralInRange<uint32_t>(0, NUM_AUDIO_USAGE - 1)];
+ attributes.source = AUDIO_SOURCE[fdp.ConsumeIntegralInRange<uint32_t>(0, NUM_AUDIO_SOURCE - 1)];
+ attributes.flags = static_cast<audio_flags_mask_t>(fdp.ConsumeIntegral<uint32_t>());
+
+ // Create an instance of TestVibrationController
+ sp<TestVibrationController> vibrationController = new TestVibrationController();
+ if (!vibrationController) {
+ return 0;
+ }
+
+ // Set all the parameters in the constructor call
+ sp<os::ExternalVibration> extVibration =
+ new os::ExternalVibration(uid, pkg, attributes, vibrationController);
+ if (!extVibration) {
+ return 0;
+ }
+
+ // Get all the parameters that were previously set
+ extVibration->getUid();
+ extVibration->getPackage();
+ extVibration->getAudioAttributes();
+ extVibration->getController();
+
+ // Set the parameters in a Parcel object and send it to libvibrator
+ // This parcel shall be read by libvibrator
+ Parcel parcel;
+ parcel.writeInt32(uid);
+ parcel.writeString16(String16(pkg.c_str()));
+ parcel.writeStrongBinder(IInterface::asBinder(vibrationController));
+ parcel.setDataPosition(0);
+ extVibration->readFromParcel(&parcel);
+
+ // Send a Parcel to libvibrator
+ // Parameters shall be written to this parcel by libvibrator
+ extVibration->writeToParcel(&parcel);
+ return 0;
+}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 17f37c3..b620e2d 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -745,12 +745,17 @@
mOrientedRanges.clear();
}
- // Create pointer controller if needed.
+ // Create pointer controller if needed, and keep it around if Pointer Capture is enabled to
+ // preserve the cursor position.
if (mDeviceMode == DeviceMode::POINTER ||
- (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches)) {
+ (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches) ||
+ (mParameters.deviceType == Parameters::DeviceType::POINTER && mConfig.pointerCapture)) {
if (mPointerController == nullptr) {
mPointerController = getContext()->getPointerController(getDeviceId());
}
+ if (mConfig.pointerCapture) {
+ mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
+ }
} else {
mPointerController.reset();
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index bf5be47..b63e8c8 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -45,6 +45,9 @@
#include "FrameTimeline.h"
#include "HwcStrongTypes.h"
+#undef LOG_TAG
+#define LOG_TAG "EventThread"
+
using namespace std::chrono_literals;
namespace android {
@@ -123,14 +126,36 @@
return event;
}
+DisplayEventReceiver::Event makeFrameRateOverrideEvent(PhysicalDisplayId displayId,
+ FrameRateOverride frameRateOverride) {
+ return DisplayEventReceiver::Event{
+ .header =
+ DisplayEventReceiver::Event::Header{
+ .type = DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
+ .displayId = displayId,
+ .timestamp = systemTime(),
+ },
+ .frameRateOverride = frameRateOverride,
+ };
+}
+
+DisplayEventReceiver::Event makeFrameRateOverrideFlushEvent(PhysicalDisplayId displayId) {
+ return DisplayEventReceiver::Event{
+ .header = DisplayEventReceiver::Event::Header{
+ .type = DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
+ .displayId = displayId,
+ .timestamp = systemTime(),
+ }};
+}
+
} // namespace
-EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid,
- ResyncCallback resyncCallback,
- ISurfaceComposer::ConfigChanged configChanged)
+EventThreadConnection::EventThreadConnection(
+ EventThread* eventThread, uid_t callingUid, ResyncCallback resyncCallback,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration)
: resyncCallback(std::move(resyncCallback)),
- mConfigChanged(configChanged),
mOwnerUid(callingUid),
+ mEventRegistration(eventRegistration),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}
@@ -161,8 +186,25 @@
}
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
- ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
- return size < 0 ? status_t(size) : status_t(NO_ERROR);
+ constexpr auto toStatus = [](ssize_t size) {
+ return size < 0 ? status_t(size) : status_t(NO_ERROR);
+ };
+
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE ||
+ event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
+ mPendingEvents.emplace_back(event);
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
+ return status_t(NO_ERROR);
+ }
+
+ auto size = DisplayEventReceiver::sendEvents(&mChannel, mPendingEvents.data(),
+ mPendingEvents.size());
+ mPendingEvents.clear();
+ return toStatus(size);
+ }
+
+ auto size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
+ return toStatus(size);
}
// ---------------------------------------------------------------------------
@@ -220,10 +262,11 @@
}
sp<EventThreadConnection> EventThread::createEventConnection(
- ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const {
+ ResyncCallback resyncCallback,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration) const {
return new EventThreadConnection(const_cast<EventThread*>(this),
IPCThreadState::self()->getCallingUid(),
- std::move(resyncCallback), configChanged);
+ std::move(resyncCallback), eventRegistration);
}
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -333,6 +376,18 @@
mCondition.notify_all();
}
+void EventThread::onFrameRateOverridesChanged(PhysicalDisplayId displayId,
+ std::vector<FrameRateOverride> overrides) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ for (auto frameRateOverride : overrides) {
+ mPendingEvents.push_back(makeFrameRateOverrideEvent(displayId, frameRateOverride));
+ }
+ mPendingEvents.push_back(makeFrameRateOverrideFlushEvent(displayId));
+
+ mCondition.notify_all();
+}
+
size_t EventThread::getEventThreadConnectionCount() {
std::lock_guard<std::mutex> lock(mMutex);
return mDisplayEventConnections.size();
@@ -459,7 +514,8 @@
return true;
case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
- return connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
+ return connection->mEventRegistration.test(
+ ISurfaceComposer::EventRegistration::configChanged);
}
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
@@ -488,6 +544,12 @@
return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
}
+ case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+ [[fallthrough]];
+ case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
+ return connection->mEventRegistration.test(
+ ISurfaceComposer::EventRegistration::frameRateOverride);
+
default:
return false;
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 2e2d989..e75b718 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -48,6 +48,7 @@
// ---------------------------------------------------------------------------
using ResyncCallback = std::function<void()>;
+using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
enum class VSyncRequest {
None = -2,
@@ -82,7 +83,7 @@
class EventThreadConnection : public BnDisplayEventConnection {
public:
EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback,
- ISurfaceComposer::ConfigChanged configChanged);
+ ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
virtual ~EventThreadConnection();
virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -95,15 +96,15 @@
const ResyncCallback resyncCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
- const ISurfaceComposer::ConfigChanged mConfigChanged =
- ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;
-
const uid_t mOwnerUid;
+ const ISurfaceComposer::EventRegistrationFlags mEventRegistration;
private:
virtual void onFirstRef();
EventThread* const mEventThread;
gui::BitTube mChannel;
+
+ std::vector<DisplayEventReceiver::Event> mPendingEvents;
};
class EventThread {
@@ -111,7 +112,8 @@
virtual ~EventThread();
virtual sp<EventThreadConnection> createEventConnection(
- ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const = 0;
+ ResyncCallback,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) const = 0;
// called before the screen is turned off from main thread
virtual void onScreenReleased() = 0;
@@ -125,6 +127,10 @@
virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
nsecs_t vsyncPeriod) = 0;
+ // called when SF updates the Frame Rate Override list
+ virtual void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
+ std::vector<FrameRateOverride> overrides) = 0;
+
virtual void dump(std::string& result) const = 0;
virtual void setDuration(std::chrono::nanoseconds workDuration,
@@ -152,7 +158,8 @@
~EventThread();
sp<EventThreadConnection> createEventConnection(
- ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const override;
+ ResyncCallback,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) const override;
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
@@ -169,6 +176,9 @@
void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
nsecs_t vsyncPeriod) override;
+ void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
+ std::vector<FrameRateOverride> overrides) override;
+
void dump(std::string& result) const override;
void setDuration(std::chrono::nanoseconds workDuration,
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 2559eb4..83fa20e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -650,21 +650,20 @@
return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
}
-void RefreshRateConfigs::setPreferredRefreshRateForUid(uid_t uid, float refreshRateHz) {
- if (refreshRateHz > 0 && refreshRateHz < 1) {
+void RefreshRateConfigs::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
+ if (frameRateOverride.frameRateHz > 0 && frameRateOverride.frameRateHz < 1) {
return;
}
std::lock_guard lock(mLock);
- if (refreshRateHz != 0) {
- mPreferredRefreshRateForUid[uid] = refreshRateHz;
+ if (frameRateOverride.frameRateHz != 0) {
+ mPreferredRefreshRateForUid[frameRateOverride.uid] = frameRateOverride.frameRateHz;
} else {
- mPreferredRefreshRateForUid.erase(uid);
+ mPreferredRefreshRateForUid.erase(frameRateOverride.uid);
}
}
int RefreshRateConfigs::getRefreshRateDividerForUid(uid_t uid) const {
- constexpr float kThreshold = 0.1f;
std::lock_guard lock(mLock);
const auto iter = mPreferredRefreshRateForUid.find(uid);
@@ -672,6 +671,9 @@
return 1;
}
+ // This calculation needs to be in sync with the java code
+ // in DisplayManagerService.getDisplayInfoForFrameRateOverride
+ constexpr float kThreshold = 0.1f;
const auto refreshRateHz = iter->second;
const auto numPeriods = mCurrentRefreshRate->getFps() / refreshRateHz;
const auto numPeriodsRounded = std::round(numPeriods);
@@ -679,7 +681,19 @@
return 1;
}
- return static_cast<int>(numPeriods);
+ return static_cast<int>(numPeriodsRounded);
+}
+
+std::vector<FrameRateOverride> RefreshRateConfigs::getFrameRateOverrides() {
+ std::lock_guard lock(mLock);
+ std::vector<FrameRateOverride> overrides;
+ overrides.reserve(mPreferredRefreshRateForUid.size());
+
+ for (const auto [uid, frameRate] : mPreferredRefreshRateForUid) {
+ overrides.emplace_back(FrameRateOverride{uid, frameRate});
+ }
+
+ return overrides;
}
void RefreshRateConfigs::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index a5fadbf..8ebbd74 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -17,6 +17,7 @@
#pragma once
#include <android-base/stringprintf.h>
+#include <gui/DisplayEventReceiver.h>
#include <algorithm>
#include <numeric>
@@ -40,6 +41,8 @@
return static_cast<RefreshRateConfigEvent>(static_cast<T>(lhs) | static_cast<T>(rhs));
}
+using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
+
/**
* This class is used to encapsulate configuration for refresh rates. It holds information
* about available refresh rates on the device, and the mapping between the numbers and human
@@ -313,14 +316,17 @@
KernelIdleTimerAction getIdleTimerAction() const;
// Stores the preferred refresh rate that an app should run at.
- // refreshRate == 0 means no preference.
- void setPreferredRefreshRateForUid(uid_t, float refreshRateHz) EXCLUDES(mLock);
+ // FrameRateOverride.refreshRateHz == 0 means no preference.
+ void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mLock);
// Returns a divider for the current refresh rate
int getRefreshRateDividerForUid(uid_t) const EXCLUDES(mLock);
void dump(std::string& result) const EXCLUDES(mLock);
+ // Returns the current frame rate overrides
+ std::vector<FrameRateOverride> getFrameRateOverrides() EXCLUDES(mLock);
+
private:
friend class RefreshRateConfigsTest;
@@ -378,6 +384,8 @@
Policy mDisplayManagerPolicy GUARDED_BY(mLock);
std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);
+ // A mapping between a UID and a preferred refresh rate that this app would
+ // run at.
std::unordered_map<uid_t, float> mPreferredRefreshRateForUid GUARDED_BY(mLock);
// The min and max refresh rates supported by the device.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index a9e08fc..52bf483 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -233,8 +233,7 @@
const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
- auto connection =
- createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
+ auto connection = createConnectionInternal(eventThread.get());
std::lock_guard<std::mutex> lock(mConnectionsLock);
mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
@@ -242,15 +241,15 @@
}
sp<EventThreadConnection> Scheduler::createConnectionInternal(
- EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) {
- return eventThread->createEventConnection([&] { resync(); }, configChanged);
+ EventThread* eventThread, ISurfaceComposer::EventRegistrationFlags eventRegistration) {
+ return eventThread->createEventConnection([&] { resync(); }, eventRegistration);
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- ConnectionHandle handle, ISurfaceComposer::ConfigChanged configChanged) {
+ ConnectionHandle handle, ISurfaceComposer::EventRegistrationFlags eventRegistration) {
std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle, nullptr);
- return createConnectionInternal(mConnections[handle].thread.get(), configChanged);
+ return createConnectionInternal(mConnections[handle].thread.get(), eventRegistration);
}
sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
@@ -291,6 +290,17 @@
thread->onScreenReleased();
}
+void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
+ std::vector<FrameRateOverride> overrides) {
+ android::EventThread* thread;
+ {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
+ RETURN_IF_INVALID_HANDLE(handle);
+ thread = mConnections[handle].thread.get();
+ }
+ thread->onFrameRateOverridesChanged(displayId, std::move(overrides));
+}
+
void Scheduler::onPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
std::lock_guard<std::mutex> lock(mFeatureStateLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 936d96a..f16e1f9 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -79,8 +79,8 @@
std::chrono::nanoseconds readyDuration,
impl::EventThread::InterceptVSyncsCallback);
- sp<IDisplayEventConnection> createDisplayEventConnection(ConnectionHandle,
- ISurfaceComposer::ConfigChanged);
+ sp<IDisplayEventConnection> createDisplayEventConnection(
+ ConnectionHandle, ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
sp<EventThreadConnection> getEventConnection(ConnectionHandle);
@@ -93,6 +93,9 @@
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
+ void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId,
+ std::vector<FrameRateOverride>);
+
// Modifies work duration in the event thread.
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration);
@@ -200,8 +203,8 @@
// Create a connection on the given EventThread.
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
- sp<EventThreadConnection> createConnectionInternal(EventThread*,
- ISurfaceComposer::ConfigChanged);
+ sp<EventThreadConnection> createConnectionInternal(
+ EventThread*, ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
// Update feature state machine to given state when corresponding timer resets or expires.
void kernelIdleTimerCallback(TimerState);
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index a28ed92..a6f9372 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -222,10 +222,10 @@
/*
* Returns whether a given vsync timestamp is in phase with a vsync divider.
- * For example, if the vsync timestamps are (0,16,32,48):
- * isVSyncInPhase(0, 2) = true
- * isVSyncInPhase(16, 2) = false
- * isVSyncInPhase(32, 2) = true
+ * For example, if the vsync timestamps are (16,32,48,64):
+ * isVSyncInPhase(16, 2) = true
+ * isVSyncInPhase(32, 2) = false
+ * isVSyncInPhase(48, 2) = true
*/
bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, int divider) const {
struct VsyncError {
@@ -235,11 +235,11 @@
bool operator<(const VsyncError& other) const { return error < other.error; }
};
- std::lock_guard lock(mMutex);
- if (divider <= 1) {
+ if (divider <= 1 || timePoint == 0) {
return true;
}
+ std::lock_guard lock(mMutex);
const nsecs_t period = mRateMap[mIdealPeriod].slope;
const nsecs_t justBeforeTimePoint = timePoint - period / 2;
const nsecs_t dividedPeriod = mIdealPeriod / divider;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dbfa881..576bd50 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1526,11 +1526,12 @@
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
- ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) {
+ ISurfaceComposer::VsyncSource vsyncSource,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration) {
const auto& handle =
vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
- return mScheduler->createDisplayEventConnection(handle, configChanged);
+ return mScheduler->createDisplayEventConnection(handle, eventRegistration);
}
void SurfaceFlinger::signalTransaction() {
@@ -4034,7 +4035,14 @@
sp<Layer>* outLayer) {
LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
args.textureName = getNewTexture();
- sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args);
+ sp<BufferStateLayer> layer;
+ {
+ // TODO (b/173538294): Investigate why we need mStateLock here and above in
+ // createBufferQueue layer. Is it the renderengine::Image?
+ Mutex::Autolock lock(mStateLock);
+ layer = getFactory().createBufferStateLayer(args);
+
+ }
*handle = layer->getHandle();
*outLayer = layer;
@@ -5270,10 +5278,18 @@
return NO_ERROR;
}
case 1039: {
- // The first parameter is the uid
- n = data.readInt32();
- const float refreshRateHz = data.readFloat();
- mRefreshRateConfigs->setPreferredRefreshRateForUid(n, refreshRateHz);
+ PhysicalDisplayId displayId = [&]() {
+ Mutex::Autolock lock(mStateLock);
+ return getDefaultDisplayDeviceLocked()->getPhysicalId();
+ }();
+
+ auto inUid = static_cast<uid_t>(data.readInt32());
+ const auto refreshRate = data.readFloat();
+ mRefreshRateConfigs->setPreferredRefreshRateForUid(
+ FrameRateOverride{inUid, refreshRate});
+ const auto mappings = mRefreshRateConfigs->getFrameRateOverrides();
+ mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId,
+ std::move(mappings));
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9666f14..a909ad8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -530,8 +530,7 @@
status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override;
sp<IDisplayEventConnection> createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
- ISurfaceComposer::ConfigChanged configChanged =
- ISurfaceComposer::eConfigChangedSuppress) override;
+ ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override;
status_t captureDisplay(const DisplayCaptureArgs& args,
const sp<IScreenCaptureListener>& captureListener) override;
status_t captureDisplay(uint64_t displayOrLayerStack,
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 0a70f5c..31a5126 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -240,8 +240,9 @@
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
- mReceiver.reset(new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp,
- ISurfaceComposer::eConfigChangedDispatch));
+ mReceiver.reset(
+ new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp,
+ ISurfaceComposer::EventRegistration::configChanged));
mLooper = new Looper(false);
mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 0911712..be9d336 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -133,17 +133,13 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(
- new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(
- new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index f0311bd..9069200 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -70,15 +70,13 @@
void DisplayTransactionTest::injectMockScheduler() {
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*mEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(mEventThread, /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ .WillOnce(Return(
+ new EventThreadConnection(mEventThread, /*callingUid=*/0, ResyncCallback())));
EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*mSFEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(mSFEventThread, /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ .WillOnce(Return(
+ new EventThreadConnection(mSFEventThread, /*callingUid=*/0, ResyncCallback())));
mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController),
std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 3aafd45..ee56178 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -29,6 +29,7 @@
using namespace std::chrono_literals;
using namespace std::placeholders;
+using namespace android::flag_operators;
using testing::_;
using testing::Invoke;
@@ -61,9 +62,9 @@
public:
MockEventThreadConnection(impl::EventThread* eventThread, uid_t callingUid,
ResyncCallback&& resyncCallback,
- ISurfaceComposer::ConfigChanged configChanged)
+ ISurfaceComposer::EventRegistrationFlags eventRegistration)
: EventThreadConnection(eventThread, callingUid, std::move(resyncCallback),
- configChanged) {}
+ eventRegistration) {}
MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
};
@@ -74,9 +75,10 @@
~EventThreadTest() override;
void createThread(std::unique_ptr<VSyncSource>);
- sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
- ISurfaceComposer::ConfigChanged configChanged,
- uid_t ownerUid = mConnectionUid);
+ sp<MockEventThreadConnection> createConnection(
+ ConnectionEventRecorder& recorder,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration = {},
+ uid_t ownerUid = mConnectionUid);
void expectVSyncSetEnabledCallReceived(bool expectedState);
void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration,
@@ -93,6 +95,8 @@
int32_t expectedConfigId,
nsecs_t expectedVsyncPeriod);
void expectThrottleVsyncReceived(nsecs_t expectedTimestamp, uid_t);
+ void expectUidFrameRateMappingEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
+ std::vector<FrameRateOverride>);
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -133,10 +137,11 @@
createThread(std::move(vsyncSource));
mConnection = createConnection(mConnectionEventCallRecorder,
- ISurfaceComposer::eConfigChangedDispatch);
- mThrottledConnection =
- createConnection(mThrottledConnectionEventCallRecorder,
- ISurfaceComposer::eConfigChangedDispatch, mThrottledConnectionUid);
+ ISurfaceComposer::EventRegistration::configChanged |
+ ISurfaceComposer::EventRegistration::frameRateOverride);
+ mThrottledConnection = createConnection(mThrottledConnectionEventCallRecorder,
+ ISurfaceComposer::EventRegistration::configChanged,
+ mThrottledConnectionUid);
// A display must be connected for VSYNC events to be delivered.
mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
@@ -169,11 +174,11 @@
}
sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
- ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged,
- uid_t ownerUid) {
+ ConnectionEventRecorder& recorder,
+ ISurfaceComposer::EventRegistrationFlags eventRegistration, uid_t ownerUid) {
sp<MockEventThreadConnection> connection =
new MockEventThreadConnection(mThread.get(), ownerUid,
- mResyncCallRecorder.getInvocable(), configChanged);
+ mResyncCallRecorder.getInvocable(), eventRegistration);
EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
return connection;
}
@@ -254,6 +259,25 @@
EXPECT_EQ(expectedVsyncPeriod, event.config.vsyncPeriod);
}
+void EventThreadTest::expectUidFrameRateMappingEventReceivedByConnection(
+ PhysicalDisplayId expectedDisplayId, std::vector<FrameRateOverride> expectedOverrides) {
+ for (const auto [uid, frameRateHz] : expectedOverrides) {
+ auto args = mConnectionEventCallRecorder.waitForCall();
+ ASSERT_TRUE(args.has_value());
+ const auto& event = std::get<0>(args.value());
+ EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE, event.header.type);
+ EXPECT_EQ(expectedDisplayId, event.header.displayId);
+ EXPECT_EQ(uid, event.frameRateOverride.uid);
+ EXPECT_EQ(frameRateHz, event.frameRateOverride.frameRateHz);
+ }
+
+ auto args = mConnectionEventCallRecorder.waitForCall();
+ ASSERT_TRUE(args.has_value());
+ const auto& event = std::get<0>(args.value());
+ EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH, event.header.type);
+ EXPECT_EQ(expectedDisplayId, event.header.displayId);
+}
+
namespace {
/* ------------------------------------------------------------------------
@@ -313,9 +337,7 @@
TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
// Create a first connection, register it, and request a vsync rate of zero.
ConnectionEventRecorder firstConnectionEventRecorder{0};
- sp<MockEventThreadConnection> firstConnection =
- createConnection(firstConnectionEventRecorder,
- ISurfaceComposer::eConfigChangedSuppress);
+ sp<MockEventThreadConnection> firstConnection = createConnection(firstConnectionEventRecorder);
mThread->setVsyncRate(0, firstConnection);
// By itself, this should not enable vsync events
@@ -325,8 +347,7 @@
// However if there is another connection which wants events at a nonzero rate.....
ConnectionEventRecorder secondConnectionEventRecorder{0};
sp<MockEventThreadConnection> secondConnection =
- createConnection(secondConnectionEventRecorder,
- ISurfaceComposer::eConfigChangedSuppress);
+ createConnection(secondConnectionEventRecorder);
mThread->setVsyncRate(1, secondConnection);
// EventThread should enable vsync callbacks.
@@ -418,9 +439,7 @@
TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
- sp<MockEventThreadConnection> errorConnection =
- createConnection(errorConnectionEventRecorder,
- ISurfaceComposer::eConfigChangedSuppress);
+ sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
mThread->setVsyncRate(1, errorConnection);
// EventThread should enable vsync callbacks.
@@ -445,15 +464,12 @@
TEST_F(EventThreadTest, tracksEventConnections) {
EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
- sp<MockEventThreadConnection> errorConnection =
- createConnection(errorConnectionEventRecorder,
- ISurfaceComposer::eConfigChangedSuppress);
+ sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
mThread->setVsyncRate(1, errorConnection);
EXPECT_EQ(3, mThread->getEventThreadConnectionCount());
ConnectionEventRecorder secondConnectionEventRecorder{0};
sp<MockEventThreadConnection> secondConnection =
- createConnection(secondConnectionEventRecorder,
- ISurfaceComposer::eConfigChangedSuppress);
+ createConnection(secondConnectionEventRecorder);
mThread->setVsyncRate(1, secondConnection);
EXPECT_EQ(4, mThread->getEventThreadConnectionCount());
@@ -472,9 +488,7 @@
TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
- sp<MockEventThreadConnection> errorConnection =
- createConnection(errorConnectionEventRecorder,
- ISurfaceComposer::eConfigChangedSuppress);
+ sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
mThread->setVsyncRate(1, errorConnection);
// EventThread should enable vsync callbacks.
@@ -539,8 +553,7 @@
TEST_F(EventThreadTest, suppressConfigChanged) {
ConnectionEventRecorder suppressConnectionEventRecorder{0};
sp<MockEventThreadConnection> suppressConnection =
- createConnection(suppressConnectionEventRecorder,
- ISurfaceComposer::eConfigChangedSuppress);
+ createConnection(suppressConnectionEventRecorder);
mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9), 16666666);
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
@@ -549,6 +562,35 @@
ASSERT_FALSE(args.has_value());
}
+TEST_F(EventThreadTest, postUidFrameRateMapping) {
+ const std::vector<FrameRateOverride> overrides = {
+ {.uid = 1, .frameRateHz = 20},
+ {.uid = 3, .frameRateHz = 40},
+ {.uid = 5, .frameRateHz = 60},
+ };
+
+ mThread->onFrameRateOverridesChanged(INTERNAL_DISPLAY_ID, overrides);
+ expectUidFrameRateMappingEventReceivedByConnection(INTERNAL_DISPLAY_ID, overrides);
+}
+
+TEST_F(EventThreadTest, suppressUidFrameRateMapping) {
+ const std::vector<FrameRateOverride> overrides = {
+ {.uid = 1, .frameRateHz = 20},
+ {.uid = 3, .frameRateHz = 40},
+ {.uid = 5, .frameRateHz = 60},
+ };
+
+ ConnectionEventRecorder suppressConnectionEventRecorder{0};
+ sp<MockEventThreadConnection> suppressConnection =
+ createConnection(suppressConnectionEventRecorder);
+
+ mThread->onFrameRateOverridesChanged(INTERNAL_DISPLAY_ID, overrides);
+ expectUidFrameRateMappingEventReceivedByConnection(INTERNAL_DISPLAY_ID, overrides);
+
+ auto args = suppressConnectionEventRecorder.waitForCall();
+ ASSERT_FALSE(args.has_value());
+}
+
TEST_F(EventThreadTest, requestNextVsyncWithThrottleVsyncDoesntPostVSync) {
// Signal that we want the next vsync event to be posted to the throttled connection
mThread->requestNextVsync(mThrottledConnection);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 82cf22c..f2b7191 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1538,7 +1538,7 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_30);
const uid_t uid = 1234;
- refreshRateConfigs->setPreferredRefreshRateForUid(uid, 30);
+ refreshRateConfigs->setPreferredRefreshRateForUid({uid, 30});
EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDividerForUid(uid));
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60);
@@ -1552,6 +1552,12 @@
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120);
EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
+
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+ refreshRateConfigs->setPreferredRefreshRateForUid({uid, 22.5});
+ EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
+ refreshRateConfigs->setPreferredRefreshRateForUid({uid, 22.6f});
+ EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index 8cd8372..c5deb7c 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -132,14 +132,12 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
.WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
.WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 895c6b3..fb02a33 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -42,8 +42,7 @@
class MockEventThreadConnection : public android::EventThreadConnection {
public:
explicit MockEventThreadConnection(EventThread* eventThread)
- : EventThreadConnection(eventThread, /*callingUid=*/0, ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress) {}
+ : EventThreadConnection(eventThread, /*callingUid=*/0, ResyncCallback()) {}
~MockEventThreadConnection() = default;
MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -97,9 +96,7 @@
TEST_F(SchedulerTest, invalidConnectionHandle) {
Scheduler::ConnectionHandle handle;
- const sp<IDisplayEventConnection> connection =
- mScheduler.createDisplayEventConnection(handle,
- ISurfaceComposer::eConfigChangedSuppress);
+ const sp<IDisplayEventConnection> connection = mScheduler.createDisplayEventConnection(handle);
EXPECT_FALSE(connection);
EXPECT_FALSE(mScheduler.getEventConnection(handle));
@@ -125,8 +122,7 @@
TEST_F(SchedulerTest, validConnectionHandle) {
const sp<IDisplayEventConnection> connection =
- mScheduler.createDisplayEventConnection(mConnectionHandle,
- ISurfaceComposer::eConfigChangedSuppress);
+ mScheduler.createDisplayEventConnection(mConnectionHandle);
ASSERT_EQ(mEventThreadConnection, connection);
EXPECT_TRUE(mScheduler.getEventConnection(mConnectionHandle));
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index e25d501..5278641 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -172,14 +172,12 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
.WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
.WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 68cf330..c36d994 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -65,17 +65,13 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(
- new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(
- new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress)));
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
EXPECT_CALL(*mVSyncTracker, currentPeriod())
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index b4594c1..650d52d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,11 +28,14 @@
~EventThread() override;
MOCK_CONST_METHOD2(createEventConnection,
- sp<EventThreadConnection>(ResyncCallback, ISurfaceComposer::ConfigChanged));
+ sp<EventThreadConnection>(ResyncCallback,
+ ISurfaceComposer::EventRegistrationFlags));
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t));
+ MOCK_METHOD2(onFrameRateOverridesChanged,
+ void(PhysicalDisplayId, std::vector<FrameRateOverride>));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_METHOD2(setDuration,
void(std::chrono::nanoseconds workDuration,