Merge changes I09f4a157,I738be45b
* changes:
[SurfaceFlinger] Remove saturation matrix of Adaptive mode.
[SurfaceFlinger] Remove usage of legacy data spaces.
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 0ee6c3a..f2678eb 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -137,6 +137,7 @@
dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
dprintf(fd, "version: %s\n", ds_.version_.c_str());
dprintf(fd, "bugreport_dir: %s\n", ds_.bugreport_dir_.c_str());
+ dprintf(fd, "bugreport_internal_dir_: %s\n", ds_.bugreport_internal_dir_.c_str());
dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index df80651..be10232 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -82,6 +82,7 @@
using android::TIMED_OUT;
using android::UNKNOWN_ERROR;
using android::Vector;
+using android::base::StringPrintf;
using android::os::dumpstate::CommandOptions;
using android::os::dumpstate::DumpFileToFd;
using android::os::dumpstate::DumpstateSectionReporter;
@@ -121,6 +122,69 @@
// TODO: temporary variables and functions used during C++ refactoring
static Dumpstate& ds = Dumpstate::GetInstance();
+
+namespace android {
+namespace os {
+namespace {
+
+static int Open(std::string path, int flags, mode_t mode = 0) {
+ int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
+ if (fd == -1) {
+ MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
+ }
+ return fd;
+}
+
+static int OpenForWrite(std::string path) {
+ return Open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+}
+
+static int OpenForRead(std::string path) {
+ return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+}
+
+bool CopyFile(int in_fd, int out_fd) {
+ char buf[4096];
+ ssize_t byte_count;
+ while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
+ if (!android::base::WriteFully(out_fd, buf, byte_count)) {
+ return false;
+ }
+ }
+ return (byte_count != -1);
+}
+
+static bool CopyFileToFd(const std::string& input_file, int out_fd) {
+ MYLOGD("Going to copy bugreport file (%s) to %d\n", ds.path_.c_str(), out_fd);
+
+ // Obtain a handle to the source file.
+ android::base::unique_fd in_fd(OpenForRead(input_file));
+ if (out_fd != -1 && in_fd.get() != -1) {
+ if (CopyFile(in_fd.get(), out_fd)) {
+ return true;
+ }
+ MYLOGE("Failed to copy zip file: %s\n", strerror(errno));
+ }
+ return false;
+}
+
+static bool CopyFileToFile(const std::string& input_file, const std::string& output_file) {
+ if (input_file == output_file) {
+ MYLOGD("Skipping copying bugreport file since the destination is the same (%s)\n",
+ output_file.c_str());
+ return false;
+ }
+
+ MYLOGD("Going to copy bugreport file (%s) to %s\n", input_file.c_str(), output_file.c_str());
+ android::base::unique_fd out_fd(OpenForWrite(output_file));
+ return CopyFileToFd(input_file, out_fd.get());
+}
+
+} // namespace
+} // namespace os
+} // namespace android
+
static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
const CommandOptions& options = CommandOptions::DEFAULT) {
return ds.RunCommand(title, fullCommand, options);
@@ -137,8 +201,6 @@
// Relative directory (inside the zip) for all files copied as-is into the bugreport.
static const std::string ZIP_ROOT_DIR = "FS";
-// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
-static const std::string kDumpstateBoardPath = "/bugreports/";
static const std::string kProtoPath = "proto/";
static const std::string kProtoExt = ".proto";
static const std::string kDumpstateBoardFiles[] = {
@@ -1145,7 +1207,7 @@
return !isalnum(c) &&
std::string("@-_:.").find(c) == std::string::npos;
}, '_');
- const std::string path = kDumpstateBoardPath + "lshal_debug_" + cleanName;
+ const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
{
auto fd = android::base::unique_fd(
@@ -1529,7 +1591,8 @@
std::vector<std::string> paths;
std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
for (int i = 0; i < NUM_OF_DUMPS; i++) {
- paths.emplace_back(kDumpstateBoardPath + kDumpstateBoardFiles[i]);
+ paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
+ kDumpstateBoardFiles[i].c_str()));
remover.emplace_back(android::base::make_scope_guard(std::bind(
[](std::string path) {
if (remove(path.c_str()) != 0 && errno != ENOENT) {
@@ -1687,7 +1750,8 @@
MYLOGE("Failed to add dumpstate log to .zip file\n");
return false;
}
- // ... and re-opens it for further logging.
+ // TODO: Should truncate the existing file.
+ // ... and re-open it for further logging.
redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
fprintf(stderr, "\n");
@@ -1770,17 +1834,30 @@
// clang-format on
}
+static void MaybeResolveSymlink(std::string* path) {
+ std::string resolved_path;
+ if (android::base::Readlink(*path, &resolved_path)) {
+ *path = resolved_path;
+ }
+}
+
/*
* Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
* if we are writing zip files and adds the version file.
*/
static void PrepareToWriteToFile() {
- ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
+ MaybeResolveSymlink(&ds.bugreport_internal_dir_);
+
+ std::string base_name_part1 = "bugreport";
+ if (!ds.options_->use_outfile.empty()) {
+ ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
+ base_name_part1 = basename(ds.options_->use_outfile.c_str());
+ }
+
std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
ds.base_name_ =
- android::base::StringPrintf("%s-%s-%s", basename(ds.options_->use_outfile.c_str()),
- device_name.c_str(), build_id.c_str());
+ StringPrintf("%s-%s-%s", base_name_part1.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_));
@@ -1801,15 +1878,18 @@
ds.tmp_path_ = ds.GetPath(".tmp");
ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
+ std::string destination = ds.options_->fd != -1 ? StringPrintf("[fd:%d]", ds.options_->fd)
+ : ds.bugreport_dir_.c_str();
MYLOGD(
"Bugreport dir: %s\n"
+ "Internal Bugreport dir: %s\n"
"Base name: %s\n"
"Suffix: %s\n"
"Log path: %s\n"
"Temporary path: %s\n"
"Screenshot path: %s\n",
- 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());
+ destination.c_str(), ds.bugreport_internal_dir_.c_str(), ds.base_name_.c_str(),
+ ds.name_.c_str(), ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
if (ds.options_->do_zip_file) {
ds.path_ = ds.GetPath(".zip");
@@ -1875,6 +1955,19 @@
ds.path_ = new_path;
}
}
+ // The zip file lives in an internal directory. Copy it over to output.
+ bool copy_succeeded = false;
+ if (ds.options_->fd != -1) {
+ copy_succeeded = android::os::CopyFileToFd(ds.path_, ds.options_->fd);
+ } else {
+ ds.final_path_ = ds.GetPath(ds.bugreport_dir_, ".zip");
+ copy_succeeded = android::os::CopyFileToFile(ds.path_, ds.final_path_);
+ }
+ if (copy_succeeded) {
+ if (remove(ds.path_.c_str())) {
+ MYLOGE("remove(%s): %s", ds.path_.c_str(), strerror(errno));
+ }
+ }
}
}
if (do_text_file) {
@@ -1899,8 +1992,9 @@
/* Broadcasts that we are done with the bugreport */
static void SendBugreportFinishedBroadcast() {
- if (!ds.path_.empty()) {
- MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
+ // TODO(b/111441001): use callback instead of broadcast.
+ if (!ds.final_path_.empty()) {
+ MYLOGI("Final bugreport path: %s\n", ds.final_path_.c_str());
// clang-format off
std::vector<std::string> am_args = {
@@ -1908,7 +2002,7 @@
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
"--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
- "--es", "android.intent.extra.BUGREPORT", ds.path_,
+ "--es", "android.intent.extra.BUGREPORT", ds.final_path_,
"--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
};
// clang-format on
@@ -1930,7 +2024,7 @@
if (ds.options_->is_remote_mode) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
- am_args.push_back(SHA256_file_hash(ds.path_));
+ am_args.push_back(SHA256_file_hash(ds.final_path_));
SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
} else {
SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
@@ -2060,6 +2154,7 @@
MYLOGI("telephony_only: %d\n", options.telephony_only);
MYLOGI("wifi_only: %d\n", options.wifi_only);
MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
+ MYLOGI("fd: %d\n", options.fd);
MYLOGI("use_outfile: %s\n", options.use_outfile.c_str());
MYLOGI("extra_options: %s\n", options.extra_options.c_str());
MYLOGI("args: %s\n", options.args.c_str());
@@ -2125,8 +2220,13 @@
}
bool Dumpstate::DumpOptions::ValidateOptions() const {
- if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast)
- && use_outfile.empty()) {
+ if (fd != -1 && !do_zip_file) {
+ return false;
+ }
+
+ bool has_out_file_options = !use_outfile.empty() || fd != -1;
+ if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) &&
+ !has_out_file_options) {
return false;
}
@@ -2148,10 +2248,31 @@
options_ = std::move(options);
}
+/*
+ * Dumps relevant information to a bugreport based on the given options.
+ *
+ * The bugreport can be dumped to a file or streamed to a socket.
+ *
+ * How dumping to file works:
+ * stdout is redirected to a temporary file. This will later become the main bugreport entry.
+ * stderr is redirected a log file.
+ *
+ * The temporary bugreport is then populated via printfs, dumping contents of files and
+ * output of commands to stdout.
+ *
+ * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
+ * text file.
+ *
+ * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
+ * gets added to the archive.
+ *
+ * Bugreports are first generated in a local directory and later copied to the caller's fd or
+ * directory.
+ */
Dumpstate::RunStatus Dumpstate::Run() {
+ LogDumpOptions(*options_);
if (!options_->ValidateOptions()) {
MYLOGE("Invalid options specified\n");
- LogDumpOptions(*options_);
return RunStatus::INVALID_INPUT;
}
/* set as high priority, and protect from OOM killer */
@@ -2191,9 +2312,9 @@
// 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()))
- : "";
+ is_redirecting
+ ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
+ : "";
progress_.reset(new Progress(stats_path));
/* gets the sequential id */
@@ -2289,13 +2410,18 @@
int dup_stdout_fd;
int dup_stderr_fd;
if (is_redirecting) {
+ // Redirect stderr to log_path_ for debugging.
TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
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));
}
+
+ // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
+ // moved into zip file later, if zipping.
TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
+ // TODO: why not write to a file instead of stdout to overcome this problem?
/* TODO: rather than generating a text file now and zipping it later,
it would be more efficient to redirect stdout to the zip entry
directly, but the libziparchive doesn't support that option yet. */
@@ -2370,7 +2496,7 @@
return RunStatus::OK;
}
-/* Main entry point for dumpstate. */
+/* Main entry point for dumpstate binary. */
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);
@@ -2382,7 +2508,7 @@
switch (status) {
case Dumpstate::RunStatus::OK:
return 0;
- break;
+ // TODO(b/111441001): Exit directly in the following cases.
case Dumpstate::RunStatus::HELP:
ShowUsageAndExit(0 /* exit code */);
break;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 35cbdb1..94e3191 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -142,7 +142,7 @@
float growth_factor_;
int32_t n_runs_;
int32_t average_max_;
- const std::string& path_;
+ std::string path_;
};
/*
@@ -164,6 +164,11 @@
static std::string VERSION_DEFAULT = "default";
/*
+ * Directory used by Dumpstate binary to keep its local files.
+ */
+static const std::string DUMPSTATE_DIRECTORY = "/bugreports";
+
+/*
* Structure that contains the information of an open dump file.
*/
struct DumpData {
@@ -300,7 +305,11 @@
*/
bool FinishZipFile();
- /* Gets the path of a bugreport file with the given suffix. */
+ /* Constructs a full path inside directory with file name formatted using the given suffix. */
+ std::string GetPath(const std::string& directory, const std::string& suffix) const;
+
+ /* Constructs a full path inside bugreport_internal_dir_ with file name formatted using the
+ * given suffix. */
std::string GetPath(const std::string& suffix) const;
/* Returns true if the current version supports priority dump feature. */
@@ -314,7 +323,6 @@
/* Sets runtime options. */
void SetOptions(std::unique_ptr<DumpOptions> options);
- // TODO: add other options from DumpState.
/*
* Structure to hold options that determine the behavior of dumpstate.
*/
@@ -333,6 +341,10 @@
bool wifi_only = false;
// Whether progress updates should be published.
bool do_progress_updates = false;
+ // File descriptor to output zip file. -1 indicates not set. Takes precedence over
+ // use_outfile.
+ int fd = -1;
+ // Partial path to output file.
std::string use_outfile;
// TODO: rename to MODE.
// Extra options passed as system property.
@@ -381,12 +393,6 @@
// Bugreport format version;
std::string version_ = VERSION_CURRENT;
- // Full path of the directory where the bugreport files will be written.
- std::string bugreport_dir_;
-
- // Full path of the temporary file containing the screenshot (when requested).
- std::string screenshot_path_;
-
time_t now_;
// Base name (without suffix or extensions) of the bugreport files, typically
@@ -397,15 +403,30 @@
// `-d`), but it could be changed by the user..
std::string name_;
- // Full path of the temporary file containing the bugreport.
+ std::string bugreport_internal_dir_ = DUMPSTATE_DIRECTORY;
+
+ // Full path of the temporary file containing the bugreport, inside bugreport_internal_dir_.
+ // At the very end this file is pulled into the zip file.
std::string tmp_path_;
- // Full path of the file containing the dumpstate logs.
+ // Full path of the file containing the dumpstate logs, inside bugreport_internal_dir_.
+ // This is useful for debugging.
std::string log_path_;
- // Pointer to the actual path, be it zip or text.
+ // Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_.
std::string path_;
+ // TODO: If temporary this should be removed at the end.
+ // Full path of the temporary file containing the screenshot (when requested).
+ std::string screenshot_path_;
+
+ // TODO(b/111441001): remove when obsolete.
+ // Full path of the final zip file inside the caller-specified directory, if available.
+ std::string final_path_;
+
+ // The caller-specified directory, if available.
+ std::string bugreport_dir_;
+
// Pointer to the zipped file.
std::unique_ptr<FILE, int (*)(FILE*)> zip_file{nullptr, fclose};
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 6cbb691..d97ffbf 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -229,7 +229,11 @@
}
std::string Dumpstate::GetPath(const std::string& suffix) const {
- return android::base::StringPrintf("%s/%s-%s%s", bugreport_dir_.c_str(), base_name_.c_str(),
+ return GetPath(bugreport_internal_dir_, suffix);
+}
+
+std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
+ return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
name_.c_str(), suffix.c_str());
}
diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h
index dc25ded..fe2e2ac 100644
--- a/headers/media_plugin/media/openmax/OMX_AsString.h
+++ b/headers/media_plugin/media/openmax/OMX_AsString.h
@@ -189,6 +189,7 @@
switch (i) {
case OMX_AUDIO_CodingAndroidAC3: return "AndroidAC3";
case OMX_AUDIO_CodingAndroidOPUS: return "AndroidOPUS";
+ case OMX_AUDIO_CodingAndroidAC4: return "AndroidAC4";
default: return asString((OMX_AUDIO_CODINGTYPE)i, def);
}
}
@@ -536,6 +537,7 @@
case OMX_IndexParamAudioAndroidOpus: return "ParamAudioAndroidOpus";
case OMX_IndexParamAudioAndroidAacPresentation: return "ParamAudioAndroidAacPresentation";
case OMX_IndexParamAudioAndroidEac3: return "ParamAudioAndroidEac3";
+ case OMX_IndexParamAudioAndroidAc4: return "ParamAudioAndroidAc4";
case OMX_IndexParamAudioProfileQuerySupported: return "ParamAudioProfileQuerySupported";
// case OMX_IndexParamNalStreamFormatSupported: return "ParamNalStreamFormatSupported";
// case OMX_IndexParamNalStreamFormat: return "ParamNalStreamFormat";
diff --git a/headers/media_plugin/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h
index 8409553..1ea740f 100644
--- a/headers/media_plugin/media/openmax/OMX_AudioExt.h
+++ b/headers/media_plugin/media/openmax/OMX_AudioExt.h
@@ -48,6 +48,7 @@
OMX_AUDIO_CodingAndroidAC3, /**< AC3 encoded data */
OMX_AUDIO_CodingAndroidOPUS, /**< OPUS encoded data */
OMX_AUDIO_CodingAndroidEAC3, /**< EAC3 encoded data */
+ OMX_AUDIO_CodingAndroidAC4, /**< AC4 encoded data */
} OMX_AUDIO_CODINGEXTTYPE;
typedef struct OMX_AUDIO_PARAM_ANDROID_AC3TYPE {
@@ -68,6 +69,15 @@
variable or unknown sampling rate. */
} OMX_AUDIO_PARAM_ANDROID_EAC3TYPE;
+typedef struct OMX_AUDIO_PARAM_ANDROID_AC4TYPE {
+ OMX_U32 nSize; /**< size of the structure in bytes */
+ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+ OMX_U32 nPortIndex; /**< port that this structure applies to */
+ OMX_U32 nChannels; /**< Number of channels */
+ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for
+ variable or unknown sampling rate. */
+} OMX_AUDIO_PARAM_ANDROID_AC4TYPE;
+
typedef struct OMX_AUDIO_PARAM_ANDROID_OPUSTYPE {
OMX_U32 nSize; /**< size of the structure in bytes */
OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 716d959..9fc3ef3 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -64,6 +64,7 @@
OMX_IndexParamAudioAndroidEac3, /**< reference: OMX_AUDIO_PARAM_ANDROID_EAC3TYPE */
OMX_IndexParamAudioProfileQuerySupported, /**< reference: OMX_AUDIO_PARAM_ANDROID_PROFILETYPE */
OMX_IndexParamAudioAndroidAacDrcPresentation, /**< reference: OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE */
+ OMX_IndexParamAudioAndroidAc4, /**< reference: OMX_AUDIO_PARAM_ANDROID_AC4TYPE */
OMX_IndexExtAudioEndUnused,
/* Image parameters and configurations */
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index c2a6764..dfdda0c 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -135,8 +135,8 @@
}
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
- bool developerOptIn, const int rulesFd, const long rulesOffset,
- const long rulesLength) {
+ const std::string developerOptIn, const int rulesFd,
+ const long rulesOffset, const long rulesLength) {
if (!mAnglePath.empty()) {
ALOGV("ignoring attempt to change ANGLE path from '%s' to '%s'", mAnglePath.c_str(),
path.c_str());
@@ -153,7 +153,13 @@
mAngleAppName = appName;
}
- mAngleDeveloperOptIn = developerOptIn;
+ if (!mAngleDeveloperOptIn.empty()) {
+ ALOGV("ignoring attempt to change ANGLE application opt-in from '%s' to '%s'",
+ mAngleDeveloperOptIn.c_str(), developerOptIn.c_str());
+ } else {
+ ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
+ mAngleDeveloperOptIn = developerOptIn;
+ }
ALOGV("setting ANGLE rules file descriptor to '%i'", rulesFd);
mAngleRulesFd = rulesFd;
@@ -182,8 +188,8 @@
return mAngleAppName.c_str();
}
-bool GraphicsEnv::getAngleDeveloperOptIn() {
- return mAngleDeveloperOptIn;
+const char* GraphicsEnv::getAngleDeveloperOptIn() {
+ return mAngleDeveloperOptIn.c_str();
}
int GraphicsEnv::getAngleRulesFd() {
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 20e4d66..4ec53f1 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -44,12 +44,12 @@
// (libraries must be stored uncompressed and page aligned); such elements
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
- void setAngleInfo(const std::string path, const std::string appName, bool devOptIn,
+ void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn,
const int rulesFd, const long rulesOffset, const long rulesLength);
android_namespace_t* getAngleNamespace();
const char* getAngleAppName();
const char* getAngleAppPref();
- bool getAngleDeveloperOptIn();
+ const char* getAngleDeveloperOptIn();
int getAngleRulesFd();
long getAngleRulesOffset();
long getAngleRulesLength();
@@ -69,7 +69,7 @@
std::string mDriverPath;
std::string mAnglePath;
std::string mAngleAppName;
- bool mAngleDeveloperOptIn;
+ std::string mAngleDeveloperOptIn;
int mAngleRulesFd;
long mAngleRulesOffset;
long mAngleRulesLength;
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index e747ee1..3816c1b 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -61,6 +61,16 @@
// to use Binder.
static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
+using dvr::BufferHubDefs::AnyClientAcquired;
+using dvr::BufferHubDefs::AnyClientGained;
+using dvr::BufferHubDefs::AnyClientPosted;
+using dvr::BufferHubDefs::IsClientAcquired;
+using dvr::BufferHubDefs::IsClientGained;
+using dvr::BufferHubDefs::IsClientPosted;
+using dvr::BufferHubDefs::IsClientReleased;
+using dvr::BufferHubDefs::kHighBitsMask;
+using dvr::BufferHubDefs::kMetadataHeaderSize;
+
} // namespace
BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
@@ -71,7 +81,7 @@
BufferHubClient::~BufferHubClient() {}
bool BufferHubClient::IsValid() const {
- return IsConnected() && GetChannelHandle().valid();
+ return IsConnected() && GetChannelHandle().valid();
}
LocalChannelHandle BufferHubClient::TakeChannelHandle() {
@@ -151,11 +161,17 @@
}
size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
- if (metadataSize < dvr::BufferHubDefs::kMetadataHeaderSize) {
+ if (metadataSize < kMetadataHeaderSize) {
ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata too small: %zu", metadataSize);
return -EINVAL;
}
+ // Populate shortcuts to the atomics in metadata.
+ auto metadata_header = mMetadata.metadata_header();
+ buffer_state_ = &metadata_header->buffer_state;
+ fence_state_ = &metadata_header->fence_state;
+ active_clients_bit_mask_ = &metadata_header->active_clients_bit_mask;
+
// Import the buffer: We only need to hold on the native_handle_t here so that
// GraphicBuffer instance can be created in future.
mBufferHandle = bufferTraits.take_buffer_handle();
@@ -176,7 +192,93 @@
// TODO(b/112012161) Set up shared fences.
ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
- mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire));
+ buffer_state_->load(std::memory_order_acquire));
+ return 0;
+}
+
+int BufferHubBuffer::Gain() {
+ uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+ if (IsClientGained(current_buffer_state, mClientStateMask)) {
+ ALOGV("%s: Buffer is already gained by this client %" PRIx64 ".", __FUNCTION__,
+ mClientStateMask);
+ return 0;
+ }
+ do {
+ if (AnyClientGained(current_buffer_state & (~mClientStateMask)) ||
+ AnyClientAcquired(current_buffer_state)) {
+ ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+ __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+ return -EBUSY;
+ }
+ // Change the buffer state to gained state, whose value happens to be the same as
+ // mClientStateMask.
+ } while (!buffer_state_->compare_exchange_weak(current_buffer_state, mClientStateMask,
+ std::memory_order_acq_rel,
+ std::memory_order_acquire));
+ // TODO(b/119837586): Update fence state and return GPU fence.
+ return 0;
+}
+
+int BufferHubBuffer::Post() {
+ uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+ uint64_t current_active_clients_bit_mask = 0ULL;
+ uint64_t updated_buffer_state = 0ULL;
+ do {
+ if (!IsClientGained(current_buffer_state, mClientStateMask)) {
+ ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
+ "mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+ __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+ return -EBUSY;
+ }
+ // Set the producer client buffer state to released, other clients' buffer state to posted.
+ current_active_clients_bit_mask = active_clients_bit_mask_->load(std::memory_order_acquire);
+ updated_buffer_state =
+ current_active_clients_bit_mask & (~mClientStateMask) & kHighBitsMask;
+ } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
+ std::memory_order_acq_rel,
+ std::memory_order_acquire));
+ // TODO(b/119837586): Update fence state and return GPU fence if needed.
+ return 0;
+}
+
+int BufferHubBuffer::Acquire() {
+ uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+ if (IsClientAcquired(current_buffer_state, mClientStateMask)) {
+ ALOGV("%s: Buffer is already acquired by this client %" PRIx64 ".", __FUNCTION__,
+ mClientStateMask);
+ return 0;
+ }
+ uint64_t updated_buffer_state = 0ULL;
+ do {
+ if (!IsClientPosted(current_buffer_state, mClientStateMask)) {
+ ALOGE("%s: Cannot acquire a buffer that is not in posted state. buffer_id=%d "
+ "mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+ __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+ return -EBUSY;
+ }
+ // Change the buffer state for this consumer from posted to acquired.
+ updated_buffer_state = current_buffer_state ^ mClientStateMask;
+ } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
+ std::memory_order_acq_rel,
+ std::memory_order_acquire));
+ // TODO(b/119837586): Update fence state and return GPU fence.
+ return 0;
+}
+
+int BufferHubBuffer::Release() {
+ uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+ if (IsClientReleased(current_buffer_state, mClientStateMask)) {
+ ALOGV("%s: Buffer is already released by this client %" PRIx64 ".", __FUNCTION__,
+ mClientStateMask);
+ return 0;
+ }
+ uint64_t updated_buffer_state = 0ULL;
+ do {
+ updated_buffer_state = current_buffer_state & (~mClientStateMask);
+ } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
+ std::memory_order_acq_rel,
+ std::memory_order_acquire));
+ // TODO(b/119837586): Update fence state and return GPU fence if needed.
return 0;
}
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 37cf617..20f27c5 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -42,9 +42,6 @@
for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) {
bits = bits | bit;
}
- // TODO(b/72323293, b/72703005): Remove these additional bits
- bits = bits | (1 << 10) | (1 << 13);
-
return bits;
}();
return valid10UsageBits;
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index a2f1783..f56e6b9 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -101,6 +101,9 @@
if (layerCount < 1)
layerCount = 1;
+ // TODO(b/72323293, b/72703005): Remove these invalid bits from callers
+ usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
+
Gralloc2::IMapper::BufferDescriptorInfo info = {};
info.width = width;
info.height = height;
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 6850b43..03d10e7 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -103,6 +103,27 @@
// to read from and/or write into.
bool IsValid() const { return mBufferHandle.IsValid(); }
+ // Gains the buffer for exclusive write permission. Read permission is implied once a buffer is
+ // gained.
+ // The buffer can be gained as long as there is no other client in acquired or gained state.
+ int Gain();
+
+ // Posts the gained buffer for other buffer clients to use the buffer.
+ // The buffer can be posted iff the buffer state for this client is gained.
+ // After posting the buffer, this client is put to released state and does not have access to
+ // the buffer for this cycle of the usage of the buffer.
+ int Post();
+
+ // Acquires the buffer for shared read permission.
+ // The buffer can be acquired iff the buffer state for this client is posted.
+ int Acquire();
+
+ // Releases the buffer.
+ // The buffer can be released from any buffer state.
+ // After releasing the buffer, this client no longer have any permissions to the buffer for the
+ // current cycle of the usage of the buffer.
+ int Release();
+
// Returns the event mask for all the events that are pending on this buffer (see sys/poll.h for
// all possible bits).
pdx::Status<int> GetEventMask(int events) {
@@ -130,6 +151,9 @@
// Global id for the buffer that is consistent across processes.
int mId = -1;
+
+ // Client state mask of this BufferHubBuffer object. It is unique amoung all
+ // clients/users of the buffer.
uint64_t mClientStateMask = 0;
// Stores ground truth of the buffer.
@@ -141,6 +165,10 @@
// An ashmem-based metadata object. The same shared memory are mapped to the
// bufferhubd daemon and all buffer clients.
BufferHubMetadata mMetadata;
+ // Shortcuts to the atomics inside the header of mMetadata.
+ std::atomic<uint64_t>* buffer_state_{nullptr};
+ std::atomic<uint64_t>* fence_state_{nullptr};
+ std::atomic<uint64_t>* active_clients_bit_mask_{nullptr};
// PDX backend.
BufferHubClient mClient;
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index fcc6d37..18bbb3e 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -74,7 +74,12 @@
cc_test {
name: "BufferHubMetadata_test",
header_libs: ["libbufferhub_headers", "libdvr_headers"],
- shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+ shared_libs: [
+ "libbase",
+ "libpdx_default_transport",
+ "libui",
+ "libutils",
+ ],
srcs: ["BufferHubMetadata_test.cpp"],
cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 6c7d06b..e33acf6 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -36,7 +36,14 @@
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
+using dvr::BufferHubDefs::AnyClientAcquired;
+using dvr::BufferHubDefs::AnyClientGained;
+using dvr::BufferHubDefs::AnyClientPosted;
using dvr::BufferHubDefs::IsBufferReleased;
+using dvr::BufferHubDefs::IsClientAcquired;
+using dvr::BufferHubDefs::IsClientGained;
+using dvr::BufferHubDefs::IsClientPosted;
+using dvr::BufferHubDefs::IsClientReleased;
using dvr::BufferHubDefs::kFirstClientBitMask;
using dvr::BufferHubDefs::kMetadataHeaderSize;
using frameworks::bufferhub::V1_0::BufferHubStatus;
@@ -48,9 +55,40 @@
using pdx::LocalChannelHandle;
class BufferHubBufferTest : public ::testing::Test {
+protected:
void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
};
+class BufferHubBufferStateTransitionTest : public BufferHubBufferTest {
+protected:
+ void SetUp() override {
+ BufferHubBufferTest::SetUp();
+ CreateTwoClientsOfABuffer();
+ }
+
+ std::unique_ptr<BufferHubBuffer> b1;
+ uint64_t b1ClientMask = 0ULL;
+ std::unique_ptr<BufferHubBuffer> b2;
+ uint64_t b2ClientMask = 0ULL;
+
+private:
+ // Creates b1 and b2 as the clients of the same buffer for testing.
+ void CreateTwoClientsOfABuffer();
+};
+
+void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() {
+ b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ b1ClientMask = b1->client_state_mask();
+ ASSERT_NE(b1ClientMask, 0ULL);
+ auto statusOrHandle = b1->Duplicate();
+ ASSERT_TRUE(statusOrHandle);
+ LocalChannelHandle h2 = statusOrHandle.take();
+ b2 = BufferHubBuffer::Import(std::move(h2));
+ b2ClientMask = b2->client_state_mask();
+ ASSERT_NE(b2ClientMask, 0ULL);
+ ASSERT_NE(b2ClientMask, b1ClientMask);
+}
+
TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
// Buffer Creation will fail: BLOB format requires height to be 1.
auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
@@ -315,5 +353,180 @@
EXPECT_EQ(nullptr, client2.get());
}
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
+ ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+
+ // Successful gaining the buffer should change the buffer state bit of b1 to
+ // gained state, other client state bits to released state.
+ EXPECT_EQ(b1->Gain(), 0);
+ EXPECT_TRUE(IsClientGained(b1->buffer_state(), b1ClientMask));
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromGainedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ auto current_buffer_state = b1->buffer_state();
+ ASSERT_TRUE(IsClientGained(current_buffer_state, b1ClientMask));
+
+ // Gaining from gained state by the same client should not return error.
+ EXPECT_EQ(b1->Gain(), 0);
+
+ // Gaining from gained state by another client should return error.
+ EXPECT_EQ(b2->Gain(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromAcquiredState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_EQ(b2->Acquire(), 0);
+ ASSERT_TRUE(AnyClientAcquired(b1->buffer_state()));
+
+ // Gaining from acquired state should fail.
+ EXPECT_EQ(b1->Gain(), -EBUSY);
+ EXPECT_EQ(b2->Gain(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromOtherClientInPostedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_TRUE(AnyClientPosted(b1->buffer_state()));
+
+ // Gaining a buffer who has other posted client should succeed.
+ EXPECT_EQ(b1->Gain(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromSelfInPostedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_TRUE(AnyClientPosted(b1->buffer_state()));
+
+ // A posted client should be able to gain the buffer when there is no other clients in
+ // acquired state.
+ EXPECT_EQ(b2->Gain(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromOtherInGainedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_TRUE(IsClientGained(b1->buffer_state(), b1ClientMask));
+
+ EXPECT_EQ(b2->Post(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromSelfInGainedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_TRUE(IsClientGained(b1->buffer_state(), b1ClientMask));
+
+ EXPECT_EQ(b1->Post(), 0);
+ auto current_buffer_state = b1->buffer_state();
+ EXPECT_TRUE(IsClientReleased(current_buffer_state, b1ClientMask));
+ EXPECT_TRUE(IsClientPosted(current_buffer_state, b2ClientMask));
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromPostedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_TRUE(AnyClientPosted(b1->buffer_state()));
+
+ // Post from posted state should fail.
+ EXPECT_EQ(b1->Post(), -EBUSY);
+ EXPECT_EQ(b2->Post(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromAcquiredState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_EQ(b2->Acquire(), 0);
+ ASSERT_TRUE(AnyClientAcquired(b1->buffer_state()));
+
+ // Posting from acquired state should fail.
+ EXPECT_EQ(b1->Post(), -EBUSY);
+ EXPECT_EQ(b2->Post(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromReleasedState) {
+ ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+
+ // Posting from released state should fail.
+ EXPECT_EQ(b1->Post(), -EBUSY);
+ EXPECT_EQ(b2->Post(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromSelfInPostedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_TRUE(IsClientPosted(b1->buffer_state(), b2ClientMask));
+
+ // Acquire from posted state should pass.
+ EXPECT_EQ(b2->Acquire(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromOtherInPostedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_TRUE(IsClientPosted(b1->buffer_state(), b2ClientMask));
+
+ // Acquire from released state should fail, although there are other clients
+ // in posted state.
+ EXPECT_EQ(b1->Acquire(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromSelfInAcquiredState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_EQ(b2->Acquire(), 0);
+ auto current_buffer_state = b1->buffer_state();
+ ASSERT_TRUE(IsClientAcquired(current_buffer_state, b2ClientMask));
+
+ // Acquiring from acquired state by the same client should not error out.
+ EXPECT_EQ(b2->Acquire(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromReleasedState) {
+ ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+
+ // Acquiring form released state should fail.
+ EXPECT_EQ(b1->Acquire(), -EBUSY);
+ EXPECT_EQ(b2->Acquire(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromGainedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_TRUE(AnyClientGained(b1->buffer_state()));
+
+ // Acquiring from gained state should fail.
+ EXPECT_EQ(b1->Acquire(), -EBUSY);
+ EXPECT_EQ(b2->Acquire(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInReleasedState) {
+ ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+
+ EXPECT_EQ(b1->Release(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInGainedState) {
+ ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_TRUE(AnyClientGained(b1->buffer_state()));
+
+ EXPECT_EQ(b1->Release(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInPostedState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_TRUE(AnyClientPosted(b1->buffer_state()));
+
+ EXPECT_EQ(b2->Release(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInAcquiredState) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_EQ(b2->Acquire(), 0);
+ ASSERT_TRUE(AnyClientAcquired(b1->buffer_state()));
+
+ EXPECT_EQ(b2->Release(), 0);
+}
+
} // namespace
} // namespace android
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index de03fad..cd92b62 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -224,15 +224,17 @@
uint64_t current_fence_state = fence_state_->load(std::memory_order_acquire);
uint64_t current_active_clients_bit_mask =
active_clients_bit_mask_->load(std::memory_order_acquire);
- // If there is an release fence from consumer, we need to return it.
+ // If there are release fence(s) from consumer(s), we need to return it to the
+ // consumer(s).
// TODO(b/112007999) add an atomic variable in metadata header in shared
// memory to indicate which client is the last producer of the buffer.
// Currently, assume the first client is the only producer to the buffer.
if (current_fence_state & current_active_clients_bit_mask &
(~BufferHubDefs::kFirstClientBitMask)) {
*out_fence = shared_release_fence_.Duplicate();
- out_meta->release_fence_mask =
- current_fence_state & current_active_clients_bit_mask;
+ out_meta->release_fence_mask = current_fence_state &
+ current_active_clients_bit_mask &
+ (~BufferHubDefs::kFirstClientBitMask);
}
return 0;
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 6edadcd..50e30c2 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -41,6 +41,12 @@
extern "C" {
android_namespace_t* android_get_exported_namespace(const char*);
+ typedef enum ANGLEPreference {
+ ANGLE_PREFER_DEFAULT = 0,
+ ANGLE_PREFER_NATIVE = 1,
+ ANGLE_PREFER_ANGLE = 2,
+ } ANGLEPreference;
+
// TODO(ianelliott@): Get the following from an ANGLE header:
// Version-1 API:
typedef bool (*fpANGLEGetUtilityAPI)(unsigned int* versionToUse);
@@ -524,6 +530,17 @@
return nullptr;
}
+static ANGLEPreference getAngleDevOption(const char* devOption) {
+ if (devOption == nullptr)
+ return ANGLE_PREFER_DEFAULT;
+
+ if (strcmp(devOption, "angle") == 0) {
+ return ANGLE_PREFER_ANGLE;
+ } else if (strcmp(devOption, "native") == 0) {
+ return ANGLE_PREFER_NATIVE;
+ }
+ return ANGLE_PREFER_DEFAULT;
+}
static bool check_angle_rules(void* so, const char* app_name) {
bool use_angle = false;
@@ -646,15 +663,19 @@
char prop[PROPERTY_VALUE_MAX];
const char* app_name = android::GraphicsEnv::getInstance().getAngleAppName();
- bool developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
+ const char* developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
// Determine whether or not to use ANGLE:
- bool use_angle = developer_opt_in;
+ ANGLEPreference developer_option = getAngleDevOption(developer_opt_in);
+ bool use_angle = (developer_option == ANGLE_PREFER_ANGLE);
if (use_angle) {
ALOGV("User set \"Developer Options\" to force the use of ANGLE");
} else if (cnx->angleDecided) {
use_angle = cnx->useAngle;
+ } else if (developer_option == ANGLE_PREFER_NATIVE) {
+ ALOGV("User set \"Developer Options\" to force the use of Native");
+ use_angle = false;
} 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:
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 4433af0..c100db7 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -378,7 +378,8 @@
if (wideColorBoardConfig && hasColorSpaceSupport) {
mExtensionString.append(
"EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
- "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
+ "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 "
+ "EGL_EXT_gl_colorspace_display_p3_passthrough ");
}
bool hasHdrBoardConfig =
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 31e4e2d..79166a7 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -466,6 +466,8 @@
return HAL_DATASPACE_DISPLAY_P3;
} else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) {
return HAL_DATASPACE_DISPLAY_P3_LINEAR;
+ } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT) {
+ return HAL_DATASPACE_DISPLAY_P3;
} else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) {
return HAL_DATASPACE_V0_SCRGB;
} else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
@@ -510,6 +512,9 @@
if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3_linear")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
}
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3_passthrough")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT);
+ }
return colorSpaces;
}
@@ -527,6 +532,7 @@
case EGL_GL_COLORSPACE_LINEAR_KHR:
case EGL_GL_COLORSPACE_SRGB_KHR:
case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
+ case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
case EGL_GL_COLORSPACE_SCRGB_EXT:
case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT:
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 459b135..cca91c3 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -217,6 +217,7 @@
// Test that display-p3 extensions exist
ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3"));
ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear"));
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_passthrough"));
// Use 8-bit to keep forcus on Display-P3 aspect
EGLint attrs[] = {
@@ -289,6 +290,59 @@
EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
}
+TEST_F(EGLTest, EGLDisplayP3Passthrough) {
+ EGLConfig config;
+ EGLBoolean success;
+
+ if (!hasWideColorDisplay) {
+ // skip this test if device does not have wide-color display
+ std::cerr << "[ ] Device does not support wide-color, test skipped" << std::endl;
+ return;
+ }
+
+ // Test that display-p3 extensions exist
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3"));
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear"));
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_passthrough"));
+
+ 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_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT,
+ EGL_NONE, 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);
+
+ EGLint value;
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT, value);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
TEST_F(EGLTest, EGLDisplayP31010102) {
EGLint numConfigs;
EGLConfig config;
@@ -303,6 +357,7 @@
// Test that display-p3 extensions exist
ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3"));
ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear"));
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_passthrough"));
// Use 8-bit to keep forcus on Display-P3 aspect
EGLint attrs[] = {
diff --git a/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h
index eb9571d..cfa378f 100644
--- a/opengl/tests/lib/include/EGLUtils.h
+++ b/opengl/tests/lib/include/EGLUtils.h
@@ -280,6 +280,8 @@
return String8("EGL_GL_COLORSPACE_SRGB_KHR");
case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
return String8("EGL_GL_COLORSPACE_DISPLAY_P3_EXT");
+ case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
+ return String8("EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT");
case EGL_GL_COLORSPACE_LINEAR_KHR:
return String8("EGL_GL_COLORSPACE_LINEAR_KHR");
default:
diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml
index 26771e1..8d661ae 100644
--- a/opengl/tools/glgen2/registry/egl.xml
+++ b/opengl/tools/glgen2/registry/egl.xml
@@ -894,6 +894,11 @@
<unused start="0x3481" end="0x348F"/>
</enums>
+ <enums namespace="EGL" start="0x3490" end="0x349F" vendor="EXT" comment="Reserved for Courtney Goeltzenleuchter - Android (gitlab EGL bug 69)">
+ <enum value="0x3490" name="EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT"/>
+ <unused start="0x3491" end="0x349F"/>
+ </enums>
+
<!-- Please remember that new enumerant allocations must be obtained by
request to the Khronos API registrar (see comments at the top of this
file) File requests in the Khronos Bugzilla, EGL project, Registry
@@ -903,8 +908,8 @@
<!-- Reservable for future use. To generate a new range, allocate multiples
of 16 starting at the lowest available point in this block. -->
- <enums namespace="EGL" start="0x3490" end="0x3FFF" vendor="KHR" comment="Reserved for future use">
- <unused start="0x3490" end="0x3FFF"/>
+ <enums namespace="EGL" start="0x34A0" end="0x3FFF" vendor="KHR" comment="Reserved for future use">
+ <unused start="0x34A0" end="0x3FFF"/>
</enums>
<enums namespace="EGL" start="0x8F70" end="0x8F7F" vendor="HI" comment="For Mark Callow, Khronos bug 4055. Shared with GL.">
@@ -2250,6 +2255,11 @@
<enum name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/>
</require>
</extension>
+ <extension name="EGL_EXT_gl_colorspace_display_p3_passthrough" supported="egl">
+ <require>
+ <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT"/>
+ </require>
+ </extension>
<extension name="EGL_EXT_image_dma_buf_import" supported="egl">
<require>
<enum name="EGL_LINUX_DMA_BUF_EXT"/>
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 9e748d8..9ba4140 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2638,6 +2638,7 @@
mOrientation = internalViewport->orientation;
}
}
+ getPolicy()->updatePointerDisplay();
bumpGeneration();
}
}
@@ -2783,7 +2784,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
- displayId = ADISPLAY_ID_DEFAULT;
+ displayId = mPointerController->getDisplayId();
} else {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
@@ -3601,6 +3602,9 @@
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
if (mPointerController == nullptr) {
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
+ getPolicy()->updatePointerDisplay();
+ } else if (viewportChanged) {
+ getPolicy()->updatePointerDisplay();
}
} else {
mPointerController.clear();
@@ -5387,7 +5391,8 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ int32_t displayId = mPointerController->getDisplayId();
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
@@ -6294,6 +6299,7 @@
void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
bool down, bool hovering) {
int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t displayId = mViewport.displayId;
if (mPointerController != nullptr) {
if (down || hovering) {
@@ -6304,13 +6310,14 @@
} else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
}
+ displayId = mPointerController->getDisplayId();
}
if (mPointerSimple.down && !down) {
mPointerSimple.down = false;
// Send up.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
@@ -6323,7 +6330,7 @@
mPointerSimple.hovering = false;
// Send hover exit.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
@@ -6338,7 +6345,7 @@
mPointerSimple.downTime = when;
// Send down.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
@@ -6348,7 +6355,7 @@
}
// Send move.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
@@ -6362,7 +6369,7 @@
mPointerSimple.hovering = true;
// Send hover enter.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
@@ -6373,7 +6380,7 @@
}
// Send hover move.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
@@ -6395,7 +6402,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &pointerCoords,
@@ -6457,8 +6464,9 @@
ALOG_ASSERT(false);
}
}
-
- NotifyMotionArgs args(when, getDeviceId(), source, mViewport.displayId, policyFlags,
+ int32_t displayId = mPointerController != nullptr ?
+ mPointerController->getDisplayId() : mViewport.displayId;
+ NotifyMotionArgs args(when, getDeviceId(), source, displayId, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index fe1c50b..5a78df7 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -342,6 +342,9 @@
/* Gets the affine calibration associated with the specified device. */
virtual TouchAffineTransformation getTouchAffineTransformation(
const std::string& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
+
+ /* Update the pointer controller associated with the specified display. */
+ virtual void updatePointerDisplay() = 0;
};
} // namespace android
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index e94dd94..e60b3f4 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -58,6 +58,9 @@
/* Gets the absolute location of the pointer. */
virtual void getPosition(float* outX, float* outY) const = 0;
+ /* Gets the id of the display where the pointer should be shown. */
+ virtual int32_t getDisplayId() const = 0;
+
enum Transition {
// Fade/unfade immediately.
TRANSITION_IMMEDIATE,
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 04b87d5..b18cae3 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -57,6 +57,7 @@
float mMinX, mMinY, mMaxX, mMaxY;
float mX, mY;
int32_t mButtonState;
+ int32_t mDisplayId;
protected:
virtual ~FakePointerController() { }
@@ -64,7 +65,7 @@
public:
FakePointerController() :
mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0),
- mButtonState(0) {
+ mButtonState(0), mDisplayId(ADISPLAY_ID_DEFAULT) {
}
void setBounds(float minX, float minY, float maxX, float maxY) {
@@ -75,6 +76,10 @@
mMaxY = maxY;
}
+ void setDisplayId(int32_t displayId) {
+ mDisplayId = displayId;
+ }
+
virtual void setPosition(float x, float y) {
mX = x;
mY = y;
@@ -93,6 +98,10 @@
*outY = mY;
}
+ virtual int32_t getDisplayId() const {
+ return mDisplayId;
+ }
+
private:
virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const {
*outMinX = mMinX;
@@ -262,6 +271,9 @@
virtual std::string getDeviceAlias(const InputDeviceIdentifier&) {
return "";
}
+
+ virtual void updatePointerDisplay() {
+ }
};
@@ -3127,6 +3139,30 @@
ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
}
+TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
+ CursorInputMapper* mapper = new CursorInputMapper(mDevice);
+ addMapperAndConfigure(mapper);
+
+ // Setup PointerController for second display.
+ constexpr int32_t SECOND_DISPLAY_ID = 1;
+ mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ mFakePointerController->setPosition(100, 200);
+ mFakePointerController->setButtonState(0);
+ mFakePointerController->setDisplayId(SECOND_DISPLAY_ID);
+
+ NotifyMotionArgs args;
+ process(mapper, ARBITRARY_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+ ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
+}
+
// --- TouchInputMapperTest ---
@@ -4625,7 +4661,6 @@
toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
}
-
// --- MultiTouchInputMapperTest ---
class MultiTouchInputMapperTest : public TouchInputMapperTest {
@@ -6246,4 +6281,30 @@
ASSERT_EQ(DISPLAY_ID, args.displayId);
}
+TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
+ // Setup PointerController for second display.
+ sp<FakePointerController> fakePointerController = new FakePointerController();
+ fakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ fakePointerController->setPosition(100, 200);
+ fakePointerController->setButtonState(0);
+ fakePointerController->setDisplayId(SECONDARY_DISPLAY_ID);
+ mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+
+ // Check source is mouse that would obtain the PointerController.
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
+
+ NotifyMotionArgs motionArgs;
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
+ ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
+}
+
} // namespace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 8dc80cc..776efab 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -32,8 +32,9 @@
const String16& opPackageName, bool hasSensorAccess)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
- mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
- mDestroyed(false), mHasSensorAccess(hasSensorAccess) {
+ mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
+ mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false),
+ mHasSensorAccess(hasSensorAccess) {
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -405,9 +406,6 @@
reAllocateCacheLocked(events, count);
} else {
// The events do not fit within the cache: drop the oldest events.
- ALOGW("Dropping events from cache (%d / %d) to save %d newer events", mCacheSize,
- mMaxCacheSize, count);
-
int freeSpace = mMaxCacheSize - mCacheSize;
// Drop up to the currently cached number of events to make room for new events
@@ -419,6 +417,18 @@
// Determine the number of new events to copy into the cache
int eventsToCopy = std::min(mMaxCacheSize, count);
+ constexpr nsecs_t kMinimumTimeBetweenDropLogNs = 2 * 1000 * 1000 * 1000; // 2 sec
+ if (events[0].timestamp - mTimeOfLastEventDrop > kMinimumTimeBetweenDropLogNs) {
+ ALOGW("Dropping %d cached events (%d/%d) to save %d/%d new events. %d events previously"
+ " dropped", cachedEventsToDrop, mCacheSize, mMaxCacheSize, eventsToCopy,
+ count, mEventsDropped);
+ mEventsDropped = 0;
+ mTimeOfLastEventDrop = events[0].timestamp;
+ } else {
+ // Record the number dropped
+ mEventsDropped += cachedEventsToDrop + newEventsToDrop;
+ }
+
// Check for any flush complete events in the events that will be dropped
countFlushCompleteEventsLocked(mEventCache, cachedEventsToDrop);
countFlushCompleteEventsLocked(events, newEventsToDrop);
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index eefd81a..061809f 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -165,6 +165,8 @@
sensors_event_t *mEventCache;
int mCacheSize, mMaxCacheSize;
+ int64_t mTimeOfLastEventDrop;
+ int mEventsDropped;
String8 mPackageName;
const String16 mOpPackageName;
#if DEBUG_CONNECTIONS
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 42b7146..1a13f77 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -24,6 +24,7 @@
},
srcs: [
":libsurfaceflinger_sources",
+ "libsurfaceflinger_unittest_main.cpp",
"CompositionTest.cpp",
"DisplayIdentificationTest.cpp",
"DisplayTransactionTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index bfd34cd..86f1a39 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -27,6 +27,8 @@
#include "TimeStats/TimeStats.h"
+#include "libsurfaceflinger_unittest_main.h"
+
using namespace android::surfaceflinger;
using namespace google::protobuf;
@@ -486,6 +488,10 @@
}
TEST_F(TimeStatsTest, canSurviveMonkey) {
+ if (g_noSlowTests) {
+ GTEST_SKIP();
+ }
+
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
for (size_t i = 0; i < 10000000; ++i) {
diff --git a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
new file mode 100644
index 0000000..bc1f00d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "libsurfaceflinger_unittest_main.h"
+
+// ------------------------------------------------------------------------
+// To pass extra command line arguments to the Google Test executable from
+// atest, you have to use this somewhat verbose syntax:
+//
+// clang-format off
+//
+// atest libsurfaceflinger_unittest -- --module-arg libsurfaceflinger_unittest:native-test-flag:<--flag>[:<value>]
+//
+// For example:
+//
+// atest libsurfaceflinger_unittest -- --module-arg libsurfaceflinger_unittest:native-test-flag:--no-slow
+//
+// clang-format on
+// ------------------------------------------------------------------------
+
+// Set to true if "--no-slow" is passed to the test.
+bool g_noSlowTests = false;
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--no-slow") == 0) {
+ g_noSlowTests = true;
+ }
+ }
+
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.h b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.h
new file mode 100644
index 0000000..e742c50
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// Set to true if "--no-slow" is passed to the test.
+extern bool g_noSlowTests;
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index f936e95..158ef9c 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -153,6 +153,17 @@
}
}
+void ConsumerChannel::OnProducerGained() {
+ // Clear the signal if exist. There is a possiblity that the signal still
+ // exist in consumer client when producer gains the buffer, e.g. newly added
+ // consumer fail to acquire the previous posted buffer in time. Then, when
+ // producer gains back the buffer, posts the buffer again and signal the
+ // consumer later, there won't be an signal change in eventfd, and thus,
+ // consumer will miss the posted buffer later. Thus, we need to clear the
+ // signal in consumer clients if the signal exist.
+ ClearAvailable();
+}
+
void ConsumerChannel::OnProducerPosted() {
acquired_ = false;
released_ = false;
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
index de0f23c..5fb4ec1 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
@@ -26,6 +26,7 @@
uint64_t client_state_mask() const { return client_state_mask_; }
BufferInfo GetBufferInfo() const override;
+ void OnProducerGained();
void OnProducerPosted();
void OnProducerClosed();
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index ab1d94c..b541fb3 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -424,7 +424,7 @@
// Signal any interested consumers. If there are none, the buffer will stay
// in posted state until a consumer comes online. This behavior guarantees
// that no frame is silently dropped.
- for (auto consumer : consumer_channels_) {
+ for (auto& consumer : consumer_channels_) {
consumer->OnProducerPosted();
}
@@ -437,6 +437,9 @@
ClearAvailable();
post_fence_.close();
+ for (auto& consumer : consumer_channels_) {
+ consumer->OnProducerGained();
+ }
return {std::move(returned_fence_)};
}
@@ -533,7 +536,7 @@
uint64_t current_buffer_state =
buffer_state_->load(std::memory_order_acquire);
- if (BufferHubDefs::IsClientReleased(current_buffer_state,
+ if (BufferHubDefs::IsBufferReleased(current_buffer_state &
~orphaned_consumer_bit_mask_)) {
SignalAvailable();
if (orphaned_consumer_bit_mask_) {
@@ -560,7 +563,7 @@
uint64_t current_buffer_state =
buffer_state_->load(std::memory_order_acquire);
- if (BufferHubDefs::IsClientReleased(current_buffer_state,
+ if (BufferHubDefs::IsBufferReleased(current_buffer_state &
~orphaned_consumer_bit_mask_)) {
SignalAvailable();
}
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 7eaf7b2..fed8481 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -39,6 +39,9 @@
"-Wno-switch-enum",
"-Wno-undef",
+ // Have clang emit complete debug_info.
+ "-fstandalone-debug",
+
//"-DLOG_NDEBUG=0",
],