Merge "SF: Add DisplayDevice::getDebugName()"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4ccb917..08218b8 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -9,6 +9,7 @@
libs/renderengine/
libs/ui/
libs/vr/
+ services/bufferhub/
services/surfaceflinger/
services/vr/
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d950b7c..d6ca0bf 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -91,7 +91,12 @@
chmod 0666 /sys/kernel/tracing/events/sync/enable
chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
chmod 0666 /sys/kernel/tracing/events/fence/enable
-
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable
+ chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable
+ chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable
+ chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable
# disk
chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 260ea4b..71658d8 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -87,27 +87,27 @@
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
dprintf(fd, "id: %d\n", ds_.id_);
dprintf(fd, "pid: %d\n", ds_.pid_);
- dprintf(fd, "update_progress: %s\n", ds_.update_progress_ ? "true" : "false");
+ dprintf(fd, "update_progress: %s\n", ds_.options_->do_progress_updates ? "true" : "false");
dprintf(fd, "update_progress_threshold: %d\n", ds_.update_progress_threshold_);
dprintf(fd, "last_updated_progress: %d\n", ds_.last_updated_progress_);
dprintf(fd, "progress:\n");
ds_.progress_->Dump(fd, " ");
- dprintf(fd, "args: %s\n", ds_.args_.c_str());
- dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
+ dprintf(fd, "args: %s\n", ds_.options_->args.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
dprintf(fd, "version: %s\n", ds_.version_.c_str());
dprintf(fd, "bugreport_dir: %s\n", ds_.bugreport_dir_.c_str());
dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
dprintf(fd, "path: %s\n", ds_.path_.c_str());
- dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str());
dprintf(fd, "name: %s\n", ds_.name_.c_str());
dprintf(fd, "now: %ld\n", ds_.now_);
dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
- dprintf(fd, "notification title: %s\n", ds_.notification_title.c_str());
- dprintf(fd, "notification description: %s\n", ds_.notification_description.c_str());
+ dprintf(fd, "notification title: %s\n", ds_.options_->notification_title.c_str());
+ dprintf(fd, "notification description: %s\n", ds_.options_->notification_description.c_str());
return NO_ERROR;
}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 17bb7c3..0b9bca0 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -682,7 +682,7 @@
CommandOptions::WithTimeout(1).Always().Build());
printf("Bugreport format version: %s\n", version_.c_str());
printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
- PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
+ PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
printf("\n");
}
@@ -1623,7 +1623,7 @@
printf("*** See dumpstate-board.txt entry ***\n");
}
-static void ShowUsageAndExit(int exitCode = 1) {
+static void ShowUsageAndExit(int exit_code = 1) {
fprintf(stderr,
"usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
"[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1643,7 +1643,7 @@
" -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
"shouldn't be used with -P)\n"
" -v: prints the dumpstate header and exit\n");
- exit(exitCode);
+ exit(exit_code);
}
static void ExitOnInvalidArgs() {
@@ -1769,13 +1769,13 @@
* if we are writing zip files and adds the version file.
*/
static void PrepareToWriteToFile() {
- const Dumpstate::DumpOptions& options = ds.options_;
- ds.bugreport_dir_ = dirname(options.use_outfile.c_str());
+ ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
- ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(options.use_outfile.c_str()),
- device_name.c_str(), build_id.c_str());
- if (options.do_add_date) {
+ ds.base_name_ =
+ android::base::StringPrintf("%s-%s-%s", basename(ds.options_->use_outfile.c_str()),
+ device_name.c_str(), build_id.c_str());
+ if (ds.options_->do_add_date) {
char date[80];
strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
ds.name_ = date;
@@ -1783,13 +1783,13 @@
ds.name_ = "undated";
}
- if (options.telephony_only) {
+ if (ds.options_->telephony_only) {
ds.base_name_ += "-telephony";
- } else if (options.wifi_only) {
+ } else if (ds.options_->wifi_only) {
ds.base_name_ += "-wifi";
}
- if (options.do_fb) {
+ if (ds.options_->do_fb) {
ds.screenshot_path_ = ds.GetPath(".png");
}
ds.tmp_path_ = ds.GetPath(".tmp");
@@ -1805,7 +1805,7 @@
ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
- if (options.do_zip_file) {
+ if (ds.options_->do_zip_file) {
ds.path_ = ds.GetPath(".zip");
MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
create_parent_dirs(ds.path_.c_str());
@@ -1824,7 +1824,6 @@
* printing zipped file status, etc.
*/
static void FinalizeFile() {
- const Dumpstate::DumpOptions& options = ds.options_;
/* check if user changed the suffix using system properties */
std::string name =
android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
@@ -1853,7 +1852,7 @@
}
bool do_text_file = true;
- if (options.do_zip_file) {
+ if (ds.options_->do_zip_file) {
if (!ds.FinishZipFile()) {
MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
do_text_file = true;
@@ -1880,7 +1879,7 @@
ds.path_.clear();
}
}
- if (options.use_control_socket) {
+ if (ds.options_->use_control_socket) {
if (do_text_file) {
dprintf(ds.control_socket_fd_,
"FAIL:could not create zip file, check %s "
@@ -1894,7 +1893,6 @@
/* Broadcasts that we are done with the bugreport */
static void SendBugreportFinishedBroadcast() {
- const Dumpstate::DumpOptions& options = ds.options_;
if (!ds.path_.empty()) {
MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
// clang-format off
@@ -1908,22 +1906,22 @@
"--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
};
// clang-format on
- if (options.do_fb) {
+ if (ds.options_->do_fb) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.SCREENSHOT");
am_args.push_back(ds.screenshot_path_);
}
- if (!ds.notification_title.empty()) {
+ if (ds.options_->notification_title.empty()) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.TITLE");
- am_args.push_back(ds.notification_title);
- if (!ds.notification_description.empty()) {
+ am_args.push_back(ds.options_->notification_title);
+ if (!ds.options_->notification_description.empty()) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.DESCRIPTION");
- am_args.push_back(ds.notification_description);
+ am_args.push_back(ds.options_->notification_description);
}
}
- if (options.is_remote_mode) {
+ if (ds.options_->is_remote_mode) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
am_args.push_back(SHA256_file_hash(ds.path_));
@@ -1936,30 +1934,77 @@
}
}
-int Dumpstate::ParseCommandlineOptions(int argc, char* argv[]) {
- int ret = -1; // success
+// TODO: Move away from system properties when we have options passed via binder calls.
+/* Sets runtime options from the system properties and then clears those properties. */
+static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
+ options->extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
+ if (!options->extra_options.empty()) {
+ // Framework uses a system property to override some command-line args.
+ // Currently, it contains the type of the requested bugreport.
+ if (options->extra_options == "bugreportplus") {
+ // Currently, the dumpstate binder is only used by Shell to update progress.
+ options->do_start_service = true;
+ options->do_progress_updates = true;
+ options->do_fb = false;
+ } else if (options->extra_options == "bugreportremote") {
+ options->do_vibrate = false;
+ options->is_remote_mode = true;
+ options->do_fb = false;
+ } else if (options->extra_options == "bugreportwear") {
+ options->do_start_service = true;
+ options->do_progress_updates = true;
+ options->do_zip_file = true;
+ } else if (options->extra_options == "bugreporttelephony") {
+ options->telephony_only = true;
+ } else if (options->extra_options == "bugreportwifi") {
+ options->wifi_only = true;
+ options->do_zip_file = true;
+ } else {
+ MYLOGE("Unknown extra option: %s\n", options->extra_options.c_str());
+ }
+ // Reset the property
+ android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
+ }
+
+ options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
+ if (!options->notification_title.empty()) {
+ // Reset the property
+ android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
+
+ options->extra_options = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+ if (!options->notification_description.empty()) {
+ // Reset the property
+ android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+ }
+ MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
+ options->notification_description.c_str());
+ }
+}
+
+Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
+ RunStatus status = RunStatus::OK;
int c;
while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
switch (c) {
// clang-format off
- case 'd': options_.do_add_date = true; break;
- case 'z': options_.do_zip_file = true; break;
- case 'o': options_.use_outfile = optarg; break;
- case 's': options_.use_socket = true; break;
- case 'S': options_.use_control_socket = true; break;
- case 'v': options_.show_header_only = true; break;
- case 'q': options_.do_vibrate = false; break;
- case 'p': options_.do_fb = true; break;
- case 'P': update_progress_ = true; break;
- case 'R': options_.is_remote_mode = true; break;
- case 'B': options_.do_broadcast = true; break;
- case 'V': break; // compatibility no-op
+ case 'd': do_add_date = true; break;
+ case 'z': do_zip_file = true; break;
+ case 'o': use_outfile = optarg; break;
+ case 's': use_socket = true; break;
+ case 'S': use_control_socket = true; break;
+ case 'v': show_header_only = true; break;
+ case 'q': do_vibrate = false; break;
+ case 'p': do_fb = true; break;
+ case 'P': do_progress_updates = true; break;
+ case 'R': is_remote_mode = true; break;
+ case 'B': do_broadcast = true; break;
+ case 'V': break; // compatibility no-op
case 'h':
- ret = 0;
+ status = RunStatus::HELP;
break;
default:
fprintf(stderr, "Invalid option: %c\n", c);
- ret = 1;
+ status = RunStatus::INVALID_INPUT;
break;
// clang-format on
}
@@ -1967,87 +2012,44 @@
// TODO: use helper function to convert argv into a string
for (int i = 0; i < argc; i++) {
- args_ += argv[i];
+ args += argv[i];
if (i < argc - 1) {
- args_ += " ";
+ args += " ";
}
}
// Reset next index used by getopt so this can be called multiple times, for eg, in tests.
optind = 1;
- return ret;
+
+ SetOptionsFromProperties(this);
+ return status;
}
-// TODO: Move away from system properties when we have binder.
-void Dumpstate::SetOptionsFromProperties() {
- extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
- if (!extra_options_.empty()) {
- // Framework uses a system property to override some command-line args.
- // Currently, it contains the type of the requested bugreport.
- if (extra_options_ == "bugreportplus") {
- // Currently, the dumpstate binder is only used by Shell to update progress.
- options_.do_start_service = true;
- update_progress_ = true;
- options_.do_fb = false;
- } else if (extra_options_ == "bugreportremote") {
- options_.do_vibrate = false;
- options_.is_remote_mode = true;
- options_.do_fb = false;
- } else if (extra_options_ == "bugreportwear") {
- options_.do_start_service = true;
- update_progress_ = true;
- options_.do_zip_file = true;
- } else if (extra_options_ == "bugreporttelephony") {
- options_.telephony_only = true;
- } else if (extra_options_ == "bugreportwifi") {
- options_.wifi_only = true;
- options_.do_zip_file = true;
- } else {
- MYLOGE("Unknown extra option: %s\n", extra_options_.c_str());
- }
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
- }
-
- notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
- if (!notification_title.empty()) {
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
-
- notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
- if (!notification_description.empty()) {
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
- }
- MYLOGD("notification (title: %s, description: %s)\n", notification_title.c_str(),
- notification_description.c_str());
- }
-}
-
-bool Dumpstate::ValidateOptions() {
- if ((options_.do_zip_file || options_.do_add_date || ds.update_progress_ ||
- options_.do_broadcast) &&
- options_.use_outfile.empty()) {
+bool Dumpstate::DumpOptions::ValidateOptions() const {
+ if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast)
+ && use_outfile.empty()) {
return false;
}
- if (options_.use_control_socket && !options_.do_zip_file) {
+ if (use_control_socket && !do_zip_file) {
return false;
}
- if (ds.update_progress_ && !options_.do_broadcast) {
+ if (do_progress_updates && !do_broadcast) {
return false;
}
- if (options_.is_remote_mode && (ds.update_progress_ || !options_.do_broadcast ||
- !options_.do_zip_file || !options_.do_add_date)) {
+ if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
return false;
}
return true;
}
-/* Main entry point for dumpstate. */
-int run_main(int argc, char* argv[]) {
+Dumpstate::RunStatus Dumpstate::RunWithOptions(std::unique_ptr<DumpOptions> options) {
+ if (!options->ValidateOptions()) {
+ return RunStatus::INVALID_INPUT;
+ }
+ options_ = std::move(options);
/* set as high priority, and protect from OOM killer */
setpriority(PRIO_PROCESS, 0, -20);
@@ -2064,52 +2066,42 @@
}
}
- int status = ds.ParseCommandlineOptions(argc, argv);
- if (status != -1) {
- ShowUsageAndExit(status);
- }
- ds.SetOptionsFromProperties();
- if (!ds.ValidateOptions()) {
- ExitOnInvalidArgs();
+ if (version_ == VERSION_DEFAULT) {
+ version_ = VERSION_CURRENT;
}
- if (ds.version_ == VERSION_DEFAULT) {
- ds.version_ = VERSION_CURRENT;
- }
-
- if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
+ if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
- ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
+ version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
VERSION_SPLIT_ANR.c_str());
- exit(1);
+ return RunStatus::INVALID_INPUT;
}
- const Dumpstate::DumpOptions& options = ds.options_;
- if (options.show_header_only) {
- ds.PrintHeader();
- exit(0);
+ if (options_->show_header_only) {
+ PrintHeader();
+ return RunStatus::OK;
}
// Redirect output if needed
- bool is_redirecting = !options.use_socket && !options.use_outfile.empty();
+ bool is_redirecting = !options_->use_socket && !options_->use_outfile.empty();
// TODO: temporarily set progress until it's part of the Dumpstate constructor
- std::string stats_path = is_redirecting
- ? android::base::StringPrintf("%s/dumpstate-stats.txt",
- dirname(options.use_outfile.c_str()))
- : "";
- ds.progress_.reset(new Progress(stats_path));
+ std::string stats_path =
+ is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt",
+ dirname(options_->use_outfile.c_str()))
+ : "";
+ progress_.reset(new Progress(stats_path));
/* gets the sequential id */
uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
- ds.id_ = ++last_id;
+ id_ = ++last_id;
android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
MYLOGI("begin\n");
register_sig_handler();
- if (options.do_start_service) {
+ if (options_->do_start_service) {
MYLOGI("Starting 'dumpstate' service\n");
android::status_t ret;
if ((ret = android::os::DumpstateService::Start()) != android::OK) {
@@ -2121,43 +2113,43 @@
MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
}
- MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
- ds.extra_options_.c_str());
+ MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
+ options_->extra_options.c_str());
- MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
+ MYLOGI("bugreport format version: %s\n", version_.c_str());
- ds.do_early_screenshot_ = ds.update_progress_;
+ do_early_screenshot_ = options_->do_progress_updates;
// If we are going to use a socket, do it as early as possible
// to avoid timeouts from bugreport.
- if (options.use_socket) {
+ if (options_->use_socket) {
redirect_to_socket(stdout, "dumpstate");
}
- if (options.use_control_socket) {
+ if (options_->use_control_socket) {
MYLOGD("Opening control socket\n");
- ds.control_socket_fd_ = open_socket("dumpstate");
- ds.update_progress_ = 1;
+ control_socket_fd_ = open_socket("dumpstate");
+ options_->do_progress_updates = 1;
}
if (is_redirecting) {
PrepareToWriteToFile();
- if (ds.update_progress_) {
- if (options.do_broadcast) {
+ if (options_->do_progress_updates) {
+ if (options_->do_broadcast) {
// clang-format off
std::vector<std::string> am_args = {
"--receiver-permission", "android.permission.DUMP",
- "--es", "android.intent.extra.NAME", ds.name_,
- "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
- "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
- "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
+ "--es", "android.intent.extra.NAME", name_,
+ "--ei", "android.intent.extra.ID", std::to_string(id_),
+ "--ei", "android.intent.extra.PID", std::to_string(pid_),
+ "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
};
// clang-format on
SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
}
- if (options.use_control_socket) {
- dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
+ if (options_->use_control_socket) {
+ dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
}
}
}
@@ -2169,23 +2161,23 @@
fclose(cmdline);
}
- if (options.do_vibrate) {
+ if (options_->do_vibrate) {
Vibrate(150);
}
- if (options.do_fb && ds.do_early_screenshot_) {
- if (ds.screenshot_path_.empty()) {
+ if (options_->do_fb && do_early_screenshot_) {
+ if (screenshot_path_.empty()) {
// should not have happened
MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
} else {
MYLOGI("taking early screenshot\n");
- ds.TakeScreenshot();
+ TakeScreenshot();
}
}
- if (options.do_zip_file && ds.zip_file != nullptr) {
- if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
+ if (options_->do_zip_file && zip_file != nullptr) {
+ if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
+ MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
strerror(errno));
}
}
@@ -2194,19 +2186,19 @@
int dup_stderr_fd;
if (is_redirecting) {
TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
- redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
- if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
- ds.log_path_.c_str(), strerror(errno));
+ redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()));
+ if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
+ MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
+ strerror(errno));
}
TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
/* TODO: rather than generating a text file now and zipping it later,
it would be more efficient to redirect stdout to the zip entry
directly, but the libziparchive doesn't support that option yet. */
- redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str()));
- if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
+ redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()));
+ if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
- ds.tmp_path_.c_str(), strerror(errno));
+ tmp_path_.c_str(), strerror(errno));
}
}
@@ -2216,18 +2208,18 @@
// NOTE: there should be no stdout output until now, otherwise it would break the header.
// In particular, DurationReport objects should be created passing 'title, NULL', so their
// duration is logged into MYLOG instead.
- ds.PrintHeader();
+ PrintHeader();
- if (options.telephony_only) {
+ if (options_->telephony_only) {
DumpstateTelephonyOnly();
- ds.DumpstateBoard();
- } else if (options.wifi_only) {
+ DumpstateBoard();
+ } else if (options_->wifi_only) {
DumpstateWifiOnly();
} else {
// Dump state for the default case. This also drops root.
if (!DumpstateDefault()) {
// Something went wrong.
- return -1;
+ return RunStatus::ERROR;
}
}
@@ -2237,12 +2229,12 @@
}
/* rename or zip the (now complete) .tmp file to its final location */
- if (!options.use_outfile.empty()) {
+ if (!options_->use_outfile.empty()) {
FinalizeFile();
}
/* vibrate a few but shortly times to let user know it's finished */
- if (options.do_vibrate) {
+ if (options_->do_vibrate) {
for (int i = 0; i < 3; i++) {
Vibrate(75);
usleep((75 + 50) * 1000);
@@ -2250,26 +2242,51 @@
}
/* tell activity manager we're done */
- if (options.do_broadcast) {
+ if (options_->do_broadcast) {
SendBugreportFinishedBroadcast();
}
- MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
- ds.progress_->GetInitialMax());
- ds.progress_->Save();
- MYLOGI("done (id %d)\n", ds.id_);
+ MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
+ progress_->GetInitialMax());
+ progress_->Save();
+ MYLOGI("done (id %d)\n", id_);
if (is_redirecting) {
TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
}
- if (options.use_control_socket && ds.control_socket_fd_ != -1) {
+ if (options_->use_control_socket && control_socket_fd_ != -1) {
MYLOGD("Closing control socket\n");
- close(ds.control_socket_fd_);
+ close(control_socket_fd_);
}
- ds.tombstone_data_.clear();
- ds.anr_data_.clear();
+ tombstone_data_.clear();
+ anr_data_.clear();
+ return RunStatus::OK;
+}
+
+/* Main entry point for dumpstate. */
+int run_main(int argc, char* argv[]) {
+ std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
+ Dumpstate::RunStatus status = options->Initialize(argc, argv);
+ if (status == Dumpstate::RunStatus::OK) {
+ status = ds.RunWithOptions(std::move(options));
+ }
+
+ switch (status) {
+ case Dumpstate::RunStatus::OK:
+ return 0;
+ break;
+ case Dumpstate::RunStatus::HELP:
+ ShowUsageAndExit(0 /* exit code */);
+ break;
+ case Dumpstate::RunStatus::INVALID_INPUT:
+ ExitOnInvalidArgs();
+ break;
+ case Dumpstate::RunStatus::ERROR:
+ exit(-1);
+ break;
+ }
return 0;
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 389cc2e..c2f7f6a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -183,6 +183,8 @@
friend class DumpstateTest;
public:
+ enum RunStatus { OK, HELP, INVALID_INPUT, ERROR };
+
static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS;
static Dumpstate& GetInstance();
@@ -290,22 +292,12 @@
/* Returns true if the current version supports priority dump feature. */
bool CurrentVersionSupportsPriorityDumps() const;
- // TODO: revisit the return values later.
- /*
- * Parses commandline arguments and sets runtime options accordingly.
- *
- * Returns 0 or positive number if the caller should exit with returned value as
- * exit code, or returns -1 if caller should proceed with execution.
- */
- int ParseCommandlineOptions(int argc, char* argv[]);
+ struct DumpOptions;
- /* Sets runtime options from the system properties. */
- void SetOptionsFromProperties();
+ /* Main entry point for running a complete bugreport. Takes ownership of options. */
+ RunStatus RunWithOptions(std::unique_ptr<DumpOptions> options);
- /* Returns true if the options set so far are consistent. */
- bool ValidateOptions();
-
- // TODO: add update_progress_ & other options from DumpState.
+ // TODO: add other options from DumpState.
/*
* Structure to hold options that determine the behavior of dumpstate.
*/
@@ -322,7 +314,22 @@
bool do_start_service = false;
bool telephony_only = false;
bool wifi_only = false;
+ // Whether progress updates should be published.
+ bool do_progress_updates = false;
std::string use_outfile;
+ // Extra options passed as system property.
+ std::string extra_options;
+ // Command-line arguments as string
+ std::string args;
+ // Notification title and description
+ std::string notification_title;
+ std::string notification_description;
+
+ /* Initializes options from commandline arguments and system properties. */
+ RunStatus Initialize(int argc, char* argv[]);
+
+ /* Returns true if the options set so far are consistent. */
+ bool ValidateOptions() const;
};
// TODO: initialize fields on constructor
@@ -333,10 +340,7 @@
pid_t pid_;
// Runtime options.
- DumpOptions options_;
-
- // Whether progress updates should be published.
- bool update_progress_ = false;
+ std::unique_ptr<DumpOptions> options_;
// How frequently the progess should be updated;the listener will only be notificated when the
// delta from the previous update is more than the threshold.
@@ -356,12 +360,6 @@
// Bugreport format version;
std::string version_ = VERSION_CURRENT;
- // Command-line arguments as string
- std::string args_;
-
- // Extra options passed as system property.
- std::string extra_options_;
-
// Full path of the directory where the bugreport files will be written.
std::string bugreport_dir_;
@@ -398,10 +396,6 @@
std::string listener_name_;
bool report_section_;
- // Notification title and description
- std::string notification_title;
- std::string notification_description;
-
// List of open tombstone dump files.
std::vector<DumpData> tombstone_data_;
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index c57535a..b675c51 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -137,6 +137,175 @@
}
};
+class DumpOptionsTest : public Test {
+ public:
+ virtual ~DumpOptionsTest() {
+ }
+ virtual void SetUp() {
+ options_ = Dumpstate::DumpOptions();
+ }
+
+ Dumpstate::DumpOptions options_;
+};
+
+TEST_F(DumpOptionsTest, InitializeNone) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate")
+ };
+ // clang-format on
+
+ Dumpstate::DumpOptions options;
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ EXPECT_FALSE(options_.do_add_date);
+ EXPECT_FALSE(options_.do_zip_file);
+ EXPECT_EQ("", options_.use_outfile);
+ EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.show_header_only);
+ EXPECT_TRUE(options_.do_vibrate);
+ EXPECT_FALSE(options_.do_fb);
+ EXPECT_FALSE(options_.do_progress_updates);
+ EXPECT_FALSE(options_.is_remote_mode);
+ EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializePartial1) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate"),
+ const_cast<char*>("-d"),
+ const_cast<char*>("-z"),
+ const_cast<char*>("-o abc"),
+ const_cast<char*>("-s"),
+ const_cast<char*>("-S"),
+
+ };
+ // clang-format on
+
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ EXPECT_TRUE(options_.do_add_date);
+ EXPECT_TRUE(options_.do_zip_file);
+ // TODO: Maybe we should trim the filename
+ EXPECT_EQ(" abc", std::string(options_.use_outfile));
+ EXPECT_TRUE(options_.use_socket);
+ EXPECT_TRUE(options_.use_control_socket);
+
+ // Other options retain default values
+ EXPECT_FALSE(options_.show_header_only);
+ EXPECT_TRUE(options_.do_vibrate);
+ EXPECT_FALSE(options_.do_fb);
+ EXPECT_FALSE(options_.do_progress_updates);
+ EXPECT_FALSE(options_.is_remote_mode);
+ EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializePartial2) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate"),
+ const_cast<char*>("-v"),
+ const_cast<char*>("-q"),
+ const_cast<char*>("-p"),
+ const_cast<char*>("-P"),
+ const_cast<char*>("-R"),
+ const_cast<char*>("-B"),
+ };
+ // clang-format on
+
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ EXPECT_TRUE(options_.show_header_only);
+ EXPECT_FALSE(options_.do_vibrate);
+ EXPECT_TRUE(options_.do_fb);
+ EXPECT_TRUE(options_.do_progress_updates);
+ EXPECT_TRUE(options_.is_remote_mode);
+ EXPECT_TRUE(options_.do_broadcast);
+
+ // Other options retain default values
+ EXPECT_FALSE(options_.do_add_date);
+ EXPECT_FALSE(options_.do_zip_file);
+ EXPECT_EQ("", options_.use_outfile);
+ EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.use_control_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeHelp) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate"),
+ const_cast<char*>("-h")
+ };
+ // clang-format on
+
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ // -h is for help.
+ EXPECT_EQ(status, Dumpstate::RunStatus::HELP);
+}
+
+TEST_F(DumpOptionsTest, InitializeUnknown) {
+ // clang-format off
+ char* argv[] = {
+ const_cast<char*>("dumpstate"),
+ const_cast<char*>("-u") // unknown flag
+ };
+ // clang-format on
+
+ Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+ // -u is unknown.
+ EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
+ options_.do_zip_file = true;
+ EXPECT_FALSE(options_.ValidateOptions());
+ options_.use_outfile = "a/b/c";
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
+ options_.do_broadcast = true;
+ EXPECT_FALSE(options_.ValidateOptions());
+ options_.use_outfile = "a/b/c";
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) {
+ options_.use_control_socket = true;
+ EXPECT_FALSE(options_.ValidateOptions());
+
+ options_.do_zip_file = true;
+ options_.use_outfile = "a/b/c"; // do_zip_file needs outfile
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
+ options_.do_progress_updates = true;
+ options_.use_outfile = "a/b/c"; // do_progress_updates needs outfile
+ EXPECT_FALSE(options_.ValidateOptions());
+
+ options_.do_broadcast = true;
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
+ options_.is_remote_mode = true;
+ EXPECT_FALSE(options_.ValidateOptions());
+
+ options_.do_broadcast = true;
+ options_.do_zip_file = true;
+ options_.do_add_date = true;
+ options_.use_outfile = "a/b/c"; // do_broadcast needs outfile
+ EXPECT_TRUE(options_.ValidateOptions());
+}
+
class DumpstateTest : public DumpstateBaseTest {
public:
void SetUp() {
@@ -144,9 +313,8 @@
SetDryRun(false);
SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
ds.progress_.reset(new Progress());
- ds.update_progress_ = false;
ds.update_progress_threshold_ = 0;
- ds.options_ = Dumpstate::DumpOptions();
+ ds.options_.reset(new Dumpstate::DumpOptions());
}
// Runs a command and capture `stdout` and `stderr`.
@@ -171,7 +339,7 @@
}
void SetProgress(long progress, long initial_max, long threshold = 0) {
- ds.update_progress_ = true;
+ ds.options_->do_progress_updates = true;
ds.update_progress_threshold_ = threshold;
ds.last_updated_progress_ = 0;
ds.progress_.reset(new Progress(initial_max, progress, 1.2));
@@ -204,157 +372,6 @@
Dumpstate& ds = Dumpstate::GetInstance();
};
-TEST_F(DumpstateTest, ParseCommandlineOptionsNone) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate")
- };
- // clang-format on
-
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
- EXPECT_EQ(-1, ret);
- EXPECT_FALSE(ds.options_.do_add_date);
- EXPECT_FALSE(ds.options_.do_zip_file);
- EXPECT_EQ("", ds.options_.use_outfile);
- EXPECT_FALSE(ds.options_.use_socket);
- EXPECT_FALSE(ds.options_.use_control_socket);
- EXPECT_FALSE(ds.options_.show_header_only);
- EXPECT_TRUE(ds.options_.do_vibrate);
- EXPECT_FALSE(ds.options_.do_fb);
- EXPECT_FALSE(ds.update_progress_);
- EXPECT_FALSE(ds.options_.is_remote_mode);
- EXPECT_FALSE(ds.options_.do_broadcast);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsPartial1) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate"),
- const_cast<char*>("-d"),
- const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
- const_cast<char*>("-s"),
- const_cast<char*>("-S"),
-
- };
- // clang-format on
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
- EXPECT_EQ(-1, ret);
- EXPECT_TRUE(ds.options_.do_add_date);
- EXPECT_TRUE(ds.options_.do_zip_file);
- // TODO: Maybe we should trim the filename
- EXPECT_EQ(" abc", std::string(ds.options_.use_outfile));
- EXPECT_TRUE(ds.options_.use_socket);
- EXPECT_TRUE(ds.options_.use_control_socket);
-
- // Other options retain default values
- EXPECT_FALSE(ds.options_.show_header_only);
- EXPECT_TRUE(ds.options_.do_vibrate);
- EXPECT_FALSE(ds.options_.do_fb);
- EXPECT_FALSE(ds.update_progress_);
- EXPECT_FALSE(ds.options_.is_remote_mode);
- EXPECT_FALSE(ds.options_.do_broadcast);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsPartial2) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate"),
- const_cast<char*>("-v"),
- const_cast<char*>("-q"),
- const_cast<char*>("-p"),
- const_cast<char*>("-P"),
- const_cast<char*>("-R"),
- const_cast<char*>("-B"),
- };
- // clang-format on
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
- EXPECT_EQ(-1, ret);
- EXPECT_TRUE(ds.options_.show_header_only);
- EXPECT_FALSE(ds.options_.do_vibrate);
- EXPECT_TRUE(ds.options_.do_fb);
- EXPECT_TRUE(ds.update_progress_);
- EXPECT_TRUE(ds.options_.is_remote_mode);
- EXPECT_TRUE(ds.options_.do_broadcast);
-
- // Other options retain default values
- EXPECT_FALSE(ds.options_.do_add_date);
- EXPECT_FALSE(ds.options_.do_zip_file);
- EXPECT_EQ("", ds.options_.use_outfile);
- EXPECT_FALSE(ds.options_.use_socket);
- EXPECT_FALSE(ds.options_.use_control_socket);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsHelp) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate"),
- const_cast<char*>("-h")
- };
- // clang-format on
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-
- // -h is for help. Caller exit with code = 0 after printing usage, so expect return = 0.
- EXPECT_EQ(0, ret);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsUnknown) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("dumpstate"),
- const_cast<char*>("-u") // unknown flag
- };
- // clang-format on
- int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-
- // -u is unknown. Caller exit with code = 1 to show execution failure, after printing usage,
- // so expect return = 1.
- EXPECT_EQ(1, ret);
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedOutfile1) {
- ds.options_.do_zip_file = true;
- EXPECT_FALSE(ds.ValidateOptions());
- ds.options_.use_outfile = "a/b/c";
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedOutfile2) {
- ds.options_.do_broadcast = true;
- EXPECT_FALSE(ds.ValidateOptions());
- ds.options_.use_outfile = "a/b/c";
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedZipfile) {
- ds.options_.use_control_socket = true;
- EXPECT_FALSE(ds.ValidateOptions());
-
- ds.options_.do_zip_file = true;
- ds.options_.use_outfile = "a/b/c"; // do_zip_file needs outfile
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
- ds.update_progress_ = true;
- ds.options_.use_outfile = "a/b/c"; // update_progress_ needs outfile
- EXPECT_FALSE(ds.ValidateOptions());
-
- ds.options_.do_broadcast = true;
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsRemoteMode) {
- ds.options_.is_remote_mode = true;
- EXPECT_FALSE(ds.ValidateOptions());
-
- ds.options_.do_broadcast = true;
- ds.options_.do_zip_file = true;
- ds.options_.do_add_date = true;
- ds.options_.use_outfile = "a/b/c"; // do_broadcast needs outfile
- EXPECT_TRUE(ds.ValidateOptions());
-}
-
TEST_F(DumpstateTest, RunCommandNoArgs) {
EXPECT_EQ(-1, RunCommand("", {}));
}
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 77f09b7..4ad5c4b 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -916,7 +916,7 @@
bool max_changed = progress_->Inc(delta_sec);
// ...but only notifiy listeners when necessary.
- if (!update_progress_) return;
+ if (!options_->do_progress_updates) return;
int progress = progress_->Get();
int max = progress_->GetMax();
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 9d0d8ba..2e9701f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -14,6 +14,7 @@
"CacheItem.cpp",
"CacheTracker.cpp",
"InstalldNativeService.cpp",
+ "QuotaUtils.cpp",
"dexopt.cpp",
"globals.cpp",
"utils.cpp",
@@ -33,6 +34,21 @@
"libutils",
],
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
+
clang: true,
tidy: true,
@@ -59,6 +75,26 @@
aidl: {
export_aidl_headers: true,
},
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
+}
+
+cc_library_headers {
+ name: "libinstalld_headers",
+ export_include_dirs: ["."],
}
//
@@ -73,6 +109,21 @@
static_libs: ["libdiskusage"],
init_rc: ["installd.rc"],
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
}
// OTA chroot tool
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index a7242c3..8b868fb 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -19,13 +19,13 @@
#include "CacheTracker.h"
#include <fts.h>
-#include <sys/quota.h>
#include <sys/xattr.h>
#include <utils/Trace.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "QuotaUtils.h"
#include "utils.h"
using android::base::StringPrintf;
@@ -33,9 +33,13 @@
namespace android {
namespace installd {
-CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
- cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
- mItemsLoaded(false) {
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& uuid)
+ : cacheUsed(0),
+ cacheQuota(0),
+ mUserId(userId),
+ mAppId(appId),
+ mItemsLoaded(false),
+ mUuid(uuid) {
}
CacheTracker::~CacheTracker() {
@@ -72,26 +76,18 @@
bool CacheTracker::loadQuotaStats() {
int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId);
- if (!mQuotaDevice.empty() && cacheGid != -1 && extCacheGid != -1) {
- struct dqblk dq;
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
- }
- return false;
+ if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) {
+ int64_t space;
+ if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) {
+ cacheUsed += space;
} else {
- cacheUsed += dq.dqb_curspace;
+ return false;
}
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), extCacheGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
- }
- return false;
+ if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) {
+ cacheUsed += space;
} else {
- cacheUsed += dq.dqb_curspace;
+ return false;
}
return true;
} else {
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
index 44359b4..b0527e7 100644
--- a/cmds/installd/CacheTracker.h
+++ b/cmds/installd/CacheTracker.h
@@ -39,7 +39,7 @@
*/
class CacheTracker {
public:
- CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+ CacheTracker(userid_t userId, appid_t appId, const std::string& uuid);
~CacheTracker();
std::string toString();
@@ -61,8 +61,8 @@
private:
userid_t mUserId;
appid_t mAppId;
- std::string mQuotaDevice;
bool mItemsLoaded;
+ const std::string& mUuid;
std::vector<std::string> mDataPaths;
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a475fcc..81055d8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -31,7 +31,6 @@
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
-#include <sys/quota.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@@ -64,6 +63,7 @@
#include "CacheTracker.h"
#include "MatchExtensionGen.h"
+#include "QuotaUtils.h"
#ifndef LOG_TAG
#define LOG_TAG "installd"
@@ -257,11 +257,6 @@
for (const auto& n : mStorageMounts) {
out << " " << n.first << " = " << n.second << endl;
}
-
- out << endl << "Quota reverse mounts:" << endl;
- for (const auto& n : mQuotaReverseMounts) {
- out << " " << n.first << " = " << n.second << endl;
- }
}
{
@@ -988,9 +983,9 @@
CHECK_ARGUMENT_UUID(uuid);
std::lock_guard<std::recursive_mutex> lock(mLock);
+ auto uuidString = uuid ? *uuid : "";
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
auto data_path = create_data_path(uuid_);
- auto device = findQuotaDeviceForUuid(uuid);
auto noop = (flags & FLAG_FREE_CACHE_NOOP);
int64_t free = data_disk_free(data_path);
@@ -1037,7 +1032,7 @@
search->second->addDataPath(p->fts_path);
} else {
auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
- multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+ multiuser_get_user_id(uid), multiuser_get_app_id(uid), uuidString));
tracker->addDataPath(p->fts_path);
{
std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
@@ -1202,53 +1197,26 @@
}
#endif
-static void collectQuotaStats(const std::string& device, int32_t userId,
+static void collectQuotaStats(const std::string& uuid, int32_t userId,
int32_t appId, struct stats* stats, struct stats* extStats) {
- if (device.empty()) return;
-
- struct dqblk dq;
-
+ int64_t space;
if (stats != nullptr) {
uid_t uid = multiuser_get_uid(userId, appId);
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
- stats->dataSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+ stats->dataSize += space;
}
int cacheGid = multiuser_get_cache_gid(userId, appId);
if (cacheGid != -1) {
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
-#endif
- stats->cacheSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+ stats->cacheSize += space;
}
}
int sharedGid = multiuser_get_shared_gid(0, appId);
if (sharedGid != -1) {
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
-#endif
- stats->codeSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) {
+ stats->codeSize += space;
}
}
}
@@ -1256,32 +1224,16 @@
if (extStats != nullptr) {
int extGid = multiuser_get_ext_gid(userId, appId);
if (extGid != -1) {
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
-#endif
- extStats->dataSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) {
+ extStats->dataSize += space;
}
}
int extCacheGid = multiuser_get_ext_cache_gid(userId, appId);
if (extCacheGid != -1) {
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extCacheGid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extCacheGid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << extCacheGid << " " << dq.dqb_curspace;
-#endif
- extStats->dataSize += dq.dqb_curspace;
- extStats->cacheSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) {
+ extStats->dataSize += space;
+ extStats->cacheSize += space;
}
}
}
@@ -1445,10 +1397,10 @@
memset(&stats, 0, sizeof(stats));
memset(&extStats, 0, sizeof(extStats));
+ auto uuidString = uuid ? *uuid : "";
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- auto device = findQuotaDeviceForUuid(uuid);
- if (device.empty()) {
+ if (!IsQuotaSupported(uuidString)) {
flags &= ~FLAG_USE_QUOTA;
}
@@ -1468,7 +1420,7 @@
ATRACE_END();
ATRACE_BEGIN("quota");
- collectQuotaStats(device, userId, appId, &stats, &extStats);
+ collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
ATRACE_END();
} else {
ATRACE_BEGIN("code");
@@ -1553,27 +1505,19 @@
memset(&stats, 0, sizeof(stats));
memset(&extStats, 0, sizeof(extStats));
+ auto uuidString = uuid ? *uuid : "";
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- auto device = findQuotaDeviceForUuid(uuid);
- if (device.empty()) {
+ if (!IsQuotaSupported(uuidString)) {
flags &= ~FLAG_USE_QUOTA;
}
if (flags & FLAG_USE_QUOTA) {
- struct dqblk dq;
+ int64_t space;
ATRACE_BEGIN("obb");
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
- extStats.codeSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+ extStats.codeSize += space;
}
ATRACE_END();
@@ -1599,16 +1543,8 @@
ATRACE_BEGIN("external");
uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
- extStats.dataSize += dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+ extStats.dataSize += space;
}
ATRACE_END();
@@ -1625,7 +1561,7 @@
int64_t dataSize = extStats.dataSize;
for (auto appId : appIds) {
if (appId >= AID_APP_START) {
- collectQuotaStats(device, userId, appId, &stats, &extStats);
+ collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
#if MEASURE_DEBUG
// Sleep to make sure we don't lose logs
@@ -1707,6 +1643,7 @@
LOG(INFO) << "Measuring external " << userId;
#endif
+ auto uuidString = uuid ? *uuid : "";
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
int64_t totalSize = 0;
@@ -1716,58 +1653,33 @@
int64_t appSize = 0;
int64_t obbSize = 0;
- auto device = findQuotaDeviceForUuid(uuid);
- if (device.empty()) {
+ if (!IsQuotaSupported(uuidString)) {
flags &= ~FLAG_USE_QUOTA;
}
if (flags & FLAG_USE_QUOTA) {
- struct dqblk dq;
+ int64_t space;
ATRACE_BEGIN("quota");
uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
- reinterpret_cast<char*>(&dq)) != 0) {
- if (errno != ESRCH) {
- PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
- }
- } else {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
- totalSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+ totalSize = space;
}
gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
- reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
-#endif
- audioSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) {
+ audioSize = space;
}
gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
- reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
-#endif
- videoSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) {
+ videoSize = space;
}
gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
- reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
-#endif
- imageSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) {
+ imageSize = space;
}
- if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
- reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
- obbSize = dq.dqb_curspace;
+ if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+ obbSize = space;
}
ATRACE_END();
@@ -1776,7 +1688,7 @@
memset(&extStats, 0, sizeof(extStats));
for (auto appId : appIds) {
if (appId >= AID_APP_START) {
- collectQuotaStats(device, userId, appId, nullptr, &extStats);
+ collectQuotaStats(uuidString, userId, appId, nullptr, &extStats);
}
}
appSize = extStats.dataSize;
@@ -2564,7 +2476,12 @@
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
mStorageMounts.clear();
- mQuotaReverseMounts.clear();
+
+#if !BYPASS_QUOTA
+ if (!InvalidateQuotaMounts()) {
+ return error("Failed to read mounts");
+ }
+#endif
std::ifstream in("/proc/mounts");
if (!in.is_open()) {
@@ -2585,17 +2502,6 @@
mStorageMounts[source] = target;
}
#endif
-
-#if !BYPASS_QUOTA
- if (source.compare(0, 11, "/dev/block/") == 0) {
- struct dqblk dq;
- if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
- reinterpret_cast<char*>(&dq)) == 0) {
- LOG(DEBUG) << "Found quota mount " << source << " at " << target;
- mQuotaReverseMounts[target] = source;
- }
- }
-#endif
}
return ok();
}
@@ -2613,16 +2519,10 @@
return StringPrintf("%s/%u", resolved.c_str(), userid);
}
-std::string InstalldNativeService::findQuotaDeviceForUuid(
- const std::unique_ptr<std::string>& uuid) {
- std::lock_guard<std::recursive_mutex> lock(mMountsLock);
- auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
- return mQuotaReverseMounts[path];
-}
-
binder::Status InstalldNativeService::isQuotaSupported(
- const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) {
- *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty();
+ const std::unique_ptr<std::string>& uuid, bool* _aidl_return) {
+ auto uuidString = uuid ? *uuid : "";
+ *_aidl_return = IsQuotaSupported(uuidString);
return ok();
}
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index cebd3f9..367f2c1 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -150,14 +150,11 @@
/* Map of all storage mounts from source to target */
std::unordered_map<std::string, std::string> mStorageMounts;
- /* Map of all quota mounts from target to source */
- std::unordered_map<std::string, std::string> mQuotaReverseMounts;
/* Map from UID to cache quota size */
std::unordered_map<uid_t, int64_t> mCacheQuotas;
std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid);
- std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
};
} // namespace installd
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
new file mode 100644
index 0000000..b238dd3
--- /dev/null
+++ b/cmds/installd/QuotaUtils.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QuotaUtils.h"
+
+#include <fstream>
+#include <unordered_map>
+
+#include <sys/quota.h>
+
+#include <android-base/logging.h>
+
+#include "utils.h"
+
+namespace android {
+namespace installd {
+
+namespace {
+
+std::recursive_mutex mMountsLock;
+
+/* Map of all quota mounts from target to source */
+std::unordered_map<std::string, std::string> mQuotaReverseMounts;
+
+std::string& FindQuotaDeviceForUuid(const std::string& uuid) {
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+ auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str());
+ return mQuotaReverseMounts[path];
+}
+
+} // namespace
+
+bool InvalidateQuotaMounts() {
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
+ mQuotaReverseMounts.clear();
+
+ std::ifstream in("/proc/mounts");
+ if (!in.is_open()) {
+ return false;
+ }
+
+ std::string source;
+ std::string target;
+ std::string ignored;
+ while (!in.eof()) {
+ std::getline(in, source, ' ');
+ std::getline(in, target, ' ');
+ std::getline(in, ignored);
+
+ if (source.compare(0, 11, "/dev/block/") == 0) {
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+ reinterpret_cast<char*>(&dq)) == 0) {
+ LOG(DEBUG) << "Found quota mount " << source << " at " << target;
+ mQuotaReverseMounts[target] = source;
+ }
+ }
+ }
+ return true;
+}
+
+bool IsQuotaSupported(const std::string& uuid) {
+ return !FindQuotaDeviceForUuid(uuid).empty();
+}
+
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) {
+ const std::string device = FindQuotaDeviceForUuid(uuid);
+ if (device == "") {
+ return -1;
+ }
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+ }
+ return -1;
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+ return dq.dqb_curspace;
+ }
+}
+
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) {
+ const std::string device = FindQuotaDeviceForUuid(uuid);
+ if (device == "") {
+ return -1;
+ }
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), gid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << gid;
+ }
+ return -1;
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << gid << " " << dq.dqb_curspace;
+#endif
+ return dq.dqb_curspace;
+ }
+
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h
new file mode 100644
index 0000000..9ad170f
--- /dev/null
+++ b/cmds/installd/QuotaUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_QUOTA_UTILS_H_
+#define ANDROID_INSTALLD_QUOTA_UTILS_H_
+
+#include <memory>
+#include <string>
+
+namespace android {
+namespace installd {
+
+/* Clear and recompute the reverse mounts map */
+bool InvalidateQuotaMounts();
+
+/* Whether quota is supported in the device with the given uuid */
+bool IsQuotaSupported(const std::string& uuid);
+
+/* Get the current occupied space in bytes for a uid or -1 if fails */
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid);
+
+/* Get the current occupied space in bytes for a gid or -1 if fails */
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid);
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_QUOTA_UTILS_H_
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 174ab21..90cadb4 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -54,6 +54,8 @@
#include "utils.h"
using android::base::EndsWith;
+using android::base::GetBoolProperty;
+using android::base::GetProperty;
using android::base::ReadFully;
using android::base::StringPrintf;
using android::base::WriteFully;
@@ -181,36 +183,11 @@
return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
}
-static int split_count(const char *str)
-{
- char *ctx;
- int count = 0;
- char buf[kPropertyValueMax];
-
- strlcpy(buf, str, sizeof(buf));
- char *pBuf = buf;
-
- while(strtok_r(pBuf, " ", &ctx) != nullptr) {
- count++;
- pBuf = nullptr;
- }
-
- return count;
-}
-
-static int split(char *buf, const char **argv)
-{
- char *ctx;
- int count = 0;
- char *tok;
- char *pBuf = buf;
-
- while((tok = strtok_r(pBuf, " ", &ctx)) != nullptr) {
- argv[count++] = tok;
- pBuf = nullptr;
- }
-
- return count;
+static std::vector<std::string> SplitBySpaces(const std::string& str) {
+ if (str.empty()) {
+ return {};
+ }
+ return android::base::Split(str, " ");
}
static const char* get_location_from_path(const char* path) {
@@ -224,6 +201,34 @@
}
}
+// Automatically adds binary and null terminator arg.
+static inline void ExecVWithArgs(const char* bin, const std::vector<std::string>& args) {
+ std::vector<const char*> argv = {bin};
+ for (const std::string& arg : args) {
+ argv.push_back(arg.c_str());
+ }
+ // Add null terminator.
+ argv.push_back(nullptr);
+ execv(bin, (char * const *)&argv[0]);
+}
+
+static inline void AddArgIfNonEmpty(const std::string& arg, std::vector<std::string>* args) {
+ DCHECK(args != nullptr);
+ if (!arg.empty()) {
+ args->push_back(arg);
+ }
+}
+
+static std::string MapPropertyToArg(const std::string& property,
+ const std::string& format,
+ const std::string& default_value = "") {
+ std::string prop = GetProperty(property, default_value);
+ if (!prop.empty()) {
+ return StringPrintf(format.c_str(), prop.c_str());
+ }
+ return "";
+}
+
[[ noreturn ]]
static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
const char* input_file_name, const char* output_file_name, int swap_fd,
@@ -231,82 +236,50 @@
bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
- static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
-
- if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
- LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
- << MAX_INSTRUCTION_SET_LEN;
- exit(DexoptReturnCodes::kInstructionSetLength);
- }
-
// Get the relative path to the input file.
const char* relative_input_file_name = get_location_from_path(input_file_name);
- char dex2oat_Xms_flag[kPropertyValueMax];
- bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, nullptr) > 0;
+ std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
+ std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
- char dex2oat_Xmx_flag[kPropertyValueMax];
- bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, nullptr) > 0;
+ const char* threads_property = post_bootcomplete
+ ? "dalvik.vm.dex2oat-threads"
+ : "dalvik.vm.boot-dex2oat-threads";
+ std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
- char dex2oat_threads_buf[kPropertyValueMax];
- bool have_dex2oat_threads_flag = get_property(post_bootcomplete
- ? "dalvik.vm.dex2oat-threads"
- : "dalvik.vm.boot-dex2oat-threads",
- dex2oat_threads_buf,
- nullptr) > 0;
- char dex2oat_threads_arg[kPropertyValueMax + 2];
- if (have_dex2oat_threads_flag) {
- sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
- }
+ const std::string dex2oat_isa_features_key =
+ StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+ std::string instruction_set_features_arg =
+ MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
- char dex2oat_isa_features_key[kPropertyKeyMax];
- sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
- char dex2oat_isa_features[kPropertyValueMax];
- bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
- dex2oat_isa_features, nullptr) > 0;
-
- char dex2oat_isa_variant_key[kPropertyKeyMax];
- sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
- char dex2oat_isa_variant[kPropertyValueMax];
- bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
- dex2oat_isa_variant, nullptr) > 0;
+ const std::string dex2oat_isa_variant_key =
+ StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+ std::string instruction_set_variant_arg =
+ MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
const char *dex2oat_norelocation = "-Xnorelocate";
- bool have_dex2oat_relocation_skip_flag = false;
- char dex2oat_flags[kPropertyValueMax];
- int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
- dex2oat_flags, nullptr) <= 0 ? 0 : split_count(dex2oat_flags);
- ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
+ const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
+ std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
+ ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
// If we are booting without the real /data, don't spend time compiling.
- char vold_decrypt[kPropertyValueMax];
- bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;
- bool skip_compilation = (have_vold_decrypt &&
- (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
- (strcmp(vold_decrypt, "1") == 0)));
+ std::string vold_decrypt = GetProperty("vold.decrypt", "");
+ bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+ vold_decrypt == "1";
- bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);
- const bool resolve_startup_strings =
- property_get_bool("dalvik.vm.dex2oat-resolve-startup-strings", false);
+ const std::string resolve_startup_string_arg =
+ MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+ "--resolve-startup-const-strings=%s");
+ const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
- char app_image_format[kPropertyValueMax];
- char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
- bool have_app_image_format =
- image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
- if (have_app_image_format) {
- sprintf(image_format_arg, "--image-format=%s", app_image_format);
+ std::string image_format_arg;
+ if (image_fd >= 0) {
+ image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
}
- char dex2oat_large_app_threshold[kPropertyValueMax];
- bool have_dex2oat_large_app_threshold =
- get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, nullptr) > 0;
- char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
- if (have_dex2oat_large_app_threshold) {
- sprintf(dex2oat_large_app_threshold_arg,
- "--very-large-app-threshold=%s",
- dex2oat_large_app_threshold);
- }
+ std::string dex2oat_large_app_threshold_arg =
+ MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
// If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
const char* dex2oat_bin = "/system/bin/dex2oat";
@@ -323,113 +296,65 @@
android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
kMinidebugInfoSystemPropertyDefault);
- static const char* RUNTIME_ARG = "--runtime-arg";
-
- static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
-
// clang FORTIFY doesn't let us use strlen in constant array bounds, so we
// use arraysize instead.
- char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN];
- char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX];
- char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN];
- char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN];
- char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN];
- char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX];
- char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
- char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax];
- char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax];
- char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax];
- char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax];
- char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax];
- bool have_dex2oat_swap_fd = false;
- char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
- bool have_dex2oat_image_fd = false;
- char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
- size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
- char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN];
- char class_loader_context_arg[class_loader_context_size];
+ std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
+ std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
+ std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
+ std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
+ std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
+ std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
+ std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
+ std::string dex2oat_compiler_filter_arg;
+ std::string dex2oat_swap_fd;
+ std::string dex2oat_image_fd;
+ std::string target_sdk_version_arg;
+ if (target_sdk_version != 0) {
+ StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+ }
+ std::string class_loader_context_arg;
if (class_loader_context != nullptr) {
- snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
- class_loader_context);
+ class_loader_context_arg = StringPrintf("--class-loader-context=%s", class_loader_context);
}
- sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
- sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
- sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);
- sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);
- sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
- sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
- sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
- sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
- sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
if (swap_fd >= 0) {
- have_dex2oat_swap_fd = true;
- sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
+ dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
}
if (image_fd >= 0) {
- have_dex2oat_image_fd = true;
- sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
+ dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
}
- if (have_dex2oat_Xms_flag) {
- sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);
- }
- if (have_dex2oat_Xmx_flag) {
- sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
- }
- sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version);
-
// Compute compiler filter.
-
- bool have_dex2oat_compiler_filter_flag = false;
+ bool have_dex2oat_relocation_skip_flag = false;
if (skip_compilation) {
- strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
- sizeof(dex2oat_compiler_filter_arg));
- have_dex2oat_compiler_filter_flag = true;
+ dex2oat_compiler_filter_arg = "--compiler-filter=extract";
have_dex2oat_relocation_skip_flag = true;
} else if (compiler_filter != nullptr) {
- if (strlen(compiler_filter) + strlen("--compiler-filter=") <
- arraysize(dex2oat_compiler_filter_arg)) {
- sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
- have_dex2oat_compiler_filter_flag = true;
- } else {
- ALOGW("Compiler filter name '%s' is too large (max characters is %zu)",
- compiler_filter,
- kPropertyValueMax);
- }
+ dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
}
- if (!have_dex2oat_compiler_filter_flag) {
- char dex2oat_compiler_filter_flag[kPropertyValueMax];
- have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
- dex2oat_compiler_filter_flag, nullptr) > 0;
- if (have_dex2oat_compiler_filter_flag) {
- sprintf(dex2oat_compiler_filter_arg,
- "--compiler-filter=%s",
- dex2oat_compiler_filter_flag);
- }
+ if (dex2oat_compiler_filter_arg.empty()) {
+ dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+ "--compiler-filter=%s");
}
// Check whether all apps should be compiled debuggable.
if (!debuggable) {
- char prop_buf[kPropertyValueMax];
- debuggable =
- (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
- (prop_buf[0] == '1');
+ debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
}
- char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
+ std::string profile_arg;
if (profile_fd != -1) {
- sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
+ profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
}
// Get the directory of the apk to pass as a base classpath directory.
- char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];
+ std::string base_dir;
std::string apk_dir(input_file_name);
unsigned long dir_index = apk_dir.rfind('/');
bool has_base_dir = dir_index != std::string::npos;
if (has_base_dir) {
apk_dir = apk_dir.substr(0, dir_index);
- sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
+ base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
}
std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
@@ -444,121 +369,69 @@
// supported.
const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
- const char* argv[10 // program name, mandatory arguments and the final NULL
- + (have_dex2oat_isa_variant ? 1 : 0)
- + (have_dex2oat_isa_features ? 1 : 0)
- + (have_dex2oat_Xms_flag ? 2 : 0)
- + (have_dex2oat_Xmx_flag ? 2 : 0)
- + (have_dex2oat_compiler_filter_flag ? 1 : 0)
- + (have_dex2oat_threads_flag ? 1 : 0)
- + (have_dex2oat_swap_fd ? 1 : 0)
- + (have_dex2oat_image_fd ? 1 : 0)
- + (have_dex2oat_relocation_skip_flag ? 2 : 0)
- + (generate_debug_info ? 1 : 0)
- + (debuggable ? 1 : 0)
- + (have_app_image_format ? 1 : 0)
- + dex2oat_flags_count
- + (profile_fd == -1 ? 0 : 1)
- + (class_loader_context != nullptr ? 1 : 0)
- + (has_base_dir ? 1 : 0)
- + (have_dex2oat_large_app_threshold ? 1 : 0)
- + (disable_cdex ? 1 : 0)
- + (generate_minidebug_info ? 1 : 0)
- + (target_sdk_version != 0 ? 2 : 0)
- + (enable_hidden_api_checks ? 2 : 0)
- + (dex_metadata_fd > -1 ? 1 : 0)
- + (compilation_reason != nullptr ? 1 : 0)];
- int i = 0;
- argv[i++] = dex2oat_bin;
- argv[i++] = zip_fd_arg;
- argv[i++] = zip_location_arg;
- argv[i++] = input_vdex_fd_arg;
- argv[i++] = output_vdex_fd_arg;
- argv[i++] = oat_fd_arg;
- argv[i++] = oat_location_arg;
- argv[i++] = instruction_set_arg;
- argv[i++] = resolve_startup_strings ? "--resolve-startup-const-strings=true" :
- "--resolve-startup-const-strings=false";
- if (have_dex2oat_isa_variant) {
- argv[i++] = instruction_set_variant_arg;
+ std::vector<std::string> args = {
+ zip_fd_arg,
+ zip_location_arg,
+ input_vdex_fd_arg,
+ output_vdex_fd_arg,
+ oat_fd_arg,
+ oat_location_arg,
+ instruction_set_arg,
+ };
+ auto add_runtime_arg = [&](const std::string& arg) {
+ args.push_back("--runtime-arg");
+ args.push_back(arg);
+ };
+
+ AddArgIfNonEmpty(instruction_set_variant_arg, &args);
+ AddArgIfNonEmpty(instruction_set_features_arg, &args);
+ if (!dex2oat_Xms_arg.empty()) {
+ add_runtime_arg(dex2oat_Xms_arg);
}
- if (have_dex2oat_isa_features) {
- argv[i++] = instruction_set_features_arg;
+ if (!dex2oat_Xmx_arg.empty()) {
+ add_runtime_arg(dex2oat_Xmx_arg);
}
- if (have_dex2oat_Xms_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_Xms_arg;
- }
- if (have_dex2oat_Xmx_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_Xmx_arg;
- }
- if (have_dex2oat_compiler_filter_flag) {
- argv[i++] = dex2oat_compiler_filter_arg;
- }
- if (have_dex2oat_threads_flag) {
- argv[i++] = dex2oat_threads_arg;
- }
- if (have_dex2oat_swap_fd) {
- argv[i++] = dex2oat_swap_fd;
- }
- if (have_dex2oat_image_fd) {
- argv[i++] = dex2oat_image_fd;
- }
+ AddArgIfNonEmpty(resolve_startup_string_arg, &args);
+ AddArgIfNonEmpty(dex2oat_compiler_filter_arg, &args);
+ AddArgIfNonEmpty(dex2oat_threads_arg, &args);
+ AddArgIfNonEmpty(dex2oat_swap_fd, &args);
+ AddArgIfNonEmpty(dex2oat_image_fd, &args);
+
if (generate_debug_info) {
- argv[i++] = "--generate-debug-info";
+ args.push_back("--generate-debug-info");
}
if (debuggable) {
- argv[i++] = "--debuggable";
+ args.push_back("--debuggable");
}
- if (have_app_image_format) {
- argv[i++] = image_format_arg;
- }
- if (have_dex2oat_large_app_threshold) {
- argv[i++] = dex2oat_large_app_threshold_arg;
- }
- if (dex2oat_flags_count) {
- i += split(dex2oat_flags, argv + i);
- }
+ AddArgIfNonEmpty(image_format_arg, &args);
+ AddArgIfNonEmpty(dex2oat_large_app_threshold_arg, &args);
+ args.insert(args.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
if (have_dex2oat_relocation_skip_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_norelocation;
+ add_runtime_arg(dex2oat_norelocation);
}
- if (profile_fd != -1) {
- argv[i++] = profile_arg;
- }
- if (has_base_dir) {
- argv[i++] = base_dir;
- }
- if (class_loader_context != nullptr) {
- argv[i++] = class_loader_context_arg;
- }
+ AddArgIfNonEmpty(profile_arg, &args);
+ AddArgIfNonEmpty(base_dir, &args);
+ AddArgIfNonEmpty(class_loader_context_arg, &args);
if (generate_minidebug_info) {
- argv[i++] = kMinidebugDex2oatFlag;
+ args.push_back(kMinidebugDex2oatFlag);
}
if (disable_cdex) {
- argv[i++] = kDisableCompactDexFlag;
+ args.push_back(kDisableCompactDexFlag);
}
- if (target_sdk_version != 0) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = target_sdk_version_arg;
- }
+ AddArgIfNonEmpty(target_sdk_version_arg, &args);
if (enable_hidden_api_checks) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = "-Xhidden-api-checks";
+ add_runtime_arg("-Xhidden-api-checks");
}
if (dex_metadata_fd > -1) {
- argv[i++] = dex_metadata_fd_arg.c_str();
+ args.push_back(dex_metadata_fd_arg);
}
- if(compilation_reason != nullptr) {
- argv[i++] = compilation_reason_arg.c_str();
- }
+ AddArgIfNonEmpty(compilation_reason_arg, &args);
+
// Do not add after dex2oat_flags, they should override others for debugging.
- argv[i] = nullptr;
- execv(dex2oat_bin, (char * const *)argv);
+ ExecVWithArgs(dex2oat_bin, args);
PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
exit(DexoptReturnCodes::kDex2oatExec);
}
@@ -584,13 +457,9 @@
}
// Check the "override" property. If it exists, return value == "true".
- char dex2oat_prop_buf[kPropertyValueMax];
- if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
- if (strcmp(dex2oat_prop_buf, "true") == 0) {
- return true;
- } else {
- return false;
- }
+ std::string dex2oat_prop_buf = GetProperty("dalvik.vm.dex2oat-swap", "");
+ if (!dex2oat_prop_buf.empty()) {
+ return dex2oat_prop_buf == "true";
}
// Shortcut for default value. This is an implementation optimization for the process sketched
@@ -600,8 +469,7 @@
return true;
}
- bool is_low_mem = property_get_bool("ro.config.low_ram", false);
- if (is_low_mem) {
+ if (GetBoolProperty("ro.config.low_ram", false)) {
return true;
}
@@ -755,50 +623,33 @@
CHECK(apk_fds != nullptr);
CHECK_EQ(1u, apk_fds->size());
}
- std::vector<std::string> profile_args(profile_fds.size());
- for (size_t k = 0; k < profile_fds.size(); k++) {
- profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
- }
- std::string reference_profile_arg = "--reference-profile-file-fd="
- + std::to_string(reference_profile_fd.get());
+ std::vector<std::string> args;
+ args.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
- std::vector<std::string> apk_args;
+ for (const unique_fd& fd : profile_fds) {
+ args.push_back("--profile-file-fd=" + std::to_string(fd.get()));
+ }
+
if (apk_fds != nullptr) {
- for (size_t k = 0; k < apk_fds->size(); k++) {
- apk_args.push_back("--apk-fd=" + std::to_string((*apk_fds)[k].get()));
+ for (const unique_fd& fd : *apk_fds) {
+ args.push_back("--apk-fd=" + std::to_string(fd.get()));
}
}
std::vector<std::string> dex_location_args;
if (dex_locations != nullptr) {
- for (size_t k = 0; k < dex_locations->size(); k++) {
- dex_location_args.push_back("--dex-location=" + (*dex_locations)[k]);
+ for (const std::string& dex_location : *dex_locations) {
+ args.push_back("--dex-location=" + dex_location);
}
}
- // program name, reference profile fd, the final NULL and the profile fds
- const char* argv[3 + profile_args.size() + apk_args.size()
- + dex_location_args.size() + (copy_and_update ? 1 : 0)];
- int i = 0;
- argv[i++] = profman_bin;
- argv[i++] = reference_profile_arg.c_str();
- for (size_t k = 0; k < profile_args.size(); k++) {
- argv[i++] = profile_args[k].c_str();
- }
- for (size_t k = 0; k < apk_args.size(); k++) {
- argv[i++] = apk_args[k].c_str();
- }
- for (size_t k = 0; k < dex_location_args.size(); k++) {
- argv[i++] = dex_location_args[k].c_str();
- }
if (copy_and_update) {
- argv[i++] = "--copy-and-update-profile-key";
+ args.push_back("--copy-and-update-profile-key");
}
// Do not add after dex2oat_flags, they should override others for debugging.
- argv[i] = nullptr;
- execv(profman_bin, (char * const *)argv);
+ ExecVWithArgs(profman_bin, args);
PLOG(ERROR) << "execv(" << profman_bin << ") failed";
exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */
}
@@ -931,7 +782,6 @@
const unique_fd& output_fd) {
std::vector<std::string> profman_args;
static const char* PROFMAN_BIN = "/system/bin/profman";
- profman_args.push_back(PROFMAN_BIN);
profman_args.push_back("--dump-only");
profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
if (reference_profile_fd != -1) {
@@ -947,14 +797,8 @@
for (size_t i = 0; i < apk_fds.size(); i++) {
profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
}
- const char **argv = new const char*[profman_args.size() + 1];
- size_t i = 0;
- for (const std::string& profman_arg : profman_args) {
- argv[i++] = profman_arg.c_str();
- }
- argv[i] = nullptr;
- execv(PROFMAN_BIN, (char * const *)argv);
+ ExecVWithArgs(PROFMAN_BIN, profman_args);
PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */
}
@@ -1310,10 +1154,8 @@
if (!generate_app_image) {
return Dex2oatFileWrapper();
}
- char app_image_format[kPropertyValueMax];
- bool have_app_image_format =
- get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
- if (!have_app_image_format) {
+ std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
+ if (app_image_format.empty()) {
return Dex2oatFileWrapper();
}
// Recreate is true since we do not want to modify a mapped image. If the app is
@@ -1583,13 +1425,6 @@
is_debug_runtime()
? "/system/bin/dexoptanalyzerd"
: "/system/bin/dexoptanalyzer";
- static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
-
- if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
- LOG(ERROR) << "Instruction set " << instruction_set
- << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
- return;
- }
std::string dex_file_arg = "--dex-file=" + dex_file;
std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
@@ -1604,38 +1439,30 @@
class_loader_context_arg += class_loader_context;
}
- // program name, dex file, isa, filter, the final NULL
- const int argc = 6 +
- (profile_was_updated ? 1 : 0) +
- (vdex_fd >= 0 ? 1 : 0) +
- (oat_fd >= 0 ? 1 : 0) +
- (downgrade ? 1 : 0) +
- (class_loader_context != nullptr ? 1 : 0);
- const char* argv[argc];
- int i = 0;
- argv[i++] = dexoptanalyzer_bin;
- argv[i++] = dex_file_arg.c_str();
- argv[i++] = isa_arg.c_str();
- argv[i++] = compiler_filter_arg.c_str();
+ // program name, dex file, isa, filter
+ std::vector<std::string> args = {
+ dex_file_arg,
+ isa_arg,
+ compiler_filter_arg,
+ };
if (oat_fd >= 0) {
- argv[i++] = oat_fd_arg.c_str();
+ args.push_back(oat_fd_arg);
}
if (vdex_fd >= 0) {
- argv[i++] = vdex_fd_arg.c_str();
+ args.push_back(vdex_fd_arg);
}
- argv[i++] = zip_fd_arg.c_str();
+ args.push_back(zip_fd_arg.c_str());
if (profile_was_updated) {
- argv[i++] = assume_profile_changed;
+ args.push_back(assume_profile_changed);
}
if (downgrade) {
- argv[i++] = downgrade_flag;
+ args.push_back(downgrade_flag);
}
if (class_loader_context != nullptr) {
- argv[i++] = class_loader_context_arg.c_str();
+ args.push_back(class_loader_context_arg.c_str());
}
- argv[i] = nullptr;
- execv(dexoptanalyzer_bin, (char * const *)argv);
+ ExecVWithArgs(dexoptanalyzer_bin, args);
ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
}
@@ -2425,18 +2252,14 @@
bool move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
// Get the current slot suffix. No suffix, no A/B.
- std::string slot_suffix;
- {
- char buf[kPropertyValueMax];
- if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) {
- return false;
- }
- slot_suffix = buf;
+ const std::string slot_suffix = GetProperty("ro.boot.slot_suffix", "");
+ if (slot_suffix.empty()) {
+ return false;
+ }
- if (!ValidateTargetSlotSuffix(slot_suffix)) {
- LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
- return false;
- }
+ if (!ValidateTargetSlotSuffix(slot_suffix)) {
+ LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
+ return false;
}
// Validate other inputs.
@@ -2693,6 +2516,13 @@
return false;
}
+ // Return false for empty class path since it may otherwise return true below if profiles is
+ // empty.
+ if (classpath.empty()) {
+ PLOG(ERROR) << "Class path is empty";
+ return false;
+ }
+
// Open and create the snapshot profile.
unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index f216c53..79e6859 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -143,6 +143,20 @@
"AAAACADojmFLPcugSwoBAAAUAgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAA/Ns"
"+ll1eAsAAQQj5QIABIgTAABQSwUGAAAAAAEAAQBRAAAATwEAAAAA";
+class DexoptTestEnvTest : public testing::Test {
+};
+
+TEST_F(DexoptTestEnvTest, CheckSelinux) {
+ ASSERT_EQ(1, is_selinux_enabled());
+
+ // Crude cutout for virtual devices.
+#if !defined(__i386__) && !defined(__x86_64__)
+ constexpr bool kIsX86 = false;
+#else
+ constexpr bool kIsX86 = true;
+#endif
+ ASSERT_TRUE(1 == security_getenforce() || kIsX86 || true /* b/119032200 */);
+}
class DexoptTest : public testing::Test {
protected:
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 6b9cf0d..74ad184 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -43,6 +43,7 @@
#define DEBUG_XATTRS 0
using android::base::EndsWith;
+using android::base::Fdopendir;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -1036,7 +1037,7 @@
continue;
}
- DIR* subdir = fdopendir(subdir_fd);
+ DIR* subdir = Fdopendir(std::move(subdir_fd));
if (subdir == nullptr) {
PLOG(WARNING) << "Could not open dir path " << local_path;
result = false;
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index 79f666b..c541511 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -150,19 +150,81 @@
* Move to the next system font.
*
* \param iterator an iterator for the system fonts. Passing NULL is not allowed.
- * \return true if more system fonts are available, otherwise false.
+ * \return a font. If no more font is available, returns nullptr. You need to release the returned
+ * font by ASystemFont_close when it is no longer needed.
*/
ASystemFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
/**
* Close an ASystemFont returned by ASystemFontIterator_next.
*
- * \param font a font returned by ASystemFontIterator_next. Do nothing if NULL is passed.
+ * \param font a font returned by ASystemFontIterator_next or ASystemFont_matchFamilyStyleCharacter.
+ * Do nothing if NULL is passed.
*/
void ASystemFont_close(ASystemFont* _Nullable font) __INTRODUCED_IN(29);
/**
+ * Select the best font from given parameters.
+ *
+ * Only generic font families are supported.
+ * For more information about generic font families, read [W3C spec](https://www.w3.org/TR/css-fonts-4/#generic-font-families)
+ *
+ * Even if no font can render the given text, this function will return a non-null result for
+ * drawing Tofu character.
+ *
+ * Examples:
+ * <code>
+ * // Simple font query for the ASCII character.
+ * std::vector<uint16_t> text = { 'A' };
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ * // runLength will be 1 and the font will points a valid font file.
+ *
+ * // Querying font for CJK characters
+ * std::vector<uint16_t> text = { 0x9AA8 };
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "zh-CN,ja-JP", text.data(), text.length(), &runLength);
+ * // runLength will be 1 and the font will points a Simplified Chinese font.
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "ja-JP,zh-CN", text.data(), text.length(), &runLength);
+ * // runLength will be 1 and the font will points a Japanese font.
+ *
+ * // Querying font for text/color emoji
+ * std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 };
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ * // runLength will be 8 and the font will points a color emoji font.
+ *
+ * // Mixture of multiple script of characters.
+ * // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character.
+ * std::vector<uint16_t> text = { 0x05D0, 0x0E01 };
+ * ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ * "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ * // runLength will be 1 and the font will points a Hebrew font.
+ * </code>
+ *
+ * \param familyName a null character terminated font family name
+ * \param weight a font weight value. Only from 0 to 1000 value is valid
+ * \param italic true if italic, otherwise false.
+ * \param languageTags a null character terminated comma separated IETF BCP47 compliant language
+ * tags.
+ * \param text a UTF-16 encoded text buffer to be rendered.
+ * \param textLength a length of the given text buffer.
+ * \param runLengthOut if not null, the font run length will be filled.
+ * \return a font to be used for given text and params. You need to release the returned font by
+ * ASystemFont_close when it is no longer needed.
+ */
+ASystemFont* _Nonnull ASystemFont_matchFamilyStyleCharacter(
+ const char* _Nonnull familyName,
+ uint16_t weight,
+ bool italic,
+ const char* _Nonnull languageTags,
+ const uint16_t* _Nonnull text,
+ uint32_t textLength,
+ uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29);
+
+/**
* Return an absolute path to the current font file.
*
* Here is a list of font formats returned by this method:
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 1bd7c4f..f6cc3af 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -115,6 +115,7 @@
return sEmptyDescriptor;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -137,6 +138,7 @@
return err;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::linkToDeath(
const sp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
uint32_t /*flags*/)
@@ -144,6 +146,7 @@
return INVALID_OPERATION;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::unlinkToDeath(
const wp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
uint32_t /*flags*/, wp<DeathRecipient>* /*outRecipient*/)
@@ -208,6 +211,7 @@
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 7342126..ec170f7 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -206,6 +206,7 @@
return err;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -220,6 +221,7 @@
return DEAD_OBJECT;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
@@ -254,6 +256,7 @@
return DEAD_OBJECT;
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::unlinkToDeath(
const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
wp<DeathRecipient>* outRecipient)
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index f9ec593..2f4dbee 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -49,6 +49,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnAppOpsCallback::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 068664b..fb0d521 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -129,6 +129,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnAppOpsService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index ad1e69f..b307e3e 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -136,6 +136,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnBatteryStats::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 0b89879..caf2318 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -129,6 +129,7 @@
public:
explicit BpMemory(const sp<IBinder>& impl);
virtual ~BpMemory();
+ // NOLINTNEXTLINE(google-default-arguments)
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const;
private:
@@ -180,6 +181,7 @@
{
}
+// NOLINTNEXTLINE(google-default-arguments)
sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
{
if (mHeap == nullptr) {
@@ -227,6 +229,7 @@
BnMemory::~BnMemory() {
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnMemory::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -391,6 +394,7 @@
BnMemoryHeap::~BnMemoryHeap() {
}
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnMemoryHeap::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 89ebc6c..6b99150 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -109,6 +109,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnPermissionController::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index 14b5259..159763d 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -48,6 +48,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnResultReceiver::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index dd4a65e..6c697de 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -58,6 +58,7 @@
// ----------------------------------------------------------------------
+// NOLINTNEXTLINE(google-default-arguments)
status_t BnShellCallback::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 0b60b4e..c251468 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -34,15 +34,18 @@
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0,
@@ -60,6 +63,7 @@
protected:
virtual ~BBinder();
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index c4c8ba3..1d4f881 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -41,14 +41,18 @@
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0);
+
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0,
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
index e5b12a9..b500219 100644
--- a/libs/binder/include/binder/IAppOpsCallback.h
+++ b/libs/binder/include/binder/IAppOpsCallback.h
@@ -43,6 +43,7 @@
class BnAppOpsCallback : public BnInterface<IAppOpsCallback>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index f0c5e17..7807851 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -67,6 +67,7 @@
class BnAppOpsService : public BnInterface<IAppOpsService>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
index 59e806c..48da865 100644
--- a/libs/binder/include/binder/IBatteryStats.h
+++ b/libs/binder/include/binder/IBatteryStats.h
@@ -68,6 +68,7 @@
class BnBatteryStats : public BnInterface<IBatteryStats>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 3f0dad0..14edcbe 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -86,6 +86,7 @@
Vector<String16>& args, const sp<IShellCallback>& callback,
const sp<IResultReceiver>& resultReceiver);
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
@@ -131,6 +132,7 @@
* (Nor should you need to, as there is nothing useful you can
* directly do with it now that it has passed on.)
*/
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0) = 0;
@@ -142,6 +144,7 @@
* supply a NULL @a recipient, and the recipient previously
* added with that cookie will be unlinked.
*/
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0,
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
index 11f7efa..071946f 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -54,7 +54,8 @@
class BnMemoryHeap : public BnInterface<IMemoryHeap>
{
public:
- virtual status_t onTransact(
+ // NOLINTNEXTLINE(google-default-arguments)
+ virtual status_t onTransact(
uint32_t code,
const Parcel& data,
Parcel* reply,
@@ -72,6 +73,7 @@
public:
DECLARE_META_INTERFACE(Memory)
+ // NOLINTNEXTLINE(google-default-arguments)
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0;
// helpers
@@ -84,6 +86,7 @@
class BnMemory : public BnInterface<IMemory>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 3ec459f..26a1b23 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -56,6 +56,7 @@
class BnPermissionController : public BnInterface<IPermissionController>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h
index e494fba..00b3d89 100644
--- a/libs/binder/include/binder/IResultReceiver.h
+++ b/libs/binder/include/binder/IResultReceiver.h
@@ -41,6 +41,7 @@
class BnResultReceiver : public BnInterface<IResultReceiver>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 1d39aa3..aeea1a2 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -61,6 +61,7 @@
/**
* Register a service.
*/
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated = false,
int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
@@ -68,6 +69,7 @@
/**
* Return list of all existing services.
*/
+ // NOLINTNEXTLINE(google-default-arguments)
virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
enum {
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index b47e995..6715678 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -42,6 +42,7 @@
class BnShellCallback : public BnInterface<IShellCallback>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
index d81789e..9937ad6 100644
--- a/libs/binder/include/binder/IUidObserver.h
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -47,6 +47,7 @@
class BnUidObserver : public BnInterface<IUidObserver>
{
public:
+ // NOLINTNEXTLINE(google-default-arguments)
virtual status_t onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 5461b4f..d16502f 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -38,6 +38,8 @@
"libbinder",
"libutils",
],
+
+ version_script: "libbinder_ndk.map.txt",
}
ndk_headers {
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index cc0a29d..e52a1d6 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -31,6 +31,7 @@
#include <android/binder_status.h>
#include <assert.h>
+#include <unistd.h>
#ifdef __cplusplus
@@ -113,23 +114,23 @@
/**
* This baseclass owns a single object, used to make various classes RAII.
*/
-template <typename T, void (*Destroy)(T*)>
+template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
class ScopedAResource {
public:
/**
* Takes ownership of t.
*/
- explicit ScopedAResource(T* t = nullptr) : mT(t) {}
+ explicit ScopedAResource(T t = DEFAULT) : mT(t) {}
/**
* This deletes the underlying object if it exists. See set.
*/
- ~ScopedAResource() { set(nullptr); }
+ ~ScopedAResource() { set(DEFAULT); }
/**
* Takes ownership of t.
*/
- void set(T* t) {
+ void set(T t) {
Destroy(mT);
mT = t;
}
@@ -137,12 +138,12 @@
/**
* This returns the underlying object to be modified but does not affect ownership.
*/
- T* get() { return mT; }
+ T get() { return mT; }
/**
* This returns the const underlying object but does not affect ownership.
*/
- const T* get() const { return mT; }
+ const T get() const { return mT; }
/**
* This allows the value in this class to be set from beneath it. If you call this method and
@@ -156,7 +157,7 @@
* Other usecases are discouraged.
*
*/
- T** getR() { return &mT; }
+ T* getR() { return &mT; }
// copy-constructing, or move/copy assignment is disallowed
ScopedAResource(const ScopedAResource&) = delete;
@@ -167,13 +168,13 @@
ScopedAResource(ScopedAResource&&) = default;
private:
- T* mT;
+ T mT;
};
/**
* Convenience wrapper. See AParcel.
*/
-class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> {
+class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
public:
/**
* Takes ownership of a.
@@ -186,7 +187,7 @@
/**
* Convenience wrapper. See AStatus.
*/
-class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> {
+class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
public:
/**
* Takes ownership of a.
@@ -205,7 +206,8 @@
* Convenience wrapper. See AIBinder_DeathRecipient.
*/
class ScopedAIBinder_DeathRecipient
- : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> {
+ : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+ nullptr> {
public:
/**
* Takes ownership of a.
@@ -219,7 +221,8 @@
/**
* Convenience wrapper. See AIBinder_Weak.
*/
-class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> {
+class ScopedAIBinder_Weak
+ : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
public:
/**
* Takes ownership of a.
@@ -234,6 +237,19 @@
SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
};
+/**
+ * Convenience wrapper for a file descriptor.
+ */
+class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> {
+public:
+ /**
+ * Takes ownership of a.
+ */
+ explicit ScopedFileDescriptor(int a = -1) : ScopedAResource(a) {}
+ ~ScopedFileDescriptor() {}
+ ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
+};
+
} // namespace ndk
#endif // __cplusplus
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index d36b3c0..4e0132b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -50,98 +50,128 @@
*/
void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
-/**
- * This is called to allocate an array with a given length. If allocation fails, null should be
- * returned.
- */
-typedef void* (*AParcel_arrayReallocator)(void* vectorData, size_t length);
-
// @START-PRIMITIVE-VECTOR-GETTERS
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of length length and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readInt32Array
*/
-typedef int32_t* (*AParcel_int32ArrayGetter)(void* arrayData);
+typedef int32_t* (*AParcel_int32Allocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of length length and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readUint32Array
*/
-typedef uint32_t* (*AParcel_uint32ArrayGetter)(void* arrayData);
+typedef uint32_t* (*AParcel_uint32Allocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of length length and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readInt64Array
*/
-typedef int64_t* (*AParcel_int64ArrayGetter)(void* arrayData);
+typedef int64_t* (*AParcel_int64Allocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of length length and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readUint64Array
*/
-typedef uint64_t* (*AParcel_uint64ArrayGetter)(void* arrayData);
+typedef uint64_t* (*AParcel_uint64Allocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of length length and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readFloatArray
*/
-typedef float* (*AParcel_floatArrayGetter)(void* arrayData);
+typedef float* (*AParcel_floatAllocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of length length and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readDoubleArray
*/
-typedef double* (*AParcel_doubleArrayGetter)(void* arrayData);
+typedef double* (*AParcel_doubleAllocator)(void* arrayData, size_t length);
/**
- * This is called to get the underlying data from an arrayData object.
+ * This allocates an array of length length inside of arrayData and returns whether or not there was
+ * a success.
*
- * This will never be called for an empty array.
+ * See also AParcel_readBoolArray
+ */
+typedef bool (*AParcel_boolAllocator)(void* arrayData, size_t length);
+
+/**
+ * This is called to get the underlying data from an arrayData object at index.
+ *
+ * See also AParcel_writeBoolArray
*/
typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index);
/**
* This is called to set an underlying value in an arrayData object at index.
+ *
+ * See also AParcel_readBoolArray
*/
typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of length length and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readCharArray
*/
-typedef char16_t* (*AParcel_charArrayGetter)(void* arrayData);
+typedef char16_t* (*AParcel_charAllocator)(void* arrayData, size_t length);
/**
* This is called to get the underlying data from an arrayData object.
*
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of length length and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readByteArray
*/
-typedef int8_t* (*AParcel_byteArrayGetter)(void* arrayData);
+typedef int8_t* (*AParcel_byteAllocator)(void* arrayData, size_t length);
// @END-PRIMITIVE-VECTOR-GETTERS
/**
- * This is called to allocate a buffer
+ * This is called to allocate a buffer for a C-style string (null-terminated). The buffer should be
+ * of length length which includes space for the null-terminator.
*
- * The length here includes the space required to insert a '\0' for a properly formed c-str. If the
- * buffer returned from this function is retStr, it will be filled by AParcel_readString with the
- * data from the remote process, and it will be filled such that retStr[length] == '\0'.
+ * See also AParcel_readString.
*
* If allocation fails, null should be returned.
*/
-typedef void* (*AParcel_stringReallocator)(void* stringData, size_t length);
-
-/**
- * This is called to get the buffer from a stringData object.
- */
-typedef char* (*AParcel_stringGetter)(void* stringData);
+typedef char* (*AParcel_stringAllocator)(void* stringData, size_t length);
/**
* Writes an AIBinder to the next location in a non-null parcel. Can be null.
@@ -163,6 +193,23 @@
__INTRODUCED_IN(29);
/**
+ * Writes a file descriptor to the next location in a non-null parcel. This does not take ownership
+ * of fd.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ */
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
+
+/**
+ * Reads an int from the next location in a non-null parcel.
+ *
+ * The returned fd must be closed.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ */
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
+
+/**
* Writes an AStatus object to the next location in a non-null parcel.
*
* If the status is considered to be a low-level status and has no additional information other
@@ -190,17 +237,12 @@
/**
* Reads and allocates string value from the next location in a non-null parcel.
*
- * Data is passed to the string allocator once the string size is known. This data should be used to
- * point to some kind of string data. For instance, it could be a char*, and the string allocator
- * could be realloc. Then the getter would simply be a cast to char*. In more complicated cases,
- * stringData could be a structure containing additional string data.
- *
- * If this function returns a success, the buffer returned by allocator when passed stringData will
- * contain a null-terminated c-str read from the binder.
+ * Data is passed to the string allocator once the string size is known. This size includes the
+ * space for the null-terminator of this string. This allocator returns a buffer which is used as
+ * the output buffer from this read.
*/
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator,
- AParcel_stringGetter getter, void** stringData)
- __INTRODUCED_IN(29);
+binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringAllocator allocator,
+ void* stringData) __INTRODUCED_IN(29);
// @START-PRIMITIVE-READ-WRITE
/**
@@ -331,6 +373,9 @@
/**
* Writes an array of bool to the next location in a non-null parcel.
+ *
+ * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying
+ * values to write to the parcel.
*/
binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData,
AParcel_boolArrayGetter getter, size_t length)
@@ -350,66 +395,93 @@
/**
* Reads an array of int32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
*/
-binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_int32ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+ AParcel_int32Allocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of uint32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
*/
-binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_uint32ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+ AParcel_uint32Allocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of int64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
*/
-binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_int64ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+ AParcel_int64Allocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of uint64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
*/
-binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_uint64ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+ AParcel_uint64Allocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of float from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
*/
-binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_floatArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+ AParcel_floatAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of double from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
*/
-binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_doubleArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+ AParcel_doubleAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of bool from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. Then, for every i in [0, length),
+ * setter(arrayData, i, x) will be called where x is the value at the associated index.
*/
-binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+ AParcel_boolAllocator allocator,
AParcel_boolArraySetter setter) __INTRODUCED_IN(29);
/**
* Reads an array of char16_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
*/
-binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_charArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+ AParcel_charAllocator allocator) __INTRODUCED_IN(29);
/**
* Reads an array of int8_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
*/
-binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_byteArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+ AParcel_byteAllocator allocator) __INTRODUCED_IN(29);
// @END-PRIMITIVE-READ-WRITE
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index bf0c956..6e41a7f 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -36,24 +36,26 @@
namespace ndk {
/**
- * This resizes a std::vector of some underlying type to the given length.
+ * This retrieves and allocates a vector to length length and returns the underlying buffer.
*/
template <typename T>
-static inline void* AParcel_stdVectorReallocator(void* vectorData, size_t length) {
+static inline T* AParcel_stdVectorAllocator(void* vectorData, size_t length) {
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
if (length > vec->max_size()) return nullptr;
vec->resize(length);
- return vec;
+ return vec->data();
}
/**
- * This retrieves the underlying contiguous vector from a corresponding vectorData.
+ * This allocates a vector to length length and returns whether the allocation is successful.
*/
-template <typename T>
-static inline T* AParcel_stdVectorGetter(void* vectorData) {
- std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
- return vec->data();
+static inline bool AParcel_stdVectorBoolAllocator(void* vectorData, size_t length) {
+ std::vector<bool>* vec = static_cast<std::vector<bool>*>(vectorData);
+ if (length > vec->max_size()) return false;
+
+ vec->resize(length);
+ return true;
}
/**
@@ -89,8 +91,7 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readInt32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int32_t>,
- AParcel_stdVectorGetter<int32_t>);
+ return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
}
/**
@@ -105,8 +106,7 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readUint32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint32_t>,
- AParcel_stdVectorGetter<uint32_t>);
+ return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>);
}
/**
@@ -121,8 +121,7 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readInt64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int64_t>,
- AParcel_stdVectorGetter<int64_t>);
+ return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
}
/**
@@ -137,8 +136,7 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readUint64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint64_t>,
- AParcel_stdVectorGetter<uint64_t>);
+ return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>);
}
/**
@@ -153,8 +151,7 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readFloatArray(parcel, &vectorData, &AParcel_stdVectorReallocator<float>,
- AParcel_stdVectorGetter<float>);
+ return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>);
}
/**
@@ -169,8 +166,7 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readDoubleArray(parcel, &vectorData, &AParcel_stdVectorReallocator<double>,
- AParcel_stdVectorGetter<double>);
+ return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>);
}
/**
@@ -186,7 +182,7 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readBoolArray(parcel, &vectorData, &AParcel_stdVectorReallocator<bool>,
+ return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorBoolAllocator,
AParcel_stdVectorSetter<bool>);
}
@@ -202,8 +198,7 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readCharArray(parcel, &vectorData, &AParcel_stdVectorReallocator<char16_t>,
- AParcel_stdVectorGetter<char16_t>);
+ return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>);
}
/**
@@ -218,27 +213,18 @@
*/
inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) {
void* vectorData = static_cast<void*>(vec);
- return AParcel_readByteArray(parcel, &vectorData, &AParcel_stdVectorReallocator<int8_t>,
- AParcel_stdVectorGetter<int8_t>);
+ return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
}
// @END
/**
- * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString.
- * See use below in AParcel_readString.
+ * Allocates a std::string to length and returns the underlying buffer. For use with
+ * AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*).
*/
-static inline void* AParcel_stdStringReallocator(void* stringData, size_t length) {
+static inline char* AParcel_stdStringAllocator(void* stringData, size_t length) {
std::string* str = static_cast<std::string*>(stringData);
str->resize(length - 1);
- return stringData;
-}
-
-/**
- * Takes a std::string and returns the inner char*.
- */
-static inline char* AParcel_stdStringGetter(void* stringData) {
- std::string* str = static_cast<std::string*>(stringData);
return &(*str)[0];
}
@@ -254,8 +240,7 @@
*/
static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
void* stringData = static_cast<void*>(str);
- return AParcel_readString(parcel, AParcel_stdStringReallocator, AParcel_stdStringGetter,
- &stringData);
+ return AParcel_readString(parcel, AParcel_stdStringAllocator, stringData);
}
template <typename T>
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f84814f..ec6587a 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -38,6 +38,7 @@
AParcel_readInt64;
AParcel_readInt64Array;
AParcel_readNullableStrongBinder;
+ AParcel_readParcelFileDescriptor;
AParcel_readStatusHeader;
AParcel_readString;
AParcel_readStrongBinder;
@@ -59,6 +60,7 @@
AParcel_writeInt32Array;
AParcel_writeInt64;
AParcel_writeInt64Array;
+ AParcel_writeParcelFileDescriptor;
AParcel_writeStatusHeader;
AParcel_writeString;
AParcel_writeStrongBinder;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 29094db..77c0558 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -23,16 +23,23 @@
#include <limits>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <binder/Parcel.h>
+#include <binder/ParcelFileDescriptor.h>
#include <utils/Unicode.h>
using ::android::IBinder;
using ::android::Parcel;
using ::android::sp;
using ::android::status_t;
+using ::android::base::unique_fd;
+using ::android::os::ParcelFileDescriptor;
template <typename T>
-using ContiguousArrayGetter = T* (*)(void* arrayData);
+using ContiguousArrayAllocator = T* (*)(void* arrayData, size_t length);
+
+template <typename T>
+using ArrayAllocator = bool (*)(void* arrayData, size_t length);
template <typename T>
using ArrayGetter = T (*)(const void* arrayData, size_t index);
template <typename T>
@@ -81,8 +88,8 @@
}
template <typename T>
-binder_status_t ReadArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator, ContiguousArrayGetter<T> getter) {
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData,
+ ContiguousArrayAllocator<T> allocator) {
const Parcel* rawParcel = parcel->get();
int32_t length;
@@ -91,12 +98,8 @@
if (status != STATUS_OK) return PruneStatusT(status);
if (length < 0) return STATUS_UNEXPECTED_NULL;
- *arrayData = reallocator(*arrayData, length);
- if (*arrayData == nullptr) return STATUS_NO_MEMORY;
-
+ T* array = allocator(arrayData, length);
if (length == 0) return STATUS_OK;
-
- T* array = getter(*arrayData);
if (array == nullptr) return STATUS_NO_MEMORY;
int32_t size = 0;
@@ -112,9 +115,8 @@
// Each element in a char16_t array is converted to an int32_t (not packed)
template <>
-binder_status_t ReadArray<char16_t>(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- ContiguousArrayGetter<char16_t> getter) {
+binder_status_t ReadArray<char16_t>(const AParcel* parcel, void* arrayData,
+ ContiguousArrayAllocator<char16_t> allocator) {
const Parcel* rawParcel = parcel->get();
int32_t length;
@@ -123,12 +125,8 @@
if (status != STATUS_OK) return PruneStatusT(status);
if (length < 0) return STATUS_UNEXPECTED_NULL;
- *arrayData = reallocator(*arrayData, length);
- if (*arrayData == nullptr) return STATUS_NO_MEMORY;
-
+ char16_t* array = allocator(arrayData, length);
if (length == 0) return STATUS_OK;
-
- char16_t* array = getter(*arrayData);
if (array == nullptr) return STATUS_NO_MEMORY;
int32_t size = 0;
@@ -163,9 +161,8 @@
}
template <typename T>
-binder_status_t ReadArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator, ArraySetter<T> setter,
- status_t (Parcel::*read)(T*) const) {
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData, ArrayAllocator<T> allocator,
+ ArraySetter<T> setter, status_t (Parcel::*read)(T*) const) {
const Parcel* rawParcel = parcel->get();
int32_t length;
@@ -174,15 +171,14 @@
if (status != STATUS_OK) return PruneStatusT(status);
if (length < 0) return STATUS_UNEXPECTED_NULL;
- *arrayData = reallocator(*arrayData, length);
- if (*arrayData == nullptr) return STATUS_NO_MEMORY;
+ if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
for (size_t i = 0; i < length; i++) {
T readTarget;
status = (rawParcel->*read)(&readTarget);
if (status != STATUS_OK) return PruneStatusT(status);
- setter(*arrayData, i, readTarget);
+ setter(arrayData, i, readTarget);
}
return STATUS_OK;
@@ -218,16 +214,38 @@
*binder = ret.get();
return PruneStatusT(status);
}
+
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) {
+ ParcelFileDescriptor parcelFd((unique_fd(fd)));
+
+ status_t status = parcel->get()->writeParcelable(parcelFd);
+
+ // ownership is retained by caller
+ (void)parcelFd.release().release();
+
+ return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
+ ParcelFileDescriptor parcelFd;
+ // status_t status = parcelFd.readFromParcel(parcel->get());
+ status_t status = parcel->get()->readParcelable(&parcelFd);
+ if (status != STATUS_OK) return PruneStatusT(status);
+
+ *fd = parcelFd.release().release();
+ return STATUS_OK;
+}
+
binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
return PruneStatusT(status->get()->writeToParcel(parcel->get()));
}
binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) {
::android::binder::Status bstatus;
binder_status_t ret = PruneStatusT(bstatus.readFromParcel(*parcel->get()));
- if (ret == EX_NONE) {
+ if (ret == STATUS_OK) {
*status = new AStatus(std::move(bstatus));
}
- return ret;
+ return PruneStatusT(ret);
}
binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) {
@@ -255,8 +273,8 @@
return STATUS_OK;
}
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator,
- AParcel_stringGetter getter, void** stringData) {
+binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringAllocator allocator,
+ void* stringData) {
size_t len16;
const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
@@ -278,16 +296,10 @@
return STATUS_BAD_VALUE;
}
- *stringData = reallocator(*stringData, len8);
-
- if (*stringData == nullptr) {
- return STATUS_NO_MEMORY;
- }
-
- char* str8 = getter(*stringData);
+ char* str8 = allocator(stringData, len8);
if (str8 == nullptr) {
- LOG(WARNING) << __func__ << ": AParcel_stringReallocator failed to allocate.";
+ LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate.";
return STATUS_NO_MEMORY;
}
@@ -426,58 +438,50 @@
return WriteArray<int8_t>(parcel, value, length);
}
-binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_int32ArrayGetter getter) {
- return ReadArray<int32_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+ AParcel_int32Allocator allocator) {
+ return ReadArray<int32_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_uint32ArrayGetter getter) {
- return ReadArray<uint32_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+ AParcel_uint32Allocator allocator) {
+ return ReadArray<uint32_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_int64ArrayGetter getter) {
- return ReadArray<int64_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+ AParcel_int64Allocator allocator) {
+ return ReadArray<int64_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_uint64ArrayGetter getter) {
- return ReadArray<uint64_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+ AParcel_uint64Allocator allocator) {
+ return ReadArray<uint64_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_floatArrayGetter getter) {
- return ReadArray<float>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+ AParcel_floatAllocator allocator) {
+ return ReadArray<float>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_doubleArrayGetter getter) {
- return ReadArray<double>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+ AParcel_doubleAllocator allocator) {
+ return ReadArray<double>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+ AParcel_boolAllocator allocator,
AParcel_boolArraySetter setter) {
- return ReadArray<bool>(parcel, arrayData, reallocator, setter, &Parcel::readBool);
+ return ReadArray<bool>(parcel, arrayData, allocator, setter, &Parcel::readBool);
}
-binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_charArrayGetter getter) {
- return ReadArray<char16_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+ AParcel_charAllocator allocator) {
+ return ReadArray<char16_t>(parcel, arrayData, allocator);
}
-binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData,
- AParcel_arrayReallocator reallocator,
- AParcel_byteArrayGetter getter) {
- return ReadArray<int8_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+ AParcel_byteAllocator allocator) {
+ return ReadArray<int8_t>(parcel, arrayData, allocator);
}
// @END
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 2cf10d3..86cc57e 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -96,6 +96,10 @@
header += "/**\n"
header += " * Writes an array of " + cpp + " to the next location in a non-null parcel.\n"
+ if nca:
+ header += " *\n"
+ header += " * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying values to write "
+ header += "to the parcel.\n"
header += " */\n"
header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) __INTRODUCED_IN(29);\n\n"
source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) {\n"
@@ -105,48 +109,69 @@
for pretty, cpp in data_types:
nca = pretty in non_contiguously_addressable
- extra_getter_args = ""
- if nca: extra_getter_args = ", size_t index"
- getter_return = cpp + "*"
- if nca: getter_return = cpp
- getter_array_data = "void* arrayData"
- if nca: getter_array_data = "const void* arrayData"
-
+ read_func = "AParcel_read" + pretty + "Array"
+ write_func = "AParcel_write" + pretty + "Array"
+ allocator_type = "AParcel_" + pretty.lower() + "Allocator"
getter_type = "AParcel_" + pretty.lower() + "ArrayGetter"
setter_type = "AParcel_" + pretty.lower() + "ArraySetter"
- pre_header += "/**\n"
- pre_header += " * This is called to get the underlying data from an arrayData object.\n"
- pre_header += " *\n"
- pre_header += " * This will never be called for an empty array.\n"
- pre_header += " */\n"
- pre_header += "typedef " + getter_return + " (*" + getter_type + ")(" + getter_array_data + extra_getter_args + ");\n\n"
-
if nca:
pre_header += "/**\n"
+ pre_header += " * This allocates an array of length length inside of arrayData and returns whether or not there was "
+ pre_header += "a success.\n"
+ pre_header += " *\n"
+ pre_header += " * See also " + read_func + "\n"
+ pre_header += " */\n"
+ pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
+
+ pre_header += "/**\n"
+ pre_header += " * This is called to get the underlying data from an arrayData object at index.\n"
+ pre_header += " *\n"
+ pre_header += " * See also " + write_func + "\n"
+ pre_header += " */\n"
+ pre_header += "typedef " + cpp + " (*" + getter_type + ")(const void* arrayData, size_t index);\n\n"
+
+ pre_header += "/**\n"
pre_header += " * This is called to set an underlying value in an arrayData object at index.\n"
+ pre_header += " *\n"
+ pre_header += " * See also " + read_func + "\n"
pre_header += " */\n"
pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n"
+ else:
+ pre_header += "/**\n"
+ pre_header += " * This is called to get the underlying data from an arrayData object.\n"
+ pre_header += " *\n"
+ pre_header += " * The implementation of this function should allocate a contiguous array of length length and "
+ pre_header += "return that underlying buffer to be filled out. If there is an error or length is 0, null may be "
+ pre_header += "returned.\n"
+ pre_header += " *\n"
+ pre_header += " * See also " + read_func + "\n"
+ pre_header += " */\n"
+ pre_header += "typedef " + cpp + "* (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
- read_using = "getter"
- if nca: read_using = "setter"
- read_type = getter_type
- if nca: read_type = setter_type
+ read_array_args = [("const AParcel*", "parcel")]
+ read_array_args += [("void*", "arrayData")]
+ read_array_args += [(allocator_type, "allocator")]
+ if nca: read_array_args += [(setter_type, "setter")]
- arguments = ["const AParcel* parcel"]
- arguments += ["void** arrayData"]
- arguments += ["AParcel_arrayReallocator reallocator"]
- arguments += [read_type + " " + read_using]
- arguments = ", ".join(arguments)
+ read_type_args = ", ".join((varType + " " + name for varType, name in read_array_args))
+ read_call_args = ", ".join((name for varType, name in read_array_args))
header += "/**\n"
header += " * Reads an array of " + cpp + " from the next location in a non-null parcel.\n"
+ header += " *\n"
+ if nca:
+ header += " * First, allocator will be called with the length of the array. Then, for every i in [0, length), "
+ header += "setter(arrayData, i, x) will be called where x is the value at the associated index.\n"
+ else:
+ header += " * First, allocator will be called with the length of the array. If the allocation succeeds and the "
+ header += "length is greater than zero, the buffer returned by the allocator will be filled with the corresponding data\n"
header += " */\n"
- header += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") __INTRODUCED_IN(29);\n\n"
- source += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") {\n"
+ header += "binder_status_t " + read_func + "(" + read_type_args + ") __INTRODUCED_IN(29);\n\n"
+ source += "binder_status_t " + read_func + "(" + read_type_args + ") {\n"
additional_args = ""
if nca: additional_args = ", &Parcel::read" + pretty
- source += " return ReadArray<" + cpp + ">(parcel, arrayData, reallocator, " + read_using + additional_args + ");\n";
+ source += " return ReadArray<" + cpp + ">(" + read_call_args + additional_args + ");\n";
source += "}\n\n"
cpp_helper += "/**\n"
@@ -165,9 +190,12 @@
cpp_helper += " void* vectorData = static_cast<void*>(vec);\n"
read_args = []
read_args += ["parcel"]
- read_args += ["&vectorData"]
- read_args += ["&AParcel_stdVectorReallocator<" + cpp + ">"]
- read_args += ["AParcel_stdVector" + read_using.capitalize() + "<" + cpp + ">"]
+ read_args += ["vectorData"]
+ if nca:
+ read_args += ["AParcel_stdVectorBoolAllocator"]
+ read_args += ["AParcel_stdVectorSetter<" + cpp + ">"]
+ else:
+ read_args += ["AParcel_stdVectorAllocator<" + cpp + ">"]
cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
cpp_helper += "}\n\n"
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 024d72b..97b4828 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -145,18 +145,26 @@
return mAngleRulesLength;
}
-const std::string GraphicsEnv::getLayerPaths(){
+const std::string& GraphicsEnv::getLayerPaths() {
return mLayerPaths;
}
-const std::string GraphicsEnv::getDebugLayers() {
+const std::string& GraphicsEnv::getDebugLayers() {
return mDebugLayers;
}
+const std::string& GraphicsEnv::getDebugLayersGLES() {
+ return mDebugLayersGLES;
+}
+
void GraphicsEnv::setDebugLayers(const std::string layers) {
mDebugLayers = layers;
}
+void GraphicsEnv::setDebugLayersGLES(const std::string layers) {
+ mDebugLayersGLES = layers;
+}
+
android_namespace_t* GraphicsEnv::getDriverNamespace() {
static std::once_flag once;
std::call_once(once, [this]() {
@@ -196,36 +204,3 @@
}
} // namespace android
-
-extern "C" {
-android_namespace_t* android_getDriverNamespace() {
- return android::GraphicsEnv::getInstance().getDriverNamespace();
-}
-android_namespace_t* android_getAngleNamespace() {
- return android::GraphicsEnv::getInstance().getAngleNamespace();
-}
-const char* android_getAngleAppName() {
- return android::GraphicsEnv::getInstance().getAngleAppName();
-}
-bool android_getAngleDeveloperOptIn() {
- return android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
-}
-const char* android_getAngleAppPref() {
- return android::GraphicsEnv::getInstance().getAngleAppPref();
-}
-int android_getAngleRulesFd() {
- return android::GraphicsEnv::getInstance().getAngleRulesFd();
-}
-long android_getAngleRulesOffset() {
- return android::GraphicsEnv::getInstance().getAngleRulesOffset();
-}
-long android_getAngleRulesLength() {
- return android::GraphicsEnv::getInstance().getAngleRulesLength();
-}
-const char* android_getLayerPaths() {
- return android::GraphicsEnv::getInstance().getLayerPaths().c_str();
-}
-const char* android_getDebugLayers() {
- return android::GraphicsEnv::getInstance().getDebugLayers().c_str();
-}
-}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 404823a..528c260 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -58,10 +58,12 @@
void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
NativeLoaderNamespace* getAppNamespace();
- const std::string getLayerPaths();
+ const std::string& getLayerPaths();
void setDebugLayers(const std::string layers);
- const std::string getDebugLayers();
+ void setDebugLayersGLES(const std::string layers);
+ const std::string& getDebugLayers();
+ const std::string& getDebugLayersGLES();
private:
GraphicsEnv() = default;
@@ -74,6 +76,7 @@
long mAngleRulesOffset;
long mAngleRulesLength;
std::string mDebugLayers;
+ std::string mDebugLayersGLES;
std::string mLayerPaths;
android_namespace_t* mDriverNamespace = nullptr;
android_namespace_t* mAngleNamespace = nullptr;
@@ -82,28 +85,4 @@
} // namespace android
-/* FIXME
- * Export an un-mangled function that just does
- * return android::GraphicsEnv::getInstance().getDriverNamespace();
- * This allows libEGL to get the function pointer via dlsym, since it can't
- * directly link against libgui. In a future release, we'll fix this so that
- * libgui does not depend on graphics API libraries, and libEGL can link
- * against it. The current dependencies from libgui -> libEGL are:
- * - the GLConsumer class, which should be moved to its own library
- * - the EGLsyncKHR synchronization in BufferQueue, which is deprecated and
- * will be removed soon.
- */
-extern "C" {
- android_namespace_t* android_getDriverNamespace();
- android_namespace_t* android_getAngleNamespace();
- const char* android_getAngleAppName();
- const char* android_getAngleAppPref();
- bool android_getAngleDeveloperOptIn();
- int android_getAngleRulesFd();
- long android_getAngleRulesOffset();
- long android_getAngleRulesLength();
- const char* android_getLayerPaths();
- const char* android_getDebugLayers();
-}
-
#endif // ANDROID_UI_GRAPHICS_ENV_H
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 1a7c2d3..ed773e0 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -20,7 +20,6 @@
#include <log/log.h>
#include <system/window.h>
#include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
namespace android {
@@ -276,14 +275,10 @@
status_or_handle.error());
return BAD_VALUE;
}
- std::unique_ptr<DetachedBufferHandle> handle =
- DetachedBufferHandle::Create(status_or_handle.take());
- if (!handle->isValid()) {
- ALOGE("detachBuffer: Failed to create a DetachedBufferHandle at slot %zu.", slot);
- return BAD_VALUE;
- }
- return graphic_buffer->setDetachedBufferHandle(std::move(handle));
+ // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+ // be directly backed by BufferHub.
+ return INVALID_OPERATION;
}
status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
@@ -373,7 +368,7 @@
ALOGE("attachBuffer: out_slot cannot be NULL.");
return BAD_VALUE;
}
- if (buffer == nullptr || !buffer->isDetachedBuffer()) {
+ if (buffer == nullptr) {
ALOGE("attachBuffer: invalid GraphicBuffer.");
return BAD_VALUE;
}
@@ -394,45 +389,9 @@
return BAD_VALUE;
}
- // Creates a BufferProducer from the GraphicBuffer.
- std::unique_ptr<DetachedBufferHandle> detached_handle = buffer->takeDetachedBufferHandle();
- if (detached_handle == nullptr) {
- ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
- return BAD_VALUE;
- }
- std::shared_ptr<BufferProducer> buffer_producer =
- BufferProducer::Import(std::move(detached_handle->handle()));
- if (buffer_producer == nullptr) {
- ALOGE("attachBuffer: Failed to import BufferProducer.");
- return BAD_VALUE;
- }
-
- // Adds the BufferProducer into the Queue.
- auto status_or_slot = queue_->InsertBuffer(buffer_producer);
- if (!status_or_slot.ok()) {
- ALOGE("attachBuffer: Failed to insert buffer, error=%d.", status_or_slot.error());
- return BAD_VALUE;
- }
-
- size_t slot = status_or_slot.get();
- ALOGV("attachBuffer: returning slot %zu.", slot);
- if (slot >= static_cast<size_t>(max_buffer_count_)) {
- ALOGE("attachBuffer: Invalid slot: %zu.", slot);
- return BAD_VALUE;
- }
-
- // The just attached buffer should be in dequeued state according to IGraphicBufferProducer
- // interface. In BufferHub's language the buffer should be in Gained state.
- buffers_[slot].mGraphicBuffer = buffer;
- buffers_[slot].mBufferState.attachProducer();
- buffers_[slot].mEglFence = EGL_NO_SYNC_KHR;
- buffers_[slot].mFence = Fence::NO_FENCE;
- buffers_[slot].mRequestBufferCalled = true;
- buffers_[slot].mAcquireCalled = false;
- buffers_[slot].mNeedsReallocation = false;
-
- *out_slot = static_cast<int>(slot);
- return NO_ERROR;
+ // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+ // be directly backed by BufferHub.
+ return INVALID_OPERATION;
}
status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index cf9d4c5..e66c0e5 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -565,8 +565,10 @@
return reply.readParcelableVector(outLayers);
}
- virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat) const {
+ virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+ ui::PixelFormat* defaultPixelFormat,
+ ui::Dataspace* wideColorGamutDataspace,
+ ui::PixelFormat* wideColorGamutPixelFormat) const {
Parcel data, reply;
status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (error != NO_ERROR) {
@@ -578,11 +580,28 @@
}
error = static_cast<status_t>(reply.readInt32());
if (error == NO_ERROR) {
- *dataSpace = static_cast<ui::Dataspace>(reply.readInt32());
- *pixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+ *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+ *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+ *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+ *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
}
return error;
}
+
+ virtual bool isColorManagementUsed() const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::IS_COLOR_MANAGEMET_USED, data, &reply);
+ int32_t result = 0;
+ status_t err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ ALOGE("ISurfaceComposer::isColorManagementUsed: error "
+ "retrieving result: %s (%d)",
+ strerror(-err), -err);
+ return false;
+ }
+ return result != 0;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -910,16 +929,28 @@
}
case GET_COMPOSITION_PREFERENCE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- ui::Dataspace dataSpace;
- ui::PixelFormat pixelFormat;
- status_t error = getCompositionPreference(&dataSpace, &pixelFormat);
+ ui::Dataspace defaultDataspace;
+ ui::PixelFormat defaultPixelFormat;
+ ui::Dataspace wideColorGamutDataspace;
+ ui::PixelFormat wideColorGamutPixelFormat;
+ status_t error =
+ getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
+ &wideColorGamutDataspace, &wideColorGamutPixelFormat);
reply->writeInt32(error);
if (error == NO_ERROR) {
- reply->writeInt32(static_cast<int32_t>(dataSpace));
- reply->writeInt32(static_cast<int32_t>(pixelFormat));
+ reply->writeInt32(static_cast<int32_t>(defaultDataspace));
+ reply->writeInt32(static_cast<int32_t>(defaultPixelFormat));
+ reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
+ reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
}
return NO_ERROR;
}
+ case IS_COLOR_MANAGEMET_USED: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t result = isColorManagementUsed() ? 1 : 0;
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7498f36..e5a2454 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -866,9 +866,12 @@
ComposerService::getComposerService()->setPowerMode(token, mode);
}
-status_t SurfaceComposerClient::getCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat) {
- return ComposerService::getComposerService()->getCompositionPreference(dataSpace, pixelFormat);
+status_t SurfaceComposerClient::getCompositionPreference(
+ ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat,
+ ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) {
+ return ComposerService::getComposerService()
+ ->getCompositionPreference(defaultDataspace, defaultPixelFormat,
+ wideColorGamutDataspace, wideColorGamutPixelFormat);
}
status_t SurfaceComposerClient::clearAnimationFrameStats() {
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 781e062..9316ae6 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -280,8 +280,19 @@
*/
virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
- virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat) const = 0;
+ virtual bool isColorManagementUsed() const = 0;
+
+ /* Gets the composition preference of the default data space and default pixel format,
+ * as well as the wide color gamut data space and wide color gamut pixel format.
+ * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+ * has no wide color gamut support.
+ *
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+ ui::PixelFormat* defaultPixelFormat,
+ ui::Dataspace* wideColorGamutDataspace,
+ ui::PixelFormat* wideColorGamutPixelFormat) const = 0;
};
// ----------------------------------------------------------------------------
@@ -320,6 +331,7 @@
GET_LAYER_DEBUG_INFO,
CREATE_SCOPED_CONNECTION,
GET_COMPOSITION_PREFERENCE,
+ IS_COLOR_MANAGEMET_USED,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 1b4eda7..8ccee05 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -101,9 +101,15 @@
/* Triggers screen on/off or low power mode and waits for it to complete */
static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
- //
- static status_t getCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat);
+ /* Returns the composition preference of the default data space and default pixel format,
+ * as well as the wide color gamut data space and wide color gamut pixel format.
+ * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+ * has no wide color gamut support.
+ */
+ static status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+ ui::PixelFormat* defaultPixelFormat,
+ ui::Dataspace* wideColorGamutDataspace,
+ ui::PixelFormat* wideColorGamutPixelFormat);
// ------------------------------------------------------------------------
// surface creation / destruction
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 6d03374..aef7aed 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -777,14 +777,6 @@
ASSERT_OK(mProducer->detachBuffer(slot));
EXPECT_OK(buffer->initCheck());
- if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
- // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
- // isDetachedBuffer() set. Note that this only applies to BufferHub.
- EXPECT_TRUE(buffer->isDetachedBuffer());
- } else {
- EXPECT_FALSE(buffer->isDetachedBuffer());
- }
-
ASSERT_OK(mProducer->disconnect(TEST_API));
ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
@@ -801,16 +793,7 @@
ASSERT_OK(mProducer->detachBuffer(slot));
EXPECT_OK(buffer->initCheck());
- if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
- // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
- // isDetachedBuffer() set. Note that this only applies to BufferHub.
- EXPECT_TRUE(buffer->isDetachedBuffer());
- } else {
- EXPECT_FALSE(buffer->isDetachedBuffer());
- }
-
EXPECT_OK(mProducer->attachBuffer(&slot, buffer));
- EXPECT_FALSE(buffer->isDetachedBuffer());
EXPECT_OK(buffer->initCheck());
}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 500df05..a3e9249 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -628,11 +628,15 @@
status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
return NO_ERROR;
}
- status_t getCompositionPreference(ui::Dataspace* /*outDataSpace*/,
- ui::PixelFormat* /*outPixelFormat*/) const override {
+ status_t getCompositionPreference(
+ ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/,
+ ui::Dataspace* /*outWideColorGamutDataspace*/,
+ ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override {
return NO_ERROR;
}
+ virtual bool isColorManagementUsed() const { return false; }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 5fbb3b2..647fe86 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -13,13 +13,20 @@
// limitations under the License.
ndk_headers {
- name: "libnativewindow_headers",
+ name: "libnativewindow_ndk_headers",
from: "include/android",
to: "android",
srcs: ["include/android/*.h"],
license: "NOTICE",
}
+// TODO(b/118715870): cleanup header files
+cc_library_headers {
+ name: "libnativewindow_headers",
+ export_include_dirs: ["include"],
+ vendor_available: false,
+}
+
ndk_library {
name: "libnativewindow",
symbol_file: "libnativewindow.map.txt",
@@ -70,6 +77,7 @@
header_libs: [
"libnativebase_headers",
+ "libnativewindow_headers",
],
// headers we include in our public headers
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index a6e6d73..8cc1a4e 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -37,7 +37,6 @@
#pragma clang diagnostic pop
#include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
#include <poll.h>
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c50d1d0..5a1ddee 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -22,7 +22,6 @@
#include <grallocusage/GrallocUsageConversion.h>
-#include <ui/DetachedBufferHandle.h>
#include <ui/Gralloc2.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
@@ -490,24 +489,6 @@
return NO_ERROR;
}
-bool GraphicBuffer::isDetachedBuffer() const {
- return mDetachedBufferHandle && mDetachedBufferHandle->isValid();
-}
-
-status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) {
- if (isDetachedBuffer()) {
- ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this "
- "GraphicBuffer. Replacing the old one.");
- }
-
- mDetachedBufferHandle = std::move(channel);
- return NO_ERROR;
-}
-
-std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() {
- return std::move(mDetachedBufferHandle);
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h
deleted file mode 100644
index f3c328d..0000000
--- a/libs/ui/include/ui/DetachedBufferHandle.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-
-#include <pdx/channel_handle.h>
-
-#include <memory>
-
-namespace android {
-
-// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be
-// created. Current implementation assumes that the underlying transport is using libpdx (thus
-// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder
-// backend if ever needed.
-class DetachedBufferHandle {
-public:
- static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) {
- return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle)));
- }
-
- // Accessors to get or take the internal pdx::LocalChannelHandle.
- pdx::LocalChannelHandle& handle() { return mHandle; }
- const pdx::LocalChannelHandle& handle() const { return mHandle; }
-
- // Returns whether the DetachedBufferHandle holds a BufferHub channel.
- bool isValid() const { return mHandle.valid(); }
-
-private:
- // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle.
- explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {}
-
- pdx::LocalChannelHandle mHandle;
-};
-
-} // namespace android
-
-#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index cc38982..e794462 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -34,7 +34,6 @@
namespace android {
-class DetachedBufferHandle;
class GraphicBufferMapper;
// ===========================================================================
@@ -191,11 +190,6 @@
status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
- // Sets and takes DetachedBuffer. Should only be called from BufferHub.
- bool isDetachedBuffer() const;
- status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer);
- std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle();
-
private:
~GraphicBuffer();
@@ -246,17 +240,6 @@
// match the BufferQueue's internal generation number (set through
// IGBP::setGenerationNumber), attempts to attach the buffer will fail.
uint32_t mGenerationNumber;
-
- // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a
- // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub,
- // there are three different modes:
- // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be
- // invalid.
- // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer
- // set. In this mode, mDetachedBufferHandle must be valid.
- // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer
- // set. In this mode, mDetachedBufferHandle must be invalid.
- std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle;
};
}; // namespace android
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 228d202..1521e1d 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -29,16 +29,19 @@
}
cc_test {
- name: "GraphicBuffer_test",
- shared_libs: ["libpdx_default_transport", "libui", "libutils"],
- srcs: ["GraphicBuffer_test.cpp"],
- cflags: ["-Wall", "-Werror"],
-}
-
-cc_test {
name: "BufferHubBuffer_test",
- header_libs: ["libbufferhub_headers", "libdvr_headers"],
- shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+ header_libs: [
+ "libbufferhub_headers",
+ "libdvr_headers"
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libhidlbase",
+ "libhwbinder",
+ "libpdx_default_transport",
+ "libui",
+ "libutils"
+ ],
srcs: ["BufferHubBuffer_test.cpp"],
cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index f0253b2..a247e60 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,7 +16,10 @@
#define LOG_TAG "BufferHubBufferTest"
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
#include <ui/BufferHubBuffer.h>
namespace android {
@@ -32,13 +35,18 @@
} // namespace
-using BufferHubBufferTest = ::testing::Test;
-
using dvr::BufferHubDefs::IsBufferGained;
+using dvr::BufferHubDefs::kFirstClientBitMask;
using dvr::BufferHubDefs::kMetadataHeaderSize;
-using dvr::BufferHubDefs::kProducerStateBit;
+using frameworks::bufferhub::V1_0::IBufferHub;
+using hardware::hidl_handle;
+using hidl::base::V1_0::IBase;
using pdx::LocalChannelHandle;
+class BufferHubBufferTest : public ::testing::Test {
+ void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
+};
+
TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
// Buffer Creation will fail: BLOB format requires height to be 1.
auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
@@ -75,6 +83,8 @@
auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
kUserMetadataSize);
int id1 = b1->id();
+ uint64_t bufferStateMask1 = b1->client_state_mask();
+ EXPECT_NE(bufferStateMask1, 0ULL);
EXPECT_TRUE(b1->IsValid());
EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
@@ -96,16 +106,14 @@
EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
int id2 = b2->id();
+ uint64_t bufferStateMask2 = b2->client_state_mask();
+ EXPECT_NE(bufferStateMask2, 0ULL);
// These two buffer instances are based on the same physical buffer under the
// hood, so they should share the same id.
EXPECT_EQ(id1, id2);
// We use client_state_mask() to tell those two instances apart.
- EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
- EXPECT_NE(b1->client_state_mask(), 0ULL);
- EXPECT_NE(b2->client_state_mask(), 0ULL);
- EXPECT_NE(b1->client_state_mask(), kProducerStateBit);
- EXPECT_NE(b2->client_state_mask(), kProducerStateBit);
+ EXPECT_NE(bufferStateMask1, bufferStateMask2);
// Both buffer instances should be in gained state.
EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
@@ -115,4 +123,14 @@
return;
}
+TEST_F(BufferHubBufferTest, ConnectHidlServer) {
+ sp<IBufferHub> bufferhub = IBufferHub::getService();
+ ASSERT_NE(nullptr, bufferhub.get());
+
+ // TODO(b/116681016): Fill in real test once the interface gets implemented..
+ hidl_handle handle;
+ sp<IBase> interface = bufferhub->importBuffer(handle);
+ EXPECT_EQ(nullptr, interface.get());
+}
+
} // namespace android
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
deleted file mode 100644
index eb679ac..0000000
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GraphicBufferTest"
-
-#include <ui/DetachedBufferHandle.h>
-#include <ui/GraphicBuffer.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-
-namespace {
-
-constexpr uint32_t kTestWidth = 1024;
-constexpr uint32_t kTestHeight = 1;
-constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
-constexpr uint32_t kTestLayerCount = 1;
-constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
-
-} // namespace
-
-class GraphicBufferTest : public testing::Test {};
-
-TEST_F(GraphicBufferTest, DetachedBuffer) {
- sp<GraphicBuffer> buffer(
- new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage));
-
- // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with
- // BufferHub. But this may change in the future.
- EXPECT_FALSE(buffer->isDetachedBuffer());
-
- pdx::LocalChannelHandle channel{nullptr, 1234};
- EXPECT_TRUE(channel.valid());
-
- std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel));
- EXPECT_FALSE(channel.valid());
- EXPECT_TRUE(handle->isValid());
- EXPECT_TRUE(handle->handle().valid());
-
- buffer->setDetachedBufferHandle(std::move(handle));
- EXPECT_TRUE(handle == nullptr);
- EXPECT_TRUE(buffer->isDetachedBuffer());
-
- handle = buffer->takeDetachedBufferHandle();
- EXPECT_TRUE(handle != nullptr);
- EXPECT_TRUE(handle->isValid());
- EXPECT_FALSE(buffer->isDetachedBuffer());
-}
-
-} // namespace android
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp
index 6bef98a..30cbb9f 100644
--- a/libs/vr/libbufferhub/buffer_client_impl.cpp
+++ b/libs/vr/libbufferhub/buffer_client_impl.cpp
@@ -10,6 +10,8 @@
: BpInterface<IBufferClient>(impl) {}
bool isValid() override;
+
+ status_t duplicate(uint64_t* outToken) override;
};
IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient");
@@ -17,6 +19,7 @@
// Transaction code
enum {
IS_VALID = IBinder::FIRST_CALL_TRANSACTION,
+ DUPLICATE,
};
bool BpBufferClient::isValid() {
@@ -38,13 +41,42 @@
}
}
+status_t BpBufferClient::duplicate(uint64_t* outToken) {
+ Parcel data, reply;
+ status_t ret =
+ data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferClient::duplicate: failed to write into parcel; errno=%d",
+ ret);
+ return ret;
+ }
+
+ ret = remote()->transact(DUPLICATE, data, &reply);
+ if (ret == NO_ERROR) {
+ *outToken = reply.readUint64();
+ return NO_ERROR;
+ } else {
+ ALOGE("BpBufferClient::duplicate: failed to transact; errno=%d", ret);
+ return ret;
+ }
+}
+
status_t BnBufferClient::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
case IS_VALID: {
CHECK_INTERFACE(IBufferClient, data, reply);
return reply->writeBool(isValid());
- } break;
+ }
+ case DUPLICATE: {
+ CHECK_INTERFACE(IBufferClient, data, reply);
+ uint64_t token = 0;
+ status_t ret = duplicate(&token);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ return reply->writeUint64(token);
+ }
default:
// Should not reach except binder defined transactions such as dumpsys
return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 3e26dae..73ca69b 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -5,7 +5,6 @@
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
#include <mutex>
#include <thread>
@@ -29,8 +28,8 @@
using android::dvr::BufferHubDefs::IsBufferPosted;
using android::dvr::BufferHubDefs::IsBufferReleased;
using android::dvr::BufferHubDefs::kConsumerStateMask;
+using android::dvr::BufferHubDefs::kFirstClientBitMask;
using android::dvr::BufferHubDefs::kMetadataHeaderSize;
-using android::dvr::BufferHubDefs::kProducerStateBit;
using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
using android::pdx::Status;
@@ -41,7 +40,10 @@
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
-const size_t kMaxConsumerCount = 63;
+// Maximum number of consumers for the buffer that only has one producer in the
+// test.
+const size_t kMaxConsumerCount =
+ android::dvr::BufferHubDefs::kMaxNumberOfClients - 1;
const int kPollTimeoutMs = 100;
using LibBufferHubTest = ::testing::Test;
@@ -59,14 +61,14 @@
ASSERT_TRUE(c2.get() != nullptr);
// Producer state mask is unique, i.e. 1.
- EXPECT_EQ(p->client_state_mask(), kProducerStateBit);
+ EXPECT_EQ(p->client_state_mask(), kFirstClientBitMask);
// Consumer state mask cannot have producer bit on.
- EXPECT_EQ(c->client_state_mask() & kProducerStateBit, 0U);
+ EXPECT_EQ(c->client_state_mask() & kFirstClientBitMask, 0U);
// Consumer state mask must be a single, i.e. power of 2.
EXPECT_NE(c->client_state_mask(), 0U);
EXPECT_EQ(c->client_state_mask() & (c->client_state_mask() - 1), 0U);
// Consumer state mask cannot have producer bit on.
- EXPECT_EQ(c2->client_state_mask() & kProducerStateBit, 0U);
+ EXPECT_EQ(c2->client_state_mask() & kFirstClientBitMask, 0U);
// Consumer state mask must be a single, i.e. power of 2.
EXPECT_NE(c2->client_state_mask(), 0U);
EXPECT_EQ(c2->client_state_mask() & (c2->client_state_mask() - 1), 0U);
@@ -187,7 +189,7 @@
EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
client_state_masks |= cs[i]->client_state_mask();
}
- EXPECT_EQ(client_state_masks, kProducerStateBit | kConsumerStateMask);
+ EXPECT_EQ(client_state_masks, kFirstClientBitMask | kConsumerStateMask);
// The 64th creation will fail with out-of-memory error.
auto state = p->CreateConsumer();
@@ -202,7 +204,7 @@
// The released state mask will be reused.
EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
client_state_masks |= cs[i]->client_state_mask();
- EXPECT_EQ(client_state_masks, kProducerStateBit | kConsumerStateMask);
+ EXPECT_EQ(client_state_masks, kFirstClientBitMask | kConsumerStateMask);
}
}
@@ -707,7 +709,7 @@
std::unique_ptr<ConsumerBuffer> c1 =
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c1.get() != nullptr);
- const uint64_t consumer_state_bit1 = c1->client_state_mask();
+ const uint64_t client_state_mask1 = c1->client_state_mask();
DvrNativeBufferMetadata meta;
EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
@@ -723,8 +725,8 @@
std::unique_ptr<ConsumerBuffer> c2 =
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
- const uint64_t consumer_state_bit2 = c2->client_state_mask();
- EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
+ const uint64_t client_state_mask2 = c2->client_state_mask();
+ EXPECT_NE(client_state_mask1, client_state_mask2);
// The new consumer is available for acquire.
EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
@@ -739,8 +741,8 @@
std::unique_ptr<ConsumerBuffer> c3 =
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c3.get() != nullptr);
- const uint64_t consumer_state_bit3 = c3->client_state_mask();
- EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
+ const uint64_t client_state_mask3 = c3->client_state_mask();
+ EXPECT_NE(client_state_mask2, client_state_mask3);
// The consumer buffer is not acquirable.
EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
@@ -888,6 +890,7 @@
int b1_id = b1->id();
EXPECT_TRUE(b1->IsValid());
EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
+ EXPECT_NE(b1->client_state_mask(), 0ULL);
auto status_or_handle = b1->Duplicate();
EXPECT_TRUE(status_or_handle);
@@ -905,6 +908,7 @@
ASSERT_TRUE(b2 != nullptr);
EXPECT_TRUE(b2->IsValid());
EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
+ EXPECT_NE(b2->client_state_mask(), 0ULL);
int b2_id = b2->id();
@@ -913,10 +917,6 @@
EXPECT_EQ(b1_id, b2_id);
// We use client_state_mask() to tell those two instances apart.
EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
- EXPECT_NE(b1->client_state_mask(), 0ULL);
- EXPECT_NE(b2->client_state_mask(), 0ULL);
- EXPECT_NE(b1->client_state_mask(), kProducerStateBit);
- EXPECT_NE(b2->client_state_mask(), kProducerStateBit);
// Both buffer instances should be in gained state.
EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index b4c5d42..68cc766 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -123,17 +123,17 @@
buffer_state_ = &metadata_header_->buffer_state;
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
- id(), buffer_state_->load());
+ id(), buffer_state_->load(std::memory_order_acquire));
fence_state_ = &metadata_header_->fence_state;
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
- fence_state_->load());
+ fence_state_->load(std::memory_order_acquire));
active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
ALOGD_IF(
TRACE,
"BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx64
".",
- id(), active_clients_bit_mask_->load());
+ id(), active_clients_bit_mask_->load(std::memory_order_acquire));
return 0;
}
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index a91e842..8e630ec 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -38,7 +38,7 @@
// Only check producer bit and this consumer buffer's particular consumer bit.
// The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
// is not set.
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferPosted(buffer_state, client_state_mask())) {
ALOGE("ConsumerBuffer::LocalAcquire: not posted, id=%d state=%" PRIx64
" client_state_mask=%" PRIx64 ".",
@@ -57,9 +57,10 @@
out_meta->user_metadata_ptr = 0;
}
- uint64_t fence_state = fence_state_->load();
+ uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
// If there is an acquire fence from producer, we need to return it.
- if (fence_state & BufferHubDefs::kProducerStateBit) {
+ // The producer state bit mask is kFirstClientBitMask for now.
+ if (fence_state & BufferHubDefs::kFirstClientBitMask) {
*out_fence = shared_acquire_fence_.Duplicate();
}
@@ -118,7 +119,7 @@
return error;
// Check invalid state transition.
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
ALOGE("ConsumerBuffer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
id(), buffer_state);
diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
index 03f2d95..31bf79d 100644
--- a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
+++ b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
@@ -14,6 +14,10 @@
// Checks if the buffer node is valid.
virtual bool isValid() = 0;
+
+ // Duplicates the client. Token_out will be set to a new token when succeed,
+ // and not changed when failed.
+ virtual status_t duplicate(uint64_t* outToken) = 0;
};
// BnInterface for IBufferClient. Should only be created in bufferhub service.
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 1ea8302..09feb73 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -90,7 +90,9 @@
int cid() const { return cid_; }
// Returns the buffer buffer state.
- uint64_t buffer_state() { return buffer_state_->load(); };
+ uint64_t buffer_state() {
+ return buffer_state_->load(std::memory_order_acquire);
+ };
// A state mask which is unique to a buffer hub client among all its siblings
// sharing the same concrete graphic buffer.
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 4953f9b..650da97 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -26,20 +26,21 @@
// MSB LSB
// | |
// v v
-// [P|C62|...|C1|C0]
-// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
-// Post'ed state: [1|..|0|0]
-// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
-// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
-static constexpr uint64_t kProducerStateBit = 1ULL << 63;
-static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+// [C62|...|C1|C0|P]
+// Gain'ed state: [..|0|0|0] -> Exclusively Writable.
+// Post'ed state: [..|0|0|1]
+// Acquired'ed state: [..|X|X|1] -> At least one bit is set in higher 63 bits
+// Released'ed state: [..|X|X|0] -> At least one bit is set in higher 63 bits
+static constexpr int kMaxNumberOfClients = 64;
+static constexpr uint64_t kFirstClientBitMask = 1ULL;
+static constexpr uint64_t kConsumerStateMask = ~kFirstClientBitMask;
static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
uint64_t clear_mask, uint64_t set_mask) {
uint64_t old_state;
uint64_t new_state;
do {
- old_state = buffer_state->load();
+ old_state = buffer_state->load(std::memory_order_acquire);
new_state = (old_state & ~clear_mask) | set_mask;
} while (!buffer_state->compare_exchange_weak(old_state, new_state));
}
@@ -48,23 +49,23 @@
static inline bool IsBufferPosted(uint64_t state,
uint64_t consumer_bit = kConsumerStateMask) {
- return (state & kProducerStateBit) && !(state & consumer_bit);
+ return (state & kFirstClientBitMask) && !(state & consumer_bit);
}
static inline bool IsBufferAcquired(uint64_t state) {
- return (state & kProducerStateBit) && (state & kConsumerStateMask);
+ return (state & kFirstClientBitMask) && (state & kConsumerStateMask);
}
static inline bool IsBufferReleased(uint64_t state) {
- return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+ return !(state & kFirstClientBitMask) && (state & kConsumerStateMask);
}
-static inline uint64_t FindNextClearedBit(uint64_t bits) {
+static inline uint64_t FindNextAvailableClientStateMask(uint64_t bits) {
return ~bits - (~bits & (~bits - 1));
}
static inline uint64_t FindFirstClearedBit() {
- return FindNextClearedBit(kProducerStateBit);
+ return FindNextAvailableClientStateMask(kFirstClientBitMask);
}
struct __attribute__((packed, aligned(8))) MetadataHeader {
@@ -122,7 +123,7 @@
// State mask of the buffer client. Each BufferHubBuffer client backed by the
// same buffer channel has uniqued state bit among its siblings. For a
- // producer buffer the bit must be kProducerStateBit; for a consumer the bit
+ // producer buffer the bit must be kFirstClientBitMask; for a consumer the bit
// must be one of the kConsumerStateMask.
uint64_t client_state_mask() const { return client_state_mask_; }
uint64_t metadata_size() const { return metadata_size_; }
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index de51f25..5ff4e00 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -122,9 +122,7 @@
int buffer_cid() const { return buffer_cid_; }
// State mask of the buffer client. Each BufferHub client backed by the
- // same buffer channel has uniqued state bit among its siblings. For a
- // producer buffer the bit must be kProducerStateBit; for a consumer the bit
- // must be one of the kConsumerStateMask.
+ // same buffer channel has uniqued state bit among its siblings.
uint64_t client_state_mask() const { return client_state_mask_; }
FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
FileHandleType take_release_fence() { return std::move(release_fence_fd_); }
@@ -314,7 +312,6 @@
kOpProducerGain,
kOpConsumerAcquire,
kOpConsumerRelease,
- kOpProducerBufferDetach,
kOpConsumerBufferDetach,
kOpCreateProducerQueue,
kOpCreateConsumerQueue,
@@ -344,8 +341,6 @@
PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, LocalFence(Void));
PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
void(LocalFence release_fence));
- PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
- LocalChannelHandle(Void));
// Detaches a ConsumerBuffer from an existing producer/consumer set. Can only
// be called when the consumer is the only consumer and it has exclusive
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 8f0e3e3..f36e169 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -80,7 +80,7 @@
return error;
// Check invalid state transition.
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
ALOGE("ProducerBuffer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
id(), buffer_state);
@@ -102,8 +102,9 @@
return error;
// Set the producer bit atomically to transit into posted state.
+ // The producer state bit mask is kFirstClientBitMask for now.
BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
- BufferHubDefs::kProducerStateBit);
+ BufferHubDefs::kFirstClientBitMask);
return 0;
}
@@ -135,7 +136,7 @@
int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
LocalHandle* out_fence, bool gain_posted_buffer) {
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
id(), buffer_state);
@@ -168,7 +169,7 @@
out_meta->user_metadata_ptr = 0;
}
- uint64_t fence_state = fence_state_->load();
+ uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
// If there is an release fence from consumer, we need to return it.
if (fence_state & BufferHubDefs::kConsumerStateMask) {
*out_fence = shared_release_fence_.Duplicate();
@@ -228,7 +229,9 @@
ALOGW("ProducerBuffer::Detach: not supported operation during migration");
return {};
- uint64_t buffer_state = buffer_state_->load();
+ // TODO(b/112338294) Keep here for reference. Remove it after new logic is
+ // written.
+ /* uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
// Can only detach a ProducerBuffer when it's in gained state.
ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx64
@@ -242,7 +245,7 @@
ALOGE_IF(!status,
"ProducerBuffer::Detach: Failed to detach buffer (id=%d): %s.", id(),
status.GetErrorMessage().c_str());
- return status;
+ return status; */
}
} // namespace dvr
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index d500278..9a1d2e5 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -34,4 +34,7 @@
],
cppflags: ["-std=c++1z"],
name: "vrflinger_test",
+
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index a7fea33..a150db1 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -36,6 +36,7 @@
#include "egl_platform_entries.h"
#include "egl_trace.h"
#include "egldefs.h"
+#include <EGL/eglext_angle.h>
extern "C" {
android_namespace_t* android_get_exported_namespace(const char*);
@@ -274,10 +275,24 @@
return (void*)hnd;
}
-void Loader::close(void* driver)
+void Loader::close(egl_connection_t* cnx)
{
- driver_t* hnd = (driver_t*)driver;
+ driver_t* hnd = (driver_t*) cnx->dso;
delete hnd;
+ cnx->dso = nullptr;
+
+ if (cnx->featureSo) {
+ dlclose(cnx->featureSo);
+ cnx->featureSo = nullptr;
+ }
+
+ cnx->angleDecided = false;
+ cnx->useAngle = false;
+
+ if (cnx->vendorEGL) {
+ dlclose(cnx->vendorEGL);
+ cnx->vendorEGL = nullptr;
+ }
}
void Loader::init_api(void* dso,
@@ -524,16 +539,15 @@
if (strcmp(kind, "EGL") != 0 && strcmp(kind, "GLESv2") != 0 && strcmp(kind, "GLESv1_CM") != 0)
return nullptr;
- void* so = nullptr;
std::string name;
char prop[PROPERTY_VALUE_MAX];
- const char* app_name = android_getAngleAppName();
- const char* app_pref = android_getAngleAppPref();
- bool developer_opt_in = android_getAngleDeveloperOptIn();
- const int rules_fd = android_getAngleRulesFd();
- const long rules_offset = android_getAngleRulesOffset();
- const long rules_length = android_getAngleRulesLength();
+ const char* app_name = android::GraphicsEnv::getInstance().getAngleAppName();
+ const char* app_pref = android::GraphicsEnv::getInstance().getAngleAppPref();
+ bool developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
+ const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
+ const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
+ const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
// Determine whether or not to use ANGLE:
ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
@@ -541,6 +555,8 @@
if (use_angle) {
ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+ } else if (cnx->angleDecided) {
+ use_angle = cnx->useAngle;
} else {
// The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily
// load ANGLE and call the updatable opt-in/out logic:
@@ -550,19 +566,13 @@
property_get("ro.product.manufacturer", manufacturer, "UNSET");
property_get("ro.product.model", model, "UNSET");
- // Check if ANGLE is enabled. Workaround for b/118375731
- // We suspect that loading & unloading a library somehow corrupts
- // the process.
- property_get("debug.angle.enable", prop, "0");
- if (atoi(prop)) {
- so = load_angle_from_namespace("feature_support", ns);
- }
- if (so) {
- ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
+ cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+ if (cnx->featureSo) {
+ ALOGV("loaded ANGLE's opt-in/out logic from namespace");
bool use_version0_API = false;
bool use_version1_API = false;
fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
- (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
+ (fpANGLEGetUtilityAPI)dlsym(cnx->featureSo, "ANGLEGetUtilityAPI");
if (ANGLEGetUtilityAPI) {
unsigned int versionToUse = 1;
if ((ANGLEGetUtilityAPI)(&versionToUse)) {
@@ -574,12 +584,13 @@
}
} else {
use_version0_API = true;
+ ALOGV("Cannot find ANGLEGetUtilityAPI in library");
}
if (use_version1_API) {
// Use the new version 1 API to determine if the
// application should use the ANGLE or the native driver.
fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
- (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
+ (fpAndroidUseANGLEForApplication)dlsym(cnx->featureSo, "AndroidUseANGLEForApplication");
if (AndroidUseANGLEForApplication) {
use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
rules_length, app_name_str.c_str(),
@@ -591,9 +602,10 @@
// Use the old version 0 API to determine if the
// application should use the ANGLE or the native driver.
fpANGLEUseForApplication ANGLEUseForApplication =
- (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
+ (fpANGLEUseForApplication)dlsym(cnx->featureSo, "ANGLEUseForApplication");
if (ANGLEUseForApplication) {
- ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
+ ANGLEPreference app_preference =
+ getAnglePref(android::GraphicsEnv::getInstance().getAngleAppPref());
use_angle = (ANGLEUseForApplication)(app_name_str.c_str(), manufacturer, model,
developer_option, app_preference);
ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
@@ -601,16 +613,15 @@
ALOGW("Cannot find ANGLEUseForApplication in library");
}
}
- ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
- dlclose(so);
- so = nullptr;
} else {
// We weren't able to load and call the updateable opt-in/out logic.
// If we can't load the library, there is no ANGLE available.
use_angle = false;
- ALOGV("Could not temporarily-load the ANGLE opt-in/out logic, cannot use ANGLE.");
+ ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE.");
}
+ cnx->angleDecided = true;
}
+ void* so = nullptr;
if (use_angle) {
so = load_angle_from_namespace(kind, ns);
}
@@ -618,13 +629,30 @@
if (so) {
ALOGV("Loaded ANGLE %s library for %s (instead of native)",
kind, app_name ? app_name : "nullptr");
- property_get("debug.angle.backend", prop, "UNSET");
- ALOGV("ANGLE's backend set to %s", prop);
property_get("debug.hwui.renderer", prop, "UNSET");
ALOGV("Skia's renderer set to %s", prop);
cnx->useAngle = true;
- // Find and load vendor libEGL for ANGLE
- if (!cnx->vendorEGL) {
+
+ EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+
+ char prop[PROPERTY_VALUE_MAX];
+ property_get("debug.angle.backend", prop, "0");
+ switch (atoi(prop)) {
+ case 1:
+ ALOGV("%s: Requesting OpenGLES back-end", __FUNCTION__);
+ angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
+ break;
+ case 2:
+ ALOGV("%s: Requesting Vulkan back-end", __FUNCTION__);
+ angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+ break;
+ default:
+ break;
+ }
+
+ cnx->angleBackend = angleBackendDefault;
+ if (!cnx->vendorEGL && (cnx->angleBackend == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) {
+ // Find and load vendor libEGL for ANGLE's GL back-end to use.
cnx->vendorEGL = load_system_driver("EGL");
}
return so;
@@ -667,13 +695,13 @@
ATRACE_CALL();
void* dso = nullptr;
- android_namespace_t* ns = android_getAngleNamespace();
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
if (ns) {
dso = load_angle(kind, ns, cnx);
}
#ifndef __ANDROID_VNDK__
if (!dso) {
- android_namespace_t* ns = android_getDriverNamespace();
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (ns) {
dso = load_updated_driver(kind, ns);
}
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 9cc73f3..392887d 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -51,7 +51,7 @@
~Loader();
void* open(egl_connection_t* cnx);
- void close(void* driver);
+ void close(egl_connection_t* cnx);
private:
Loader();
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 476b304..7cf58b4 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -128,56 +128,10 @@
return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
}
-static bool addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
+static bool addAnglePlatformAttributes(egl_connection_t* const cnx,
std::vector<EGLAttrib>& attrs) {
intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
- EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
- if (attrib_list) {
- while (*attrib_list != EGL_NONE) {
- EGLAttrib attr = *attrib_list++;
- EGLAttrib value = *attrib_list++;
- if (attr == EGL_PLATFORM_ANGLE_TYPE_ANGLE) {
- switch (value) {
- case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
- angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
- break;
- case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
- case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
- angleBackendDefault = value;
- break;
- default:
- ALOGW("Invalid EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute: 0x%" PRIxPTR,
- value);
- break;
- }
- }
- }
- }
-
- // Allow debug property to override application's
- char prop[PROPERTY_VALUE_MAX];
- property_get("debug.angle.backend", prop, "0");
- switch (atoi(prop)) {
- case 1:
- ALOGV("addAnglePlatformAttributes: Requesting OpenGLES back-end");
- angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
- break;
- case 2:
- ALOGV("addAnglePlatformAttributes: Requesting Vulkan back-end");
- angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
- break;
- default:
- break;
- }
-
- if (cnx->angleBackend == 0) {
- // Haven't been initialized yet, so set it.
- cnx->angleBackend = angleBackendDefault;
- } else if (cnx->angleBackend != angleBackendDefault) {
- return false;
- }
-
attrs.reserve(4 * 2);
attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
@@ -186,6 +140,7 @@
switch (cnx->angleBackend) {
case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
ALOGV("%s: Requesting Vulkan ANGLE back-end", __FUNCTION__);
+ char prop[PROPERTY_VALUE_MAX];
property_get("debug.angle.validation", prop, "0");
attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
attrs.push_back(atoi(prop));
@@ -212,7 +167,7 @@
// Initialize function ptrs for ANGLE PlatformMethods struct, used for systrace
bool initializeAnglePlatform(EGLDisplay dpy) {
// Since we're inside libEGL, use dlsym to lookup fptr for ANGLEGetDisplayPlatform
- android_namespace_t* ns = android_getAngleNamespace();
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = ns,
@@ -260,7 +215,7 @@
}
}
- if (!addAnglePlatformAttributes(cnx, attrib_list, attrs)) {
+ if (!addAnglePlatformAttributes(cnx, attrs)) {
ALOGE("eglGetDisplay(%p) failed: Mismatch display request", display);
*error = EGL_BAD_PARAMETER;
return EGL_NO_DISPLAY;
@@ -320,8 +275,7 @@
disp.dpy = dpy;
if (dpy == EGL_NO_DISPLAY) {
- loader.close(cnx->dso);
- cnx->dso = nullptr;
+ loader.close(cnx);
}
}
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index 6900b8b..dd8fbfc 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -144,8 +144,8 @@
std::string LayerLoader::GetDebugLayers() {
// Layers can be specified at the Java level in GraphicsEnvironemnt
- // gpu_debug_layers = layer1:layer2:layerN
- std::string debug_layers = android_getDebugLayers();
+ // gpu_debug_layers_gles = layer1:layer2:layerN
+ std::string debug_layers = android::GraphicsEnv::getInstance().getDebugLayersGLES();
if (debug_layers.empty()) {
// Only check system properties if Java settings are empty
@@ -339,7 +339,9 @@
// Load the layers in reverse order so we start with the driver's entrypoint and work our way up
for (int32_t i = layers.size() - 1; i >= 0; i--) {
// Check each layer path for the layer
- std::vector<std::string> paths = android::base::Split(android_getLayerPaths(), ":");
+ std::vector<std::string> paths =
+ android::base::Split(android::GraphicsEnv::getInstance().getLayerPaths().c_str(),
+ ":");
if (!system_path.empty()) {
// Prepend the system paths so they override other layers
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 1daa4d2..547a669 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -485,58 +485,29 @@
}
// Returns a list of color spaces understood by the vendor EGL driver.
-static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp,
- android_pixel_format format) {
+static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp) {
std::vector<EGLint> colorSpaces;
- if (!dp->hasColorSpaceSupport) return colorSpaces;
- // OpenGL drivers only support sRGB encoding with 8-bit formats.
- // RGB_888 is never returned by getNativePixelFormat, but is included for completeness.
- const bool formatSupportsSRGBEncoding =
- format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 ||
- format == HAL_PIXEL_FORMAT_RGB_888;
- const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16;
+ // sRGB and linear are always supported when color space support is present.
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+ colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
- if (formatSupportsSRGBEncoding) {
- // sRGB and linear are always supported when color space support is present.
- colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
- colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
- // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_display_p3")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
- }
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
}
-
- // According to the spec, scRGB is only supported for floating point formats.
- // For non-linear scRGB, the application is responsible for applying the
- // transfer function.
- if (formatIsFloatingPoint) {
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_scrgb")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
- }
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_scrgb_linear")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
- }
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
}
-
- // BT2020 can be used with any pixel format. PQ encoding must be applied by the
- // application and does not affect the behavior of OpenGL.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_bt2020_linear")) {
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb_linear")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
+ }
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_linear")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
}
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_bt2020_pq")) {
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_pq")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
}
-
- // Linear DCI-P3 simply uses different primaries than standard RGB and thus
- // can be used with any pixel format.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_display_p3_linear")) {
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3_linear")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
}
return colorSpaces;
@@ -547,18 +518,32 @@
// unmodified.
template <typename AttrType>
static EGLBoolean processAttributes(egl_display_ptr dp, ANativeWindow* window,
- android_pixel_format format, const AttrType* attrib_list,
- EGLint* colorSpace, std::vector<AttrType>* strippedAttribList) {
+ const AttrType* attrib_list, EGLint* colorSpace,
+ std::vector<AttrType>* strippedAttribList) {
for (const AttrType* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
bool copyAttribute = true;
if (attr[0] == EGL_GL_COLORSPACE_KHR) {
- // Fail immediately if the driver doesn't have color space support at all.
- if (!dp->hasColorSpaceSupport) return false;
+ switch (attr[1]) {
+ case EGL_GL_COLORSPACE_LINEAR_KHR:
+ case EGL_GL_COLORSPACE_SRGB_KHR:
+ case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
+ case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
+ case EGL_GL_COLORSPACE_SCRGB_EXT:
+ case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT:
+ case EGL_GL_COLORSPACE_BT2020_PQ_EXT:
+ case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
+ // Fail immediately if the driver doesn't have color space support at all.
+ if (!dp->hasColorSpaceSupport) return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ break;
+ default:
+ // BAD_ATTRIBUTE if attr is not any of the EGL_GL_COLORSPACE_*
+ return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
*colorSpace = static_cast<EGLint>(attr[1]);
// Strip the attribute if the driver doesn't understand it.
copyAttribute = false;
- std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format);
+ std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp);
for (auto driverColorSpace : driverColorSpaces) {
if (static_cast<EGLint>(attr[1]) == driverColorSpace) {
copyAttribute = true;
@@ -585,10 +570,8 @@
// If the passed color space has wide color gamut, check whether the target native window
// supports wide color.
- const bool colorSpaceIsNarrow =
- *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
- *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR ||
- *colorSpace == EGL_UNKNOWN;
+ const bool colorSpaceIsNarrow = *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
+ *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR || *colorSpace == EGL_UNKNOWN;
if (window && !colorSpaceIsNarrow) {
bool windowSupportsWideColor = true;
// Ordinarily we'd put a call to native_window_get_wide_color_support
@@ -606,12 +589,12 @@
ALOGE("processAttributes: invalid window (win=%p) "
"failed (%#x) (already connected to another API?)",
window, err);
- return false;
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_FALSE);
}
if (!windowSupportsWideColor) {
// Application has asked for a wide-color colorspace but
// wide-color support isn't available on the display the window is on.
- return false;
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
}
}
return true;
@@ -695,8 +678,7 @@
native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata);
s->resetSmpte2086Metadata();
if (err != 0) {
- ALOGE("error setting native window smpte2086 metadata: %s (%d)",
- strerror(-err), err);
+ ALOGE("error setting native window smpte2086 metadata: %s (%d)", strerror(-err), err);
return EGL_FALSE;
}
}
@@ -706,8 +688,7 @@
native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata);
s->resetCta8613Metadata();
if (err != 0) {
- ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
- strerror(-err), err);
+ ALOGE("error setting native window CTS 861.3 metadata: %s (%d)", strerror(-err), err);
return EGL_FALSE;
}
}
@@ -749,10 +730,12 @@
// now select correct colorspace and dataspace based on user's attribute list
EGLint colorSpace = EGL_UNKNOWN;
std::vector<AttrType> strippedAttribList;
- if (!processAttributes<AttrType>(dp, window, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
+ if (!processAttributes<AttrType>(dp, window, attrib_list, &colorSpace, &strippedAttribList)) {
ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ }
+ return EGL_NO_SURFACE;
}
attrib_list = strippedAttribList.data();
@@ -765,13 +748,14 @@
}
android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
- if (dataSpace != HAL_DATASPACE_UNKNOWN) {
- err = native_window_set_buffers_data_space(window, dataSpace);
- if (err != 0) {
- ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
+ // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN.
+ // HAL_DATASPACE_UNKNOWN is the default value, but it may have changed
+ // at this point.
+ err = native_window_set_buffers_data_space(window, dataSpace);
+ if (err != 0) {
+ ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
}
@@ -873,9 +857,8 @@
return EGL_NO_SURFACE;
}
-EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list)
-{
+EGLSurface eglCreatePbufferSurfaceImpl(EGLDisplay dpy, EGLConfig config,
+ const EGLint* attrib_list) {
egl_connection_t* cnx = nullptr;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
@@ -886,35 +869,30 @@
// Select correct colorspace based on user's attribute list
EGLint colorSpace = EGL_UNKNOWN;
std::vector<EGLint> strippedAttribList;
- if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
+ if (!processAttributes(dp, nullptr, attrib_list, &colorSpace, &strippedAttribList)) {
ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ return EGL_NO_SURFACE;
}
attrib_list = strippedAttribList.data();
- EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
- dp->disp.dpy, config, attrib_list);
+ EGLSurface surface = cnx->egl.eglCreatePbufferSurface(dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s =
- new egl_surface_t(dp.get(), config, nullptr, surface,
- getReportedColorSpace(colorSpace), cnx);
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface,
+ getReportedColorSpace(colorSpace), cnx);
return s;
}
}
return EGL_NO_SURFACE;
}
-EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface)
-{
+EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- egl_surface_t * const s = get_surface(surface);
+ egl_surface_t* const s = get_surface(surface);
EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
if (result == EGL_TRUE) {
_s.terminate();
@@ -922,17 +900,15 @@
return result;
}
-EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint *value)
-{
+EGLBoolean eglQuerySurfaceImpl(EGLDisplay dpy, EGLSurface surface, EGLint attribute,
+ EGLint* value) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- egl_surface_t const * const s = get_surface(surface);
+ egl_surface_t const* const s = get_surface(surface);
if (s->getColorSpaceAttribute(attribute, value)) {
return EGL_TRUE;
} else if (s->getSmpte2086Attribute(attribute, value)) {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 7c710d5..cca0053 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -76,9 +76,11 @@
void* libGles1;
void* libGles2;
+ bool angleDecided;
bool useAngle;
EGLint angleBackend;
void* vendorEGL;
+ void* featureSo;
};
// clang-format on
diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt
index fa26e33..b2d7957 100644
--- a/opengl/libs/libEGL.map.txt
+++ b/opengl/libs/libEGL.map.txt
@@ -3,23 +3,30 @@
eglBindAPI;
eglBindTexImage;
eglChooseConfig;
+ eglClientWaitSync; # introduced=29
eglClientWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
eglCopyBuffers;
eglCreateContext;
+ eglCreateImage; # introduced=29
eglCreateImageKHR;
eglCreateNativeClientBufferANDROID; # introduced=24
eglCreatePbufferFromClientBuffer;
eglCreatePbufferSurface;
eglCreatePixmapSurface;
+ eglCreatePlatformPixmapSurface; # introduced=29
+ eglCreatePlatformWindowSurface; # introduced=29
eglCreateStreamFromFileDescriptorKHR; # introduced=23
eglCreateStreamKHR; # introduced=23
eglCreateStreamProducerSurfaceKHR; # introduced=23
+ eglCreateSync; # introduced=29
eglCreateSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
eglCreateWindowSurface;
eglDestroyContext;
+ eglDestroyImage; # introduced=29
eglDestroyImageKHR;
eglDestroyStreamKHR; # introduced=23
eglDestroySurface;
+ eglDestroySync; # introduced=29
eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
eglDupNativeFenceFDANDROID; # vndk
eglGetConfigAttrib;
@@ -30,8 +37,10 @@
eglGetDisplay;
eglGetError;
eglGetNativeClientBufferANDROID; # introduced=26
+ eglGetPlatformDisplay; # introduced=29
eglGetProcAddress;
eglGetStreamFileDescriptorKHR; # introduced=23
+ eglGetSyncAttrib; # introduced=29
eglGetSyncAttribKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
eglGetSystemTimeFrequencyNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
eglGetSystemTimeNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
@@ -64,6 +73,7 @@
eglWaitClient;
eglWaitGL;
eglWaitNative;
+ eglWaitSync; # introduced=29
eglWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
local:
*;
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index f246077..a9e873a 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -25,6 +25,7 @@
"libhidltransport",
"liblog",
"libutils",
+ "libnativewindow",
],
include_dirs: [
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 5927dc1..459b135 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -775,4 +775,169 @@
EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
}
+
+TEST_F(EGLTest, EGLInvalidColorspaceAttribute) {
+ EGLConfig config;
+
+ ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER,
+ EGL_NONE,
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError());
+ ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+}
+
+TEST_F(EGLTest, EGLUnsupportedColorspaceFormatCombo) {
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLBoolean success;
+
+ const EGLint attrs[] = {
+ // clang-format off
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 16,
+ EGL_GREEN_SIZE, 16,
+ EGL_BLUE_SIZE, 16,
+ EGL_ALPHA_SIZE, 16,
+ EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+ EGL_NONE,
+ // clang-format on
+ };
+ success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(1, numConfigs);
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ const EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+ EGL_NONE,
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_BAD_MATCH, eglGetError());
+ ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+}
+
+TEST_F(EGLTest, EGLCreateWindowFailAndSucceed) {
+ EGLConfig config;
+
+ ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER,
+ EGL_NONE,
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError());
+ ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+
+ // Now recreate surface with a valid colorspace. Ensure proper cleanup is done
+ // in the first failed attempt (e.g. native_window_api_disconnect).
+ winAttrs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+ eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGLCreateWindowTwoColorspaces) {
+ EGLConfig config;
+
+ ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ const EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+ EGL_NONE,
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ android_dataspace dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get()));
+ ASSERT_EQ(dataspace, HAL_DATASPACE_DISPLAY_P3);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+
+ // Now create with default attribute (EGL_GL_COLORSPACE_LINEAR_KHR)
+ eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get()));
+ // Make sure the dataspace has been reset to UNKNOWN
+ ASSERT_NE(dataspace, HAL_DATASPACE_DISPLAY_P3);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
}
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
new file mode 100644
index 0000000..a9af22f
--- /dev/null
+++ b/services/bufferhub/Android.bp
@@ -0,0 +1,61 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_shared {
+ name: "libbufferhubservice",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ srcs: [
+ "BufferHubService.cpp",
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ ],
+ export_include_dirs: [
+ "include"
+ ],
+}
+
+cc_binary {
+ name: "android.frameworks.bufferhub@1.0-service",
+ relative_install_path: "hw",
+ srcs: [
+ "main_bufferhub.cpp"
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libbufferhubservice",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ init_rc: ["android.frameworks.bufferhub@1.0-service.rc"],
+ vintf_fragments: ["android.frameworks.bufferhub@1.0-service.xml"],
+}
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
new file mode 100644
index 0000000..8be85a5
--- /dev/null
+++ b/services/bufferhub/BufferHubService.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferHubService.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::status_t;
+using ::android::hardware::Void;
+
+Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& /*description*/,
+ allocateBuffer_cb /*hidl_cb*/) {
+ return Void();
+}
+
+Return<sp<IBase>> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/) {
+ return nullptr;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc
new file mode 100644
index 0000000..36fbede
--- /dev/null
+++ b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc
@@ -0,0 +1,6 @@
+service system_bufferhub /system/bin/hw/android.frameworks.bufferhub@1.0-service
+ class hal animation
+ user system
+ group system graphics
+ onrestart restart surfaceflinger
+ writepid /dev/cpuset/system-background/tasks
diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml
new file mode 100644
index 0000000..bd958d3
--- /dev/null
+++ b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.frameworks.bufferhub</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IBufferHub</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
new file mode 100644
index 0000000..b273e5b
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
+using ::android::hidl::base::V1_0::IBase;
+
+class BufferHubService : public IBufferHub {
+public:
+ Return<void> allocateBuffer(const HardwareBufferDescription& /*description*/,
+ allocateBuffer_cb /*hidl_cb*/) override;
+ Return<sp<IBase>> importBuffer(const hidl_handle& /*nativeHandle*/) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
diff --git a/services/bufferhub/main_bufferhub.cpp b/services/bufferhub/main_bufferhub.cpp
new file mode 100644
index 0000000..084460d
--- /dev/null
+++ b/services/bufferhub/main_bufferhub.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferHubService.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+#include <log/log.h>
+
+using android::sp;
+using android::frameworks::bufferhub::V1_0::IBufferHub;
+using android::frameworks::bufferhub::V1_0::implementation::BufferHubService;
+
+int main(int /*argc*/, char** /*argv*/) {
+ ALOGI("Bootstrap bufferhub HIDL service.");
+
+ android::hardware::configureRpcThreadpool(/*numThreads=*/1, /*willJoin=*/true);
+
+ sp<IBufferHub> service = new BufferHubService();
+ LOG_ALWAYS_FATAL_IF(service->registerAsService() != android::OK, "Failed to register service");
+
+ android::hardware::joinRpcThreadpool();
+
+ return 0;
+}
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2cad986..2e984d9 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2545,6 +2545,9 @@
uint32_t policyFlags = args->policyFlags;
int32_t flags = args->flags;
int32_t metaState = args->metaState;
+ // InputDispatcher tracks and generates key repeats on behalf of
+ // whatever notifies it, so repeatCount should always be set to 0
+ constexpr int32_t repeatCount = 0;
if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
policyFlags |= POLICY_FLAG_VIRTUAL;
flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
@@ -2560,7 +2563,7 @@
KeyEvent event;
event.initialize(args->deviceId, args->source, args->displayId, args->action,
- flags, keyCode, args->scanCode, metaState, 0,
+ flags, keyCode, args->scanCode, metaState, repeatCount,
args->downTime, args->eventTime);
android::base::Timer t;
@@ -2585,7 +2588,6 @@
mLock.lock();
}
- int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, args->displayId, policyFlags,
args->action, flags, keyCode, args->scanCode,
@@ -2756,7 +2758,7 @@
accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
/*byref*/ keyCode, /*byref*/ metaState);
keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
- action, flags, keyCode, keyEvent.getScanCode(), metaState, 0,
+ action, flags, keyCode, keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(),
keyEvent.getDownTime(), keyEvent.getEventTime());
if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 5df8ade..73098bf 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -470,8 +470,7 @@
}
// TODO(marissaw): properly support mTimeStats
- mTimeStats.setLayerName(layerID, getName().c_str());
- mTimeStats.setPostTime(layerID, getFrameNumber(), latchTime);
+ mTimeStats.setPostTime(layerID, getFrameNumber(), getName().c_str(), latchTime);
mTimeStats.setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
mTimeStats.setLatchTime(layerID, getFrameNumber(), latchTime);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 88c3c8a..2e564e7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1476,9 +1476,8 @@
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) {
if (newTimestamps) {
- const int32_t layerID = getSequence();
- mTimeStats.setLayerName(layerID, getName().c_str());
- mTimeStats.setPostTime(layerID, newTimestamps->frameNumber, newTimestamps->postedTime);
+ mTimeStats.setPostTime(getSequence(), newTimestamps->frameNumber, getName().c_str(),
+ newTimestamps->postedTime);
}
Mutex::Autolock lock(mFrameEventHistoryMutex);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ab07bc6..5c31ada 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -196,8 +196,10 @@
int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
bool SurfaceFlinger::useColorManagement;
bool SurfaceFlinger::useContextPriority;
-Dataspace SurfaceFlinger::compositionDataSpace = Dataspace::V0_SRGB;
-ui::PixelFormat SurfaceFlinger::compositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
std::string getHwcServiceName() {
char value[PROPERTY_VALUE_MAX] = {};
@@ -303,10 +305,13 @@
auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
if (surfaceFlingerConfigsServiceV1_2) {
surfaceFlingerConfigsServiceV1_2->getCompositionPreference(
- [&](Dataspace tmpDataSpace, ui::PixelFormat tmpPixelFormat) {
- compositionDataSpace = tmpDataSpace;
- compositionPixelFormat = tmpPixelFormat;
- });
+ [&](auto tmpDefaultDataspace, auto tmpDefaultPixelFormat,
+ auto tmpWideColorGamutDataspace, auto tmpWideColorGamutPixelFormat) {
+ defaultCompositionDataspace = tmpDefaultDataspace;
+ defaultCompositionPixelFormat = tmpDefaultPixelFormat;
+ wideColorGamutCompositionDataspace = tmpWideColorGamutDataspace;
+ wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
+ });
}
useContextPriority = getBool<ISurfaceFlingerConfigs,
@@ -513,6 +518,10 @@
return mDisplayTokens[id];
}
+bool SurfaceFlinger::isColorManagementUsed() const {
+ return useColorManagement;
+}
+
void SurfaceFlinger::bootFinished()
{
if (mStartPropertySetThread->join() != NO_ERROR) {
@@ -634,8 +643,8 @@
// TODO(b/77156734): We need to stop casting and use HAL types when possible.
getBE().mRenderEngine =
- renderengine::RenderEngine::create(static_cast<int32_t>(compositionPixelFormat),
- renderEngineFeature);
+ renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
+ renderEngineFeature);
LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
@@ -1153,10 +1162,14 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getCompositionPreference(Dataspace* outDataSpace,
- ui::PixelFormat* outPixelFormat) const {
- *outDataSpace = compositionDataSpace;
- *outPixelFormat = compositionPixelFormat;
+status_t SurfaceFlinger::getCompositionPreference(
+ Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+ Dataspace* outWideColorGamutDataspace,
+ ui::PixelFormat* outWideColorGamutPixelFormat) const {
+ *outDataspace = defaultCompositionDataspace;
+ *outPixelFormat = defaultCompositionPixelFormat;
+ *outWideColorGamutDataspace = wideColorGamutCompositionDataspace;
+ *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
return NO_ERROR;
}
@@ -4744,6 +4757,7 @@
case SET_TRANSACTION_STATE:
// Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
case CREATE_SCOPED_CONNECTION:
+ case IS_COLOR_MANAGEMET_USED:
case GET_COMPOSITION_PREFERENCE: {
return OK;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9e47b3f..d60765c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -294,8 +294,14 @@
// The data space and pixel format that SurfaceFlinger expects hardware composer
// to composite efficiently. Meaning under most scenarios, hardware composer
// will accept layers with the data space and pixel format.
- static ui::Dataspace compositionDataSpace;
- static ui::PixelFormat compositionPixelFormat;
+ static ui::Dataspace defaultCompositionDataspace;
+ static ui::PixelFormat defaultCompositionPixelFormat;
+
+ // The data space and pixel format that SurfaceFlinger expects hardware composer
+ // to composite efficiently for wide color gamut surfaces. Meaning under most scenarios,
+ // hardware composer will accept layers with the data space and pixel format.
+ static ui::Dataspace wideColorGamutCompositionDataspace;
+ static ui::PixelFormat wideColorGamutCompositionPixelFormat;
static char const* getServiceName() ANDROID_API {
return "SurfaceFlinger";
@@ -460,8 +466,10 @@
virtual status_t enableVSyncInjections(bool enable);
virtual status_t injectVSync(nsecs_t when);
virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
- status_t getCompositionPreference(ui::Dataspace* outDataSpace,
- ui::PixelFormat* outPixelFormat) const override;
+ virtual bool isColorManagementUsed() const;
+ status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+ ui::Dataspace* outWideColorGamutDataspace,
+ ui::PixelFormat* outWideColorGamutPixelFormat) const override;
/* ------------------------------------------------------------------------
* DeathRecipient interface
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 43fa262..ace7c1b 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -241,25 +241,18 @@
return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
}
-void TimeStats::setLayerName(int32_t layerID, const std::string& layerName) {
+void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+ nsecs_t postTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%d]-[%s]", layerID, layerName.c_str());
+ ALOGV("[%d]-[%" PRIu64 "]-[%s]-PostTime[%" PRId64 "]", layerID, frameNumber, layerName.c_str(),
+ postTime);
std::lock_guard<std::mutex> lock(mMutex);
if (!mTimeStatsTracker.count(layerID) && layerNameIsValid(layerName)) {
mTimeStatsTracker[layerID].layerName = layerName;
}
-}
-
-void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime) {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
- ALOGV("[%d]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerID, frameNumber, postTime);
-
- std::lock_guard<std::mutex> lock(mMutex);
if (!mTimeStatsTracker.count(layerID)) return;
LayerRecord& layerRecord = mTimeStatsTracker[layerID];
if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
@@ -451,6 +444,8 @@
}
void TimeStats::flushPowerTimeLocked() {
+ if (!mEnabled.load()) return;
+
nsecs_t curTime = systemTime();
// elapsedTime is in milliseconds.
int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
@@ -500,10 +495,14 @@
ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
mGlobalRecord.presentFences.front()->getSignalTime());
- const int32_t presentToPresentMs = msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
- ALOGV("Global present2present[%d]", presentToPresentMs);
+ if (mGlobalRecord.prevPresentTime != 0) {
+ const int32_t presentToPresentMs =
+ msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
+ ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
+ presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
+ mTimeStats.presentToPresent.insert(presentToPresentMs);
+ }
- mTimeStats.presentToPresent.insert(presentToPresentMs);
mGlobalRecord.prevPresentTime = curPresentTime;
mGlobalRecord.presentFences.pop_front();
}
@@ -514,7 +513,15 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (presentFence == nullptr) {
+ if (presentFence == nullptr || !presentFence->isValid()) {
+ mGlobalRecord.prevPresentTime = 0;
+ return;
+ }
+
+ if (mPowerTime.powerMode != HWC_POWER_MODE_NORMAL) {
+ // Try flushing the last present fence on HWC_POWER_MODE_NORMAL.
+ flushAvailableGlobalRecordsToStatsLocked();
+ mGlobalRecord.presentFences.clear();
mGlobalRecord.prevPresentTime = 0;
return;
}
@@ -537,10 +544,10 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Enabled");
mEnabled.store(true);
mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
+ ALOGD("Enabled");
}
void TimeStats::disable() {
@@ -549,16 +556,17 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Disabled");
+ flushPowerTimeLocked();
mEnabled.store(false);
mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ ALOGD("Disabled");
}
void TimeStats::clear() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- ALOGD("Cleared");
+ mTimeStatsTracker.clear();
mTimeStats.stats.clear();
mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
mTimeStats.statsEnd = 0;
@@ -568,6 +576,9 @@
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
mPowerTime.prevTime = systemTime();
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.clear();
+ ALOGD("Cleared");
}
bool TimeStats::isEnabled() {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index d1e554c..184bf40 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -86,8 +86,8 @@
void incrementMissedFrames();
void incrementClientCompositionFrames();
- void setLayerName(int32_t layerID, const std::string& layerName);
- void setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime);
+ void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+ nsecs_t postTime);
void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index c701224..599ff5c 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -39,7 +39,7 @@
if (delta < 0) return;
// std::lower_bound won't work on out of range values
if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
- hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
+ hist[histogramConfig[HISTOGRAM_SIZE - 1]] += delta / histogramConfig[HISTOGRAM_SIZE - 1];
return;
}
auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 3166a8c..c814142 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -30,6 +30,7 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <ui/ColorSpace.h>
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <utils/String8.h>
@@ -314,6 +315,10 @@
ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<IBinder> binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ mColorManagementUsed = sf->isColorManagementUsed();
}
virtual void TearDown() {
@@ -470,6 +475,8 @@
void setMatrixWithResizeHelper(uint32_t layerType);
sp<SurfaceControl> mBlackBgSurface;
+ bool mColorManagementUsed;
+
private:
void SetUpDisplay() {
mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
@@ -2064,6 +2071,47 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
+class ColorTransformHelper {
+public:
+ static void DegammaColorSingle(half& s) {
+ if (s <= 0.03928f)
+ s = s / 12.92f;
+ else
+ s = pow((s + 0.055f) / 1.055f, 2.4f);
+ }
+
+ static void DegammaColor(half3& color) {
+ DegammaColorSingle(color.r);
+ DegammaColorSingle(color.g);
+ DegammaColorSingle(color.b);
+ }
+
+ static void GammaColorSingle(half& s) {
+ if (s <= 0.0031308f) {
+ s = s * 12.92f;
+ } else {
+ s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
+ }
+ }
+
+ static void GammaColor(half3& color) {
+ GammaColorSingle(color.r);
+ GammaColorSingle(color.g);
+ GammaColorSingle(color.b);
+ }
+
+ static void applyMatrix(half3& color, const mat3& mat) {
+ half3 ret = half3(0);
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ ret[i] = ret[i] + color[j] * mat[j][i];
+ }
+ }
+ color = ret;
+ }
+};
+
TEST_F(LayerTransactionTest, SetColorTransformBasic) {
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(
@@ -2076,19 +2124,35 @@
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- const Color expected = {90, 90, 90, 255};
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
+ half3 expected = color;
mat3 matrix;
matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrix);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
Transaction().setColor(colorLayer, color)
.setColorTransform(colorLayer, matrix, vec3()).apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+ screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
diff --git a/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp b/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
index 0efd732..bb48387 100644
--- a/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
+++ b/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
@@ -68,6 +68,8 @@
static_cast<size_t>(ThrottlingSeverity::SEVERE))
? true
: false;
+ value = temperature.value == UNKNOWN_TEMPERATURE ? NAN :
+ temperature.value;
android::os::Temperature thermal_svc_temp(value, type);
mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
} else {
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index c35ddd4..5debd3d 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -29,6 +29,7 @@
name: "libbufferhubd",
srcs: [
"buffer_channel.cpp",
+ "buffer_client.cpp",
"buffer_hub.cpp",
"buffer_hub_binder.cpp",
"buffer_node.cpp",
@@ -44,7 +45,10 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
export_include_dirs: ["include"],
- header_libs: ["libdvr_headers"],
+ header_libs: [
+ "libdvr_headers",
+ "libnativewindow_headers",
+ ],
shared_libs: sharedLibraries,
static_libs: [
"libbufferhub",
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
index 2f39e41..022a9cc 100644
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -13,6 +13,8 @@
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) override;
+
+ status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
};
IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
@@ -20,6 +22,7 @@
// Transaction code
enum {
CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ IMPORT_BUFFER,
};
sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
@@ -50,6 +53,27 @@
}
}
+status_t BpBufferHub::importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) {
+ Parcel data, reply;
+ status_t ret = NO_ERROR;
+ ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
+ ret |= data.writeUint64(token);
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferHub::importBuffer: failed to write into parcel");
+ return ret;
+ }
+
+ ret = remote()->transact(IMPORT_BUFFER, data, &reply);
+ if (ret == NO_ERROR) {
+ *outClient = interface_cast<IBufferClient>(reply.readStrongBinder());
+ return NO_ERROR;
+ } else {
+ ALOGE("BpBufferHub::importBuffer: failed to transact; errno=%d", ret);
+ return ret;
+ }
+}
+
status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
@@ -64,7 +88,18 @@
sp<IBufferClient> ret = createBuffer(width, height, layer_count, format,
usage, user_metadata_size);
return reply->writeStrongBinder(IInterface::asBinder(ret));
- } break;
+ }
+ case IMPORT_BUFFER: {
+ CHECK_INTERFACE(IBufferHub, data, reply);
+ uint64_t token = data.readUint64();
+ sp<IBufferClient> client;
+ status_t ret = importBuffer(token, &client);
+ if (ret == NO_ERROR) {
+ return reply->writeStrongBinder(IInterface::asBinder(client));
+ } else {
+ return ret;
+ }
+ }
default:
// Should not reach except binder defined transactions such as dumpsys
return BBinder::onTransact(code, data, reply, flags);
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index bccfe67..589b31a 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -13,15 +13,6 @@
namespace dvr {
BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
- int channel_id, IonBuffer buffer,
- size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_node_(
- std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)) {
- client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
-}
-
-BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
uint64_t usage, size_t user_metadata_size)
@@ -58,9 +49,9 @@
BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
return BufferInfo(
- buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
- buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
- buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+ buffer_id(), /*consumer_count=*/0, buffer_node_->buffer_desc().width,
+ buffer_node_->buffer_desc().height, buffer_node_->buffer_desc().layers,
+ buffer_node_->buffer_desc().format, buffer_node_->buffer_desc().usage,
/*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
/*index=*/0);
}
@@ -94,17 +85,17 @@
// TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
return BufferTraits<BorrowedHandle>{
- /*buffer_handle=*/buffer_node_->buffer().handle(),
+ /*buffer_handle=*/buffer_node_->buffer_handle(),
/*metadata_handle=*/buffer_node_->metadata().ashmem_handle().Borrow(),
/*id=*/buffer_id(),
/*client_state_mask=*/client_state_mask_,
/*metadata_size=*/buffer_node_->metadata().metadata_size(),
- /*width=*/buffer_node_->buffer().width(),
- /*height=*/buffer_node_->buffer().height(),
- /*layer_count=*/buffer_node_->buffer().layer_count(),
- /*format=*/buffer_node_->buffer().format(),
- /*usage=*/buffer_node_->buffer().usage(),
- /*stride=*/buffer_node_->buffer().stride(),
+ /*width=*/buffer_node_->buffer_desc().width,
+ /*height=*/buffer_node_->buffer_desc().height,
+ /*layer_count=*/buffer_node_->buffer_desc().layers,
+ /*format=*/buffer_node_->buffer_desc().format,
+ /*usage=*/buffer_node_->buffer_desc().usage,
+ /*stride=*/buffer_node_->buffer_desc().stride,
/*acquire_fence_fd=*/BorrowedHandle{},
/*released_fence_fd=*/BorrowedHandle{}};
}
diff --git a/services/vr/bufferhubd/buffer_client.cpp b/services/vr/bufferhubd/buffer_client.cpp
new file mode 100644
index 0000000..f14faf7
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_client.cpp
@@ -0,0 +1,18 @@
+#include <private/dvr/buffer_client.h>
+#include <private/dvr/buffer_hub_binder.h>
+
+namespace android {
+namespace dvr {
+
+status_t BufferClient::duplicate(uint64_t* outToken) {
+ if (!buffer_node_) {
+ // Should never happen
+ ALOGE("BufferClient::duplicate: node is missing.");
+ return UNEXPECTED_NULL;
+ }
+ return service_->registerToken(std::weak_ptr<BufferNode>(buffer_node_),
+ outToken);
+}
+
+} // namespace dvr
+} // namespace android
\ No newline at end of file
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 6421a0b..b73c47d 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -256,15 +256,6 @@
*this, &BufferHubService::OnCreateProducerQueue, message);
return {};
- case BufferHubRPC::ProducerBufferDetach::Opcode:
- // In addition to the message handler in the ProducerChannel's
- // HandleMessage method, we also need to invalid the producer channel (and
- // all associated consumer channels). Note that this has to be done after
- // HandleMessage returns to make sure the IPC request has went back to the
- // client first.
- SetChannel(channel->channel_id(), nullptr);
- return {};
-
default:
return DefaultHandleMessage(message);
}
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index f8a9758..afd34aa 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -65,18 +65,65 @@
return NO_ERROR;
}
+status_t BufferHubBinderService::registerToken(
+ const std::weak_ptr<BufferNode> node, uint64_t* outToken) {
+ do {
+ *outToken = token_engine_();
+ } while (token_map_.find(*outToken) != token_map_.end());
+
+ token_map_.emplace(*outToken, node);
+ return NO_ERROR;
+}
+
sp<IBufferClient> BufferHubBinderService::createBuffer(
uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
uint64_t usage, uint64_t user_metadata_size) {
std::shared_ptr<BufferNode> node = std::make_shared<BufferNode>(
width, height, layer_count, format, usage, user_metadata_size);
- sp<BufferClient> client = new BufferClient(node);
+ sp<BufferClient> client = new BufferClient(node, this);
// Add it to list for bookkeeping and dumpsys.
client_list_.push_back(client);
return client;
}
+status_t BufferHubBinderService::importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) {
+ auto iter = token_map_.find(token);
+
+ if (iter == token_map_.end()) { // Not found
+ ALOGE("BufferHubBinderService::importBuffer: token %" PRIu64
+ "does not exist.",
+ token);
+ return PERMISSION_DENIED;
+ }
+
+ if (iter->second.expired()) { // Gone
+ ALOGW(
+ "BufferHubBinderService::importBuffer: the original node of token "
+ "%" PRIu64 "has gone.",
+ token);
+ token_map_.erase(iter);
+ return DEAD_OBJECT;
+ }
+
+ // Promote the weak_ptr
+ std::shared_ptr<BufferNode> node(iter->second);
+ if (!node) {
+ ALOGE("BufferHubBinderService::importBuffer: promote weak_ptr failed.");
+ token_map_.erase(iter);
+ return DEAD_OBJECT;
+ }
+
+ sp<BufferClient> client = new BufferClient(node, this);
+ *outClient = client;
+
+ token_map_.erase(iter);
+ client_list_.push_back(client);
+
+ return NO_ERROR;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
index e74a21f..31c6ef0 100644
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -1,6 +1,9 @@
#include <errno.h>
+
+#include <private/dvr/IBufferHub.h>
#include <private/dvr/buffer_hub_defs.h>
#include <private/dvr/buffer_node.h>
+#include <ui/GraphicBufferAllocator.h>
namespace android {
namespace dvr {
@@ -15,24 +18,30 @@
new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
}
-BufferNode::BufferNode(IonBuffer buffer, size_t user_metadata_size)
- : buffer_(std::move(buffer)) {
- metadata_ = BufferHubMetadata::Create(user_metadata_size);
- InitializeMetadata();
-}
-
// Allocates a new BufferNode.
BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
uint32_t format, uint64_t usage,
size_t user_metadata_size) {
- if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "buffer: %s",
- strerror(-ret));
+ uint32_t out_stride = 0;
+ // graphicBufferId is not used in GraphicBufferAllocator::allocate
+ int ret = GraphicBufferAllocator::get().allocate(
+ width, height, format, layer_count, usage,
+ const_cast<const native_handle_t**>(&buffer_handle_), &out_stride,
+ /*graphicBufferId=*/0, IBufferHub::getServiceName());
+
+ if (ret != OK || buffer_handle_ == nullptr) {
+ ALOGE("BufferNode::BufferNode: Failed to allocate buffer: %s",
+ strerror(-ret));
return;
}
+ buffer_desc_.width = width;
+ buffer_desc_.height = height;
+ buffer_desc_.layers = layer_count;
+ buffer_desc_.format = format;
+ buffer_desc_.usage = usage;
+ buffer_desc_.stride = out_stride;
+
metadata_ = BufferHubMetadata::Create(user_metadata_size);
if (!metadata_.IsValid()) {
ALOGE("BufferNode::BufferNode: Failed to allocate metadata.");
@@ -41,6 +50,17 @@
InitializeMetadata();
}
+// Free the handle
+BufferNode::~BufferNode() {
+ if (buffer_handle_ != nullptr) {
+ status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
+ if (ret != OK) {
+ ALOGE("BufferNode::~BufferNode: Failed to free handle; Got error: %d",
+ ret);
+ }
+ }
+}
+
uint64_t BufferNode::GetActiveClientsBitMask() const {
return active_clients_bit_mask_->load(std::memory_order_acquire);
}
@@ -50,8 +70,8 @@
uint64_t client_state_mask = 0ULL;
uint64_t updated_active_clients_bit_mask = 0ULL;
do {
- client_state_mask =
- BufferHubDefs::FindNextClearedBit(current_active_clients_bit_mask);
+ client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+ current_active_clients_bit_mask);
if (client_state_mask == 0ULL) {
ALOGE(
"BufferNode::AddNewActiveClientsBitToMask: reached the maximum "
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 4ff7adf..98ef917 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -17,10 +17,10 @@
namespace dvr {
ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id,
- int channel_id, uint64_t consumer_state_bit,
+ int channel_id, uint64_t client_state_mask,
const std::shared_ptr<Channel> producer)
: BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
- consumer_state_bit_(consumer_state_bit),
+ client_state_mask_(client_state_mask),
producer_(producer) {
GetProducer()->AddConsumer(this);
}
@@ -41,7 +41,7 @@
// If producer has not hung up, copy most buffer info from the producer.
info = producer->GetBufferInfo();
} else {
- info.signaled_mask = consumer_state_bit();
+ info.signaled_mask = client_state_mask();
}
info.id = buffer_id();
return info;
@@ -100,7 +100,7 @@
ATRACE_NAME("ConsumerChannel::OnGetBuffer");
ALOGD_IF(TRACE, "ConsumerChannel::OnGetBuffer: buffer=%d", buffer_id());
if (auto producer = GetProducer()) {
- return {producer->GetBuffer(consumer_state_bit_)};
+ return {producer->GetBuffer(client_state_mask_)};
} else {
return ErrorStatus(EPIPE);
}
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index bd5f9cf..502c6d6 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -17,6 +17,9 @@
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) = 0;
+
+ virtual status_t importBuffer(uint64_t token,
+ sp<IBufferClient>* outClient) = 0;
};
class BnBufferHub : public BnInterface<IBufferHub> {
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
index 6d1e9e1..744c095 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
@@ -33,9 +33,6 @@
void HandleImpulse(pdx::Message& message) override;
private:
- // Creates a detached buffer from existing IonBuffers.
- BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
- IonBuffer buffer, size_t user_metadata_size);
// Allocates a new detached buffer.
BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
index 20d51ee..d79ec0a 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_client.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
@@ -7,19 +7,31 @@
namespace android {
namespace dvr {
+// Forward declaration to avoid circular dependency
+class BufferHubBinderService;
+
class BufferClient : public BnBufferClient {
public:
// Creates a server-side buffer client from an existing BufferNode. Note that
// this funciton takes ownership of the shared_ptr.
- explicit BufferClient(std::shared_ptr<BufferNode> node)
- : buffer_node_(std::move(node)){};
+ explicit BufferClient(std::shared_ptr<BufferNode> node,
+ BufferHubBinderService* service)
+ : service_(service), buffer_node_(std::move(node)){};
// Binder IPC functions
bool isValid() override {
return buffer_node_ ? buffer_node_->IsValid() : false;
};
+ status_t duplicate(uint64_t* outToken) override;
+
private:
+ // Hold a pointer to the service to bypass binder interface, as BufferClient
+ // and the service will be in the same process. Also, since service owns
+ // Client, if service dead the clients will be destroyed, so this pointer is
+ // guaranteed to be valid.
+ BufferHubBinderService* service_;
+
std::shared_ptr<BufferNode> buffer_node_;
};
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index 9064d87..cf6124b 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -1,12 +1,15 @@
#ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H
#define ANDROID_DVR_BUFFER_HUB_BINDER_H
+#include <random>
+#include <unordered_map>
#include <vector>
#include <binder/BinderService.h>
#include <private/dvr/IBufferHub.h>
#include <private/dvr/buffer_client.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/buffer_node.h>
namespace android {
namespace dvr {
@@ -15,20 +18,33 @@
public BnBufferHub {
public:
static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
- // Dump bufferhub related information to given fd (usually stdout)
+ // Dumps bufferhub related information to given fd (usually stdout)
// usage: adb shell dumpsys bufferhubd
virtual status_t dump(int fd, const Vector<String16>& args) override;
+ // Marks a BufferNode to be duplicated.
+ // TODO(b/116681016): add importToken(int64_t)
+ status_t registerToken(const std::weak_ptr<BufferNode> node,
+ uint64_t* outToken);
+
// Binder IPC functions
sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
uint64_t usage,
uint64_t user_metadata_size) override;
+ status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
+
private:
std::shared_ptr<BufferHubService> pdx_service_;
std::vector<sp<BufferClient>> client_list_;
+
+ // TODO(b/118180214): use a more secure implementation
+ std::mt19937_64 token_engine_;
+ // The mapping from token to a specific node. This is a many-to-one mapping.
+ // One node could be refered by 0 to multiple tokens.
+ std::unordered_map<uint64_t, std::weak_ptr<BufferNode>> token_map_;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
index 067584e..bc0a34e 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
@@ -1,6 +1,7 @@
#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+#include <android/hardware_buffer.h>
#include <private/dvr/ion_buffer.h>
#include <ui/BufferHubMetadata.h>
@@ -9,22 +10,20 @@
class BufferNode {
public:
- // Creates a BufferNode from existing IonBuffers, i.e. creating from an
- // existing ProducerChannel. Allocate a new BufferHubMetadata.
- BufferNode(IonBuffer buffer, size_t user_metadata_size);
-
// Allocates a new BufferNode.
BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
uint32_t format, uint64_t usage, size_t user_metadata_size);
- // Returns whether the object holds a valid graphic buffer.
- bool IsValid() const { return buffer_.IsValid() && metadata_.IsValid(); }
+ ~BufferNode();
+
+ // Returns whether the object holds a valid metadata.
+ bool IsValid() const { return metadata_.IsValid(); }
size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
- // Accessors of the IonBuffer.
- IonBuffer& buffer() { return buffer_; }
- const IonBuffer& buffer() const { return buffer_; }
+ // Accessors of the buffer description and handle
+ const native_handle_t* buffer_handle() const { return buffer_handle_; }
+ const AHardwareBuffer_Desc& buffer_desc() const { return buffer_desc_; }
// Accessors of metadata.
const BufferHubMetadata& metadata() const { return metadata_; }
@@ -52,7 +51,8 @@
void InitializeMetadata();
// Gralloc buffer handles.
- IonBuffer buffer_;
+ native_handle_t* buffer_handle_;
+ AHardwareBuffer_Desc buffer_desc_;
// Metadata in shared memory.
BufferHubMetadata metadata_;
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
index 84f664d..3298529 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
@@ -16,14 +16,14 @@
using Message = pdx::Message;
ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id,
- uint64_t consumer_state_bit,
+ uint64_t client_state_mask,
const std::shared_ptr<Channel> producer);
~ConsumerChannel() override;
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
- uint64_t consumer_state_bit() const { return consumer_state_bit_; }
+ uint64_t client_state_mask() const { return client_state_mask_; }
BufferInfo GetBufferInfo() const override;
bool OnProducerPosted();
@@ -38,7 +38,7 @@
pdx::Status<void> OnConsumerRelease(Message& message,
LocalFence release_fence);
- uint64_t consumer_state_bit_{0};
+ uint64_t client_state_mask_{0};
bool acquired_{false};
bool released_{true};
std::weak_ptr<Channel> producer_;
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
index d98dbbc..8f35437 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
@@ -42,7 +42,7 @@
private:
std::shared_ptr<ProducerQueueChannel> GetProducer() const;
- // Pointer to the prodcuer channel
+ // Pointer to the producer channel.
std::weak_ptr<Channel> producer_;
// Tracks newly allocated buffer producers along with it's slot number.
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index b5c92be..5868b09 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -42,7 +42,9 @@
~ProducerChannel() override;
- uint64_t buffer_state() const { return buffer_state_->load(); }
+ uint64_t buffer_state() const {
+ return buffer_state_->load(std::memory_order_acquire);
+ }
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
@@ -108,7 +110,6 @@
pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
pdx::Status<LocalFence> OnProducerGain(Message& message);
- pdx::Status<RemoteChannelHandle> OnProducerDetach(Message& message);
ProducerChannel(const ProducerChannel&) = delete;
void operator=(const ProducerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index beedc4c..241eee7 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -100,6 +100,12 @@
active_clients_bit_mask_ =
new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
+ // Producer channel is never created after consumer channel, and one buffer
+ // only have one fixed producer for now. Thus, it is correct to assume
+ // producer state bit is kFirstClientBitMask for now.
+ active_clients_bit_mask_->store(BufferHubDefs::kFirstClientBitMask,
+ std::memory_order_release);
+
acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
if (!acquire_fence_fd_ || !release_fence_fd_) {
@@ -161,7 +167,8 @@
ALOGD_IF(TRACE,
"ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
"state=%" PRIx64 ".",
- channel_id(), buffer_id(), buffer_state_->load());
+ channel_id(), buffer_id(),
+ buffer_state_->load(std::memory_order_acquire));
for (auto consumer : consumer_channels_) {
consumer->OnProducerClosed();
}
@@ -170,14 +177,15 @@
BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
// Derive the mask of signaled buffers in this producer / consumer set.
- uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
+ uint64_t signaled_mask = signaled() ? BufferHubDefs::kFirstClientBitMask : 0;
for (const ConsumerChannel* consumer : consumer_channels_) {
- signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
+ signaled_mask |= consumer->signaled() ? consumer->client_state_mask() : 0;
}
return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
buffer_.height(), buffer_.layer_count(), buffer_.format(),
- buffer_.usage(), pending_consumers_, buffer_state_->load(),
+ buffer_.usage(), pending_consumers_,
+ buffer_state_->load(std::memory_order_acquire),
signaled_mask, metadata_header_->queue_index);
}
@@ -216,11 +224,6 @@
*this, &ProducerChannel::OnProducerGain, message);
return true;
- case BufferHubRPC::ProducerBufferDetach::Opcode:
- DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
- *this, &ProducerChannel::OnProducerDetach, message);
- return true;
-
default:
return false;
}
@@ -241,8 +244,8 @@
Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGetBuffer");
ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
- buffer_id(), buffer_state_->load());
- return {GetBuffer(BufferHubDefs::kProducerStateBit)};
+ buffer_id(), buffer_state_->load(std::memory_order_acquire));
+ return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
}
Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
@@ -266,10 +269,9 @@
// that release active_clients_bit_mask_ need to be visible here.
uint64_t current_active_clients_bit_mask =
active_clients_bit_mask_->load(std::memory_order_acquire);
- uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
- current_active_clients_bit_mask | orphaned_consumer_bit_mask_ |
- BufferHubDefs::kProducerStateBit);
- if (consumer_state_bit == 0ULL) {
+ uint64_t client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+ current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
+ if (client_state_mask == 0ULL) {
ALOGE(
"ProducerChannel::CreateConsumer: reached the maximum mumber of "
"consumers per producer: 63.");
@@ -277,7 +279,7 @@
}
uint64_t updated_active_clients_bit_mask =
- current_active_clients_bit_mask | consumer_state_bit;
+ current_active_clients_bit_mask | client_state_mask;
// Set the updated value only if the current value stays the same as what was
// read before. If the comparison succeeds, update the value without
// reordering anything before or after this read-modify-write in the current
@@ -287,15 +289,15 @@
if (!active_clients_bit_mask_->compare_exchange_weak(
current_active_clients_bit_mask, updated_active_clients_bit_mask,
std::memory_order_acq_rel, std::memory_order_acquire)) {
- ALOGE("Current active clients bit mask is changed to %" PRIu64
- ", which was expected to be %" PRIu64 ".",
+ ALOGE("Current active clients bit mask is changed to %" PRIx64
+ ", which was expected to be %" PRIx64 ".",
updated_active_clients_bit_mask, current_active_clients_bit_mask);
return ErrorStatus(EBUSY);
}
auto consumer =
std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
- consumer_state_bit, shared_from_this());
+ client_state_mask, shared_from_this());
const auto channel_status = service()->SetChannel(channel_id, consumer);
if (!channel_status) {
ALOGE(
@@ -304,13 +306,13 @@
channel_status.GetErrorMessage().c_str());
// Restore the consumer state bit and make it visible in other threads that
// acquire the active_clients_bit_mask_.
- active_clients_bit_mask_->fetch_and(~consumer_state_bit,
+ active_clients_bit_mask_->fetch_and(~client_state_mask,
std::memory_order_release);
return ErrorStatus(ENOMEM);
}
- if (!producer_owns_ &&
- !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
+ if (!producer_owns_ && !BufferHubDefs::IsBufferReleased(
+ buffer_state_->load(std::memory_order_acquire))) {
// Signal the new consumer when adding it to a posted producer.
if (consumer->OnProducerPosted())
pending_consumers_++;
@@ -403,13 +405,15 @@
return {std::move(returned_fence_)};
}
-Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
+// TODO(b/112338294) Keep here for reference. Remove it after new logic is
+// written.
+/* Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
Message& message) {
ATRACE_NAME("ProducerChannel::OnProducerDetach");
ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
buffer_id());
- uint64_t buffer_state = buffer_state_->load();
+ uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
// Can only detach a BufferProducer when it's in gained state.
ALOGW(
@@ -455,7 +459,7 @@
}
return status;
-}
+} */
Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
@@ -505,11 +509,11 @@
// has to done by BufferHub as it requries synchronization among all
// consumers.
BufferHubDefs::ModifyBufferState(buffer_state_,
- BufferHubDefs::kProducerStateBit, 0ULL);
+ BufferHubDefs::kFirstClientBitMask, 0ULL);
ALOGD_IF(TRACE,
"ProducerChannel::OnConsumerRelease: releasing last consumer: "
"buffer_id=%d state=%" PRIx64 ".",
- buffer_id(), buffer_state_->load());
+ buffer_id(), buffer_state_->load(std::memory_order_acquire));
if (orphaned_consumer_bit_mask_) {
ALOGW(
@@ -524,11 +528,12 @@
SignalAvailable();
}
- ALOGE_IF(pending_consumers_ &&
- BufferHubDefs::IsBufferReleased(buffer_state_->load()),
- "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
- "pending_consumers=%d, buffer buffer is in releaed state.",
- pending_consumers_);
+ ALOGE_IF(
+ pending_consumers_ && BufferHubDefs::IsBufferReleased(
+ buffer_state_->load(std::memory_order_acquire)),
+ "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
+ "pending_consumers=%d, buffer buffer is in releaed state.",
+ pending_consumers_);
return {};
}
@@ -549,25 +554,26 @@
// Ignore the orphaned consumer.
DecrementPendingConsumers();
- const uint64_t consumer_state_bit = channel->consumer_state_bit();
- ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
+ const uint64_t client_state_mask = channel->client_state_mask();
+ ALOGE_IF(orphaned_consumer_bit_mask_ & client_state_mask,
"ProducerChannel::OnConsumerOrphaned: Consumer "
- "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
- consumer_state_bit);
- orphaned_consumer_bit_mask_ |= consumer_state_bit;
+ "(client_state_mask=%" PRIx64 ") is already orphaned.",
+ client_state_mask);
+ orphaned_consumer_bit_mask_ |= client_state_mask;
// Atomically clear the fence state bit as an orphaned consumer will never
// signal a release fence. Also clear the buffer state as it won't be released
// as well.
- fence_state_->fetch_and(~consumer_state_bit);
- BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
+ fence_state_->fetch_and(~client_state_mask);
+ BufferHubDefs::ModifyBufferState(buffer_state_, client_state_mask, 0ULL);
ALOGW(
"ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
- "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
+ "buffer_id=%d client_state_mask=%" PRIx64 " queue_index=%" PRIu64
" buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
- buffer_id(), consumer_state_bit, metadata_header_->queue_index,
- buffer_state_->load(), fence_state_->load());
+ buffer_id(), client_state_mask, metadata_header_->queue_index,
+ buffer_state_->load(std::memory_order_acquire),
+ fence_state_->load(std::memory_order_acquire));
}
void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
@@ -579,10 +585,10 @@
std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
// Restore the consumer state bit and make it visible in other threads that
// acquire the active_clients_bit_mask_.
- active_clients_bit_mask_->fetch_and(~channel->consumer_state_bit(),
+ active_clients_bit_mask_->fetch_and(~channel->client_state_mask(),
std::memory_order_release);
- const uint64_t buffer_state = buffer_state_->load();
+ const uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
if (BufferHubDefs::IsBufferPosted(buffer_state) ||
BufferHubDefs::IsBufferAcquired(buffer_state)) {
// The consumer client is being destoryed without releasing. This could
@@ -595,10 +601,11 @@
BufferHubDefs::IsBufferGained(buffer_state)) {
// The consumer is being close while it is suppose to signal a release
// fence. Signal the dummy fence here.
- if (fence_state_->load() & channel->consumer_state_bit()) {
+ if (fence_state_->load(std::memory_order_acquire) &
+ channel->client_state_mask()) {
epoll_event event;
event.events = EPOLLIN;
- event.data.u64 = channel->consumer_state_bit();
+ event.data.u64 = channel->client_state_mask();
if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
dummy_fence_fd_.Get(), &event) < 0) {
ALOGE(
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index a80691f..c77d2d2 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -33,7 +33,10 @@
"-DTRACE=0",
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
- header_libs: ["libdvr_headers"],
+ header_libs: [
+ "libdvr_headers",
+ "libnativewindow_headers",
+ ],
static_libs: [
"libbufferhub",
"libbufferhubd",
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index 7fa2226..7c00fa6 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -10,6 +10,7 @@
namespace {
+using testing::IsNull;
using testing::NotNull;
const int kWidth = 640;
@@ -38,6 +39,46 @@
EXPECT_TRUE(bufferClient->isValid());
}
+TEST_F(BufferHubBinderServiceTest, TestDuplicateAndImportBuffer) {
+ sp<IBufferClient> bufferClient = service->createBuffer(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ ASSERT_THAT(bufferClient, NotNull());
+ EXPECT_TRUE(bufferClient->isValid());
+
+ uint64_t token1 = 0ULL;
+ status_t ret = bufferClient->duplicate(&token1);
+ EXPECT_EQ(ret, NO_ERROR);
+
+ // Tokens should be unique even corresponding to the same buffer
+ uint64_t token2 = 0ULL;
+ ret = bufferClient->duplicate(&token2);
+ EXPECT_EQ(ret, NO_ERROR);
+ EXPECT_NE(token2, token1);
+
+ sp<IBufferClient> bufferClient1;
+ ret = service->importBuffer(token1, &bufferClient1);
+ EXPECT_EQ(ret, NO_ERROR);
+ ASSERT_THAT(bufferClient1, NotNull());
+ EXPECT_TRUE(bufferClient1->isValid());
+
+ // Consumes the token to keep the service clean
+ sp<IBufferClient> bufferClient2;
+ ret = service->importBuffer(token2, &bufferClient2);
+ EXPECT_EQ(ret, NO_ERROR);
+ ASSERT_THAT(bufferClient2, NotNull());
+ EXPECT_TRUE(bufferClient2->isValid());
+}
+
+TEST_F(BufferHubBinderServiceTest, TestImportUnexistingToken) {
+ // There is very little chance that this test fails if there is a token = 0
+ // in the service.
+ uint64_t unexistingToken = 0ULL;
+ sp<IBufferClient> bufferClient;
+ status_t ret = service->importBuffer(unexistingToken, &bufferClient);
+ EXPECT_EQ(ret, PERMISSION_DENIED);
+ EXPECT_THAT(bufferClient, IsNull());
+}
+
} // namespace
} // namespace dvr
diff --git a/services/vr/bufferhubd/tests/buffer_node-test.cpp b/services/vr/bufferhubd/tests/buffer_node-test.cpp
index 9a927f1..30ecbec 100644
--- a/services/vr/bufferhubd/tests/buffer_node-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_node-test.cpp
@@ -2,18 +2,22 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <private/dvr/buffer_node.h>
+#include <ui/GraphicBufferMapper.h>
namespace android {
namespace dvr {
namespace {
+using testing::NotNull;
+
const uint32_t kWidth = 640;
const uint32_t kHeight = 480;
const uint32_t kLayerCount = 1;
const uint32_t kFormat = 1;
const uint64_t kUsage = 0;
const size_t kUserMetadataSize = 0;
+const size_t kMaxClientsCount = BufferHubDefs::kMaxNumberOfClients;
class BufferNodeTest : public ::testing::Test {
protected:
@@ -34,6 +38,16 @@
TEST_F(BufferNodeTest, TestCreateBufferNode) {
EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
+ // Test the handle just allocated is good (i.e. able to be imported)
+ GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+ const native_handle_t* outHandle;
+ status_t ret = mapper.importBuffer(
+ buffer_node->buffer_handle(), buffer_node->buffer_desc().width,
+ buffer_node->buffer_desc().height, buffer_node->buffer_desc().layers,
+ buffer_node->buffer_desc().format, buffer_node->buffer_desc().usage,
+ buffer_node->buffer_desc().stride, &outHandle);
+ EXPECT_EQ(ret, OK);
+ EXPECT_THAT(outHandle, NotNull());
}
TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
@@ -55,7 +69,7 @@
uint64_t current_mask = 0ULL;
uint64_t expected_mask = 0ULL;
- for (int i = 0; i < 64; ++i) {
+ for (int i = 0; i < kMaxClientsCount; ++i) {
new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
EXPECT_NE(new_client_state_mask, 0);
EXPECT_FALSE(new_client_state_mask & current_mask);