Merge "Define OMX_AUDIO_AACObjectER_Scalable"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 08eff9e..3ca7de9 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -363,7 +363,7 @@
// Check whether the category would be supported on the device if the user
// were root. This function assumes that root is able to write to any file
// that exists. It performs the same logic as isCategorySupported, but it
-// uses file existance rather than writability in the /sys/ file checks.
+// uses file existence rather than writability in the /sys/ file checks.
static bool isCategorySupportedForRoot(const TracingCategory& category)
{
bool ok = category.tags != 0;
@@ -970,9 +970,9 @@
" -k fname,... trace the listed kernel functions\n"
" -n ignore signals\n"
" -s N sleep for N seconds before tracing [default 0]\n"
- " -t N trace for N seconds [defualt 5]\n"
+ " -t N trace for N seconds [default 5]\n"
" -z compress the trace dump\n"
- " --async_start start circular trace and return immediatly\n"
+ " --async_start start circular trace and return immediately\n"
" --async_dump dump the current contents of circular trace buffer\n"
" --async_stop stop tracing and dump the current contents of circular\n"
" trace buffer\n"
diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp
index 19d2d64..312dceb 100644
--- a/cmds/bugreportz/bugreportz.cpp
+++ b/cmds/bugreportz/bugreportz.cpp
@@ -80,8 +80,8 @@
}
if (s == -1) {
- printf("Failed to connect to dumpstatez service: %s\n", strerror(errno));
- return EXIT_FAILURE;
+ printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
+ return EXIT_SUCCESS;
}
// Set a timeout so that if nothing is read in 10 minutes, we'll stop
@@ -91,7 +91,7 @@
tv.tv_sec = 10 * 60;
tv.tv_usec = 0;
if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
- printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno));
+ fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
}
while (1) {
@@ -105,8 +105,7 @@
if (errno == EAGAIN) {
errno = ETIMEDOUT;
}
- printf("\nBugreport read terminated abnormally (%s).\n",
- strerror(errno));
+ printf("FAIL:Bugreport read terminated abnormally (%s)\n", strerror(errno));
break;
}
@@ -117,15 +116,17 @@
write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send,
bytes_to_send));
if (bytes_written == -1) {
- printf(
+ fprintf(stderr,
"Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
bytes_read, bytes_to_send, strerror(errno));
- return EXIT_FAILURE;
+ break;
}
bytes_to_send -= bytes_written;
} while (bytes_written != 0 && bytes_to_send > 0);
}
- close(s);
+ if (close(s) == -1) {
+ fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
+ }
return EXIT_SUCCESS;
}
diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md
index d7837ae..ca7d574 100644
--- a/cmds/dumpstate/bugreport-format.md
+++ b/cmds/dumpstate/bugreport-format.md
@@ -15,13 +15,13 @@
format _YYYY-MM-DD-HH-MM-SS_), and Shell simply propagates it as an attachment
in the `ACTION_SEND_MULTIPLE` intent.
-## Version v0 (Android M)
+## Version 0 (Android M)
On _Android M (Marshmallow)_, dumpstate still generates a flat
_bugreport-DATE.txt_ file, but then **Shell** creates a zip file called
_bugreport-DATE.zip_ containing a _bugreport-DATE.txt_ entry and sends that
file as the `ACTION_SEND_MULTIPLE` attachment.
-## Version v1 (Android N)
+## Version 1.0 (Android N)
On _Android N (TBD)_, `dumpstate` generates a zip file directly (unless there
is a failure, in which case it reverts to the flat file that is zipped by
**Shell** and hence the end result is the _v0_ format).
@@ -33,7 +33,7 @@
The zip file also contains 2 metadata entries generated by `dumpstate`:
-- `version.txt`: whose value is **v1**.
+- `version.txt`: whose value is **1.0**.
- `main-entry.txt`: whose value is the name of the flat text entry (i.e.,
_bugreport-BUILD_ID-DATE.txt_ or _bugreport-NEW_NAME.txt_).
@@ -61,16 +61,16 @@
changes become stable.
For example, the initial version during _Android N_ development was
-**v1-dev1**. When `dumpsys` was split in 2 sections but not all tools were
-ready to parse that format, the version was named **v1-dev2**,
+**1.0-dev1**. When `dumpsys` was split in 2 sections but not all tools were
+ready to parse that format, the version was named **1.0-dev2**,
which had to be passed do `dumpsys` explicitly (i.e., trhough a
-`-V v1-dev2` argument). Once that format became stable and tools
-knew how to parse it, the default version became **v1-dev2**.
+`-V 1.0-dev2` argument). Once that format became stable and tools
+knew how to parse it, the default version became **1.0-dev2**.
Similarly, if changes in the file format are made after the initial release of
Android defining that format, then a new _sub-version_ will be used.
For example, if after _Android N_ launches changes are made for the next _N_
-release, the version will be called **v1.1** or something like that.
+release, the version will be called **1.1** or something like that.
Determining version and main entry
-----------------------------------------------
@@ -83,7 +83,7 @@
version = read("version.txt")
main_entry = read("main_entry.txt")
else
- version = v0
+ version = 0
main_entry = entries[0]
fi
```
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index c414134..9e2df55 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -96,10 +96,9 @@
*
* See bugreport-format.txt for more info.
*/
-// TODO: change to "v1" before final N build
-static std::string VERSION_DEFAULT = "v1-dev4";
+static std::string VERSION_DEFAULT = "1.0";
-static bool is_user_build() {
+bool is_user_build() {
return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
}
@@ -542,7 +541,7 @@
property_get("ro.build.display.id", build, "(unknown)");
property_get("ro.build.fingerprint", fingerprint, "(unknown)");
property_get("ro.build.type", build_type, "(unknown)");
- property_get("ro.baseband", radio, "(unknown)");
+ property_get("gsm.version.baseband", radio, "(unknown)");
property_get("ro.bootloader", bootloader, "(unknown)");
property_get("gsm.operator.alpha", network, "(unknown)");
strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
@@ -622,7 +621,6 @@
return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
}
-/* adds all files from a directory to the zipped bugreport file */
void add_dir(const char *dir, bool recursive) {
if (!zip_writer) {
MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
@@ -672,7 +670,8 @@
dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
dump_file("MEMORY INFO", "/proc/meminfo");
- run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
+ run_command("CPU INFO", 10, "top", "-b", "-n", "1", "-H", "-s", "6",
+ "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name", NULL);
run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
dump_file("VMALLOC INFO", "/proc/vmallocinfo");
@@ -686,13 +685,18 @@
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
dump_file("KERNEL SYNC", "/d/sync");
- run_command("PROCESSES AND THREADS", 10, "toybox", "ps", "-A", "-T", "-Z",
+ run_command("PROCESSES AND THREADS", 10, "ps", "-A", "-T", "-Z",
"-O", "pri,nice,rtprio,sched,pcy", NULL);
run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
run_command("PRINTENV", 10, "printenv", NULL);
run_command("NETSTAT", 10, "netstat", "-n", NULL);
- run_command("LSMOD", 10, "lsmod", NULL);
+ struct stat s;
+ if (stat("/proc/modules", &s) != 0) {
+ MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
+ } else {
+ run_command("LSMOD", 10, "lsmod", NULL);
+ }
do_dmesg();
@@ -946,19 +950,19 @@
printf("== Running Application Activities\n");
printf("========================================================\n");
- run_command("APP ACTIVITIES", 30, "-t", "30", "dumpsys", "activity", "all", NULL);
+ run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
printf("========================================================\n");
printf("== Running Application Services\n");
printf("========================================================\n");
- run_command("APP SERVICES", 30, "-t", "30", "dumpsys", "activity", "service", "all", NULL);
+ run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
printf("========================================================\n");
printf("== Running Application Providers\n");
printf("========================================================\n");
- run_command("APP SERVICES", 30, "-t", "30", "dumpsys", "activity", "provider", "all", NULL);
+ run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
printf("========================================================\n");
@@ -1001,7 +1005,7 @@
temporary file.
*/
static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
- time_t now) {
+ const std::string& log_path, time_t now) {
if (!add_zip_entry(bugreport_name, bugreport_path)) {
MYLOGE("Failed to add text entry to .zip file\n");
return false;
@@ -1011,6 +1015,16 @@
return false;
}
+ // Add log file (which contains stderr output) to zip...
+ fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
+ if (!add_zip_entry("dumpstate_log.txt", log_path.c_str())) {
+ MYLOGE("Failed to add dumpstate log to .zip file\n");
+ return false;
+ }
+ // ... and re-opens it for further logging.
+ redirect_to_existing_file(stderr, const_cast<char*>(log_path.c_str()));
+ fprintf(stderr, "\n");
+
int32_t err = zip_writer->Finish();
if (err) {
MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
@@ -1172,7 +1186,7 @@
/* full path of the temporary file containing the bugreport */
std::string tmp_path;
- /* full path of the file containing the dumpstate logs*/
+ /* full path of the file containing the dumpstate logs */
std::string log_path;
/* full path of the systrace file, when enabled */
@@ -1316,7 +1330,7 @@
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
- run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
+ run_command_as_shell("DUMPSYS MEMINFO", 90, "dumpsys", "-t", "90", "meminfo", "-a", NULL);
run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
/* collect stack traces from Dalvik and native processes (needs root) */
@@ -1381,7 +1395,7 @@
if (do_zip_file) {
std::string entry_name = base_name + "-" + suffix + ".txt";
MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
- if (!finish_zip_file(entry_name, tmp_path, now)) {
+ if (!finish_zip_file(entry_name, tmp_path, log_path, now)) {
MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
do_text_file = true;
} else {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 94bfc5a..6093cd1 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -93,6 +93,9 @@
/* adds a new entry to the existing zip file. */
bool add_zip_entry_from_fd(const std::string& entry_name, int fd);
+/* adds all files from a directory to the zipped bugreport file */
+void add_dir(const char *dir, bool recursive);
+
/* prints the contents of a file */
int dump_file(const char *title, const char *path);
@@ -148,9 +151,12 @@
/* redirect output to a service control socket */
void redirect_to_socket(FILE *redirect, const char *service);
-/* redirect output to a file */
+/* redirect output to a new file */
void redirect_to_file(FILE *redirect, char *path);
+/* redirect output to an existing file */
+void redirect_to_existing_file(FILE *redirect, char *path);
+
/* create leading directories, if necessary */
void create_parent_dirs(const char *path);
@@ -196,12 +202,15 @@
/** Gets the last modification time of a file, or default time if file is not found. */
time_t get_mtime(int fd, time_t default_mtime);
-/* dump eMMC Extended CSD data */
+/* Dumps eMMC Extended CSD data. */
void dump_emmc_ecsd(const char *ext_csd_path);
-/** gets command-line arguments */
+/** Gets command-line arguments. */
void format_args(int argc, const char *argv[], std::string *args);
+/** Tells if the device is running a user build. */
+bool is_user_build();
+
/*
* Helper class used to report how long it takes for a section to finish.
*
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 992f0a9..2ebd50d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -51,6 +51,8 @@
static const int64_t NANOS_PER_SEC = 1000000000;
+static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
+
/* list of native processes to include in the native dumps */
// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
static const char* native_processes_to_dump[] = {
@@ -975,11 +977,11 @@
}
}
-/* redirect output to a file */
-void redirect_to_file(FILE *redirect, char *path) {
+void _redirect_to_file(FILE *redirect, char *path, int truncate_flag) {
create_parent_dirs(path);
- int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ int fd = TEMP_FAILURE_RETRY(open(path,
+ O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
if (fd < 0) {
MYLOGE("%s: %s\n", path, strerror(errno));
@@ -990,6 +992,14 @@
close(fd);
}
+void redirect_to_file(FILE *redirect, char *path) {
+ _redirect_to_file(redirect, path, O_TRUNC);
+}
+
+void redirect_to_existing_file(FILE *redirect, char *path) {
+ _redirect_to_file(redirect, path, O_APPEND);
+}
+
static bool should_dump_native_traces(const char* path) {
for (const char** p = native_processes_to_dump; *p; p++) {
if (!strcmp(*p, path)) {
@@ -1093,7 +1103,7 @@
/* wait for the writable-close notification from inotify */
struct pollfd pfd = { ifd, POLLIN, 0 };
- int ret = poll(&pfd, 1, 5000); /* 5 sec timeout */
+ int ret = poll(&pfd, 1, TRACE_DUMP_TIMEOUT_MS);
if (ret < 0) {
MYLOGE("poll: %s\n", strerror(errno));
} else if (ret == 0) {
@@ -1376,7 +1386,7 @@
void format_args(const char* command, const char *args[], std::string *string) {
LOG_ALWAYS_FATAL_IF(args == nullptr || command == nullptr);
string->append(command);
- if (args[0] == nullptr) return;
+ if (args[1] == nullptr) return;
string->append(" ");
for (int arg = 1; arg <= 1000; ++arg) {
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 7e5bbc5..957a449 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -10,6 +10,7 @@
#include <thread>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
@@ -30,6 +31,7 @@
#include <unistd.h>
using namespace android;
+using android::base::StringPrintf;
using android::base::unique_fd;
using android::base::WriteFully;
@@ -210,7 +212,8 @@
});
auto timeout = std::chrono::seconds(timeoutArg);
- auto end = std::chrono::steady_clock::now() + timeout;
+ auto start = std::chrono::steady_clock::now();
+ auto end = start + timeout;
struct pollfd pfd = {
.fd = local_end.get(),
@@ -267,6 +270,14 @@
} else {
dump_thread.join();
}
+
+ if (N > 1) {
+ std::chrono::duration<double> elapsed_seconds =
+ std::chrono::steady_clock::now() - start;
+ aout << StringPrintf("------ %.3fs was the duration of '", elapsed_seconds.count()).
+ c_str();
+ aout << service_name << "' ------" << endl;
+ }
} else {
aerr << "Can't find service: " << service_name << endl;
}
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index a1c3495..90ccbf8 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -2043,6 +2043,37 @@
return true;
}
+// Move/rename a B artifact (from) to an A artifact (to).
+static bool move_ab_path(const std::string& b_path, const std::string& a_path) {
+ // Check whether B exists.
+ {
+ struct stat s;
+ if (stat(b_path.c_str(), &s) != 0) {
+ // Silently ignore for now. The service calling this isn't smart enough to understand
+ // lack of artifacts at the moment.
+ return false;
+ }
+ if (!S_ISREG(s.st_mode)) {
+ LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
+ // Try to unlink, but swallow errors.
+ unlink(b_path.c_str());
+ return false;
+ }
+ }
+
+ // Rename B to A.
+ if (!unlink_and_rename(b_path.c_str(), a_path.c_str())) {
+ // Delete the b_path so we don't try again (or fail earlier).
+ if (unlink(b_path.c_str()) != 0) {
+ PLOG(ERROR) << "Could not unlink " << b_path;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
int move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
if (apk_path == nullptr || instruction_set == nullptr || oat_dir == nullptr) {
LOG(ERROR) << "Cannot move_ab with null input";
@@ -2061,37 +2092,35 @@
if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) {
return -1;
}
+ const std::string a_image_path = create_image_filename(a_path);
// B path = A path + ".b"
- std::string b_path = StringPrintf("%s.b", a_path);
+ const std::string b_path = StringPrintf("%s.b", a_path);
+ const std::string b_image_path = StringPrintf("%s.b", a_image_path.c_str());
- // Check whether B exists.
- {
- struct stat s;
- if (stat(b_path.c_str(), &s) != 0) {
- // Silently ignore for now. The service calling this isn't smart enough to understand
- // lack of artifacts at the moment.
- return -1;
+ bool oat_success = move_ab_path(b_path, a_path);
+ bool success;
+
+ if (oat_success) {
+ // Note: we can live without an app image. As such, ignore failure to move the image file.
+ // If we decide to require the app image, or the app image being moved correctly,
+ // then change accordingly.
+ constexpr bool kIgnoreAppImageFailure = true;
+
+ bool art_success = true;
+ if (!a_image_path.empty()) {
+ art_success = move_ab_path(b_image_path, a_image_path);
}
- if (!S_ISREG(s.st_mode)) {
- LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
- // Try to unlink, but swallow errors.
- unlink(b_path.c_str());
- return -1;
- }
+
+ success = art_success || kIgnoreAppImageFailure;
+ } else {
+ // Cleanup: delete B image, ignore errors.
+ unlink(b_image_path.c_str());
+
+ success = false;
}
- // Rename B to A.
- if (!unlink_and_rename(b_path.c_str(), a_path)) {
- // Delete the b_path so we don't try again (or fail earlier).
- if (unlink(b_path.c_str()) != 0) {
- PLOG(ERROR) << "Could not unlink " << b_path;
- }
-
- return -1;
- }
-
- return 0;
+ return success ? 0 : -1;
}
} // namespace installd
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 3775709..e1cfc9d 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -51,8 +51,10 @@
#define TOKEN_MAX 16 /* max number of arguments in buffer */
#define REPLY_MAX 256 /* largest reply allowed */
+using android::base::EndsWith;
using android::base::Join;
using android::base::Split;
+using android::base::StartsWith;
using android::base::StringPrintf;
namespace android {
@@ -361,6 +363,49 @@
}
int RunPreopt() {
+ // Run the preopt.
+ //
+ // There's one thing we have to be careful about: we may/will be asked to compile an app
+ // living in the system image. This may be a valid request - if the app wasn't compiled,
+ // e.g., if the system image wasn't large enough to include preopted files. However, the
+ // data we have is from the old system, so the driver (the OTA service) can't actually
+ // know. Thus, we will get requests for apps that have preopted components. To avoid
+ // duplication (we'd generate files that are not used and are *not* cleaned up), do two
+ // simple checks:
+ //
+ // 1) Does the apk_path start with the value of ANDROID_ROOT? (~in the system image)
+ // (For simplicity, assume the value of ANDROID_ROOT does not contain a symlink.)
+ //
+ // 2) If you replace the name in the apk_path with "oat," does the path exist?
+ // (=have a subdirectory for preopted files)
+ //
+ // If the answer to both is yes, skip the dexopt.
+ //
+ // Note: while one may think it's OK to call dexopt and it will fail (because APKs should
+ // be stripped), that's not true for APKs signed outside the build system (so the
+ // jar content must be exactly the same).
+
+ // (This is ugly as it's the only thing where we need to understand the contents
+ // of package_parameters_, but it beats postponing the decision or using the call-
+ // backs to do weird things.)
+ constexpr size_t kApkPathIndex = 0;
+ CHECK_GT(DEXOPT_PARAM_COUNT, kApkPathIndex);
+ CHECK(package_parameters_[kApkPathIndex] != nullptr);
+ CHECK(system_properties_.GetProperty(kAndroidRootPathPropertyName) != nullptr);
+ if (StartsWith(package_parameters_[kApkPathIndex],
+ system_properties_.GetProperty(kAndroidRootPathPropertyName)->c_str())) {
+ const char* last_slash = strrchr(package_parameters_[kApkPathIndex], '/');
+ if (last_slash != nullptr) {
+ std::string path(package_parameters_[kApkPathIndex],
+ last_slash - package_parameters_[kApkPathIndex] + 1);
+ CHECK(EndsWith(path, "/"));
+ path = path + "oat";
+ if (access(path.c_str(), F_OK) == 0) {
+ return 0;
+ }
+ }
+ }
+
return dexopt(package_parameters_);
}
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index a31734a..394c244 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -18,24 +18,33 @@
# This script will run as a postinstall step to drive otapreopt.
+STATUS_FD="$2"
+
# Maximum number of packages/steps.
MAXIMUM_PACKAGES=1000
PREPARE=$(cmd otadexopt prepare)
-if [ "$PREPARE" != "Success" ] ; then
- echo "Failed to prepare."
- exit 1
-fi
+# Note: Ignore preparation failures. Step and done will fail and exit this.
+# This is necessary to support suspends - the OTA service will keep
+# the state around for us.
+
+PROGRESS=$(cmd otadexopt progress)
+print -u${STATUS_FD} "global_progress $PROGRESS"
i=0
while ((i<MAXIMUM_PACKAGES)) ; do
cmd otadexopt step
+
+ PROGRESS=$(cmd otadexopt progress)
+ print -u${STATUS_FD} "global_progress $PROGRESS"
+
DONE=$(cmd otadexopt done)
- if [ "$DONE" = "OTA complete." ] ; then
- break
+ if [ "$DONE" = "OTA incomplete." ] ; then
+ sleep 1
+ i=$((i+1))
+ continue
fi
- sleep 1
- i=$((i+1))
+ break
done
DONE=$(cmd otadexopt done)
@@ -45,6 +54,7 @@
echo "Complete or error."
fi
+print -u${STATUS_FD} "global_progress 1.0"
cmd otadexopt cleanup
exit 0
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 09300a2..fe4b1fa 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -66,6 +66,8 @@
virtual void onFrameReplaced(const BufferItem& item) override;
virtual void onBuffersReleased() override;
virtual void onSidebandStreamChanged() override;
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const override;
private:
// mConsumerListener is a weak reference to the IConsumerListener. This is
// the raison d'etre of ProxyConsumerListener.
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index a75ed98..a85bbb7 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -186,6 +186,10 @@
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) override;
+ // See IGraphicBufferProducer::getFrameTimestamps
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const override;
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
new file mode 100644
index 0000000..4dc7467
--- /dev/null
+++ b/include/gui/FrameTimestamps.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_FRAMETIMESTAMPS_H
+#define ANDROID_GUI_FRAMETIMESTAMPS_H
+
+#include <utils/Timers.h>
+#include <utils/Flattenable.h>
+
+namespace android {
+
+struct FrameTimestamps : public LightFlattenablePod<FrameTimestamps> {
+ FrameTimestamps() :
+ frameNumber(0),
+ postedTime(0),
+ acquireTime(0),
+ refreshStartTime(0),
+ glCompositionDoneTime(0),
+ displayRetireTime(0),
+ releaseTime(0) {}
+
+ uint64_t frameNumber;
+ nsecs_t postedTime;
+ nsecs_t acquireTime;
+ nsecs_t refreshStartTime;
+ nsecs_t glCompositionDoneTime;
+ nsecs_t displayRetireTime;
+ nsecs_t releaseTime;
+};
+
+} // namespace android
+#endif
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 3f39799..1efcf3c 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -25,6 +25,8 @@
#include <binder/IInterface.h>
+#include <gui/FrameTimestamps.h>
+
namespace android {
// ----------------------------------------------------------------------------
@@ -78,6 +80,11 @@
// stream is first attached and when it is either detached or replaced by a
// different stream.
virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
+
+ // See IGraphicBufferProducer::getFrameTimestamps
+ // This queries the consumer for the timestamps
+ virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
+ FrameTimestamps* /*outTimestamps*/) const { return false; }
};
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 37ae6df..0c24606 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -30,6 +30,8 @@
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <gui/FrameTimestamps.h>
+
namespace android {
// ----------------------------------------------------------------------------
@@ -568,6 +570,14 @@
// Returns NO_ERROR or the status of the Binder transaction
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) = 0;
+
+ // Attempts to retrieve timestamp information for the given frame number.
+ // If information for the given frame number is not found, returns false.
+ // Returns true otherwise.
+ //
+ // If a fence has not yet signaled the timestamp returned will be 0;
+ virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
+ FrameTimestamps* /*outTimestamps*/) const { return false; }
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 646203b..7d9d901 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -134,6 +134,12 @@
status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]);
+ // See IGraphicBufferProducer::getFrameTimestamps
+ bool getFrameTimestamps(uint64_t frameNumber, nsecs_t* outPostedTime,
+ nsecs_t* outAcquireTime, nsecs_t* outRefreshStartTime,
+ nsecs_t* outGlCompositionDoneTime, nsecs_t* outDisplayRetireTime,
+ nsecs_t* outReleaseTime);
+
protected:
virtual ~Surface();
@@ -183,6 +189,7 @@
int dispatchSetSurfaceDamage(va_list args);
int dispatchSetSharedBufferMode(va_list args);
int dispatchSetAutoRefresh(va_list args);
+ int dispatchGetFrameTimestamps(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
diff --git a/include/ui/FrameStats.h b/include/ui/FrameStats.h
index 5fdf94d..6bfe635 100644
--- a/include/ui/FrameStats.h
+++ b/include/ui/FrameStats.h
@@ -25,6 +25,7 @@
class FrameStats : public LightFlattenable<FrameStats> {
public:
+ FrameStats() : refreshPeriodNano(0) {};
/*
* Approximate refresh time, in nanoseconds.
diff --git a/include/ui/Gralloc1.h b/include/ui/Gralloc1.h
new file mode 100644
index 0000000..cf8c173
--- /dev/null
+++ b/include/ui/Gralloc1.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC1_H
+#define ANDROID_UI_GRALLOC1_H
+
+#define GRALLOC1_LOG_TAG "Gralloc1"
+
+#include <ui/Gralloc1On0Adapter.h>
+
+#include <unordered_set>
+
+namespace std {
+ template <>
+ struct hash<gralloc1_capability_t> {
+ size_t operator()(gralloc1_capability_t capability) const {
+ return std::hash<int32_t>()(static_cast<int32_t>(capability));
+ }
+ };
+}
+
+namespace android {
+
+class Fence;
+class GraphicBuffer;
+
+namespace Gralloc1 {
+
+class Device;
+
+class Descriptor {
+public:
+ Descriptor(Device& device, gralloc1_buffer_descriptor_t deviceId)
+ : mShimDevice(device),
+ mDeviceId(deviceId),
+ mWidth(0),
+ mHeight(0),
+ mFormat(static_cast<android_pixel_format_t>(0)),
+ mProducerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
+ mConsumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
+
+ ~Descriptor();
+
+ gralloc1_buffer_descriptor_t getDeviceId() const { return mDeviceId; }
+
+ gralloc1_error_t setDimensions(uint32_t width, uint32_t height);
+ gralloc1_error_t setFormat(android_pixel_format_t format);
+ gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage);
+ gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage);
+
+private:
+ Device& mShimDevice;
+ const gralloc1_buffer_descriptor_t mDeviceId;
+
+ uint32_t mWidth;
+ uint32_t mHeight;
+ android_pixel_format_t mFormat;
+ gralloc1_producer_usage_t mProducerUsage;
+ gralloc1_consumer_usage_t mConsumerUsage;
+
+}; // Descriptor
+
+class Device {
+ friend class Gralloc1::Descriptor;
+
+public:
+ Device(gralloc1_device_t* device);
+
+ bool hasCapability(gralloc1_capability_t capability) const;
+
+ std::string dump();
+
+ std::shared_ptr<Descriptor> createDescriptor();
+
+ gralloc1_error_t getStride(buffer_handle_t buffer, uint32_t* outStride);
+
+ gralloc1_error_t allocate(
+ const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
+ std::vector<buffer_handle_t>* outBuffers);
+ gralloc1_error_t allocate(
+ const std::shared_ptr<const Descriptor>& descriptor,
+ gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+
+ gralloc1_error_t retain(buffer_handle_t buffer);
+ gralloc1_error_t retain(const GraphicBuffer* buffer);
+
+ gralloc1_error_t release(buffer_handle_t buffer);
+
+ gralloc1_error_t getNumFlexPlanes(buffer_handle_t buffer,
+ uint32_t* outNumPlanes);
+
+ gralloc1_error_t lock(buffer_handle_t buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t* accessRegion, void** outData,
+ const sp<Fence>& acquireFence);
+ gralloc1_error_t lockFlex(buffer_handle_t buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t* accessRegion,
+ struct android_flex_layout* outData, const sp<Fence>& acquireFence);
+ gralloc1_error_t lockYCbCr(buffer_handle_t buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t* accessRegion, struct android_ycbcr* outData,
+ const sp<Fence>& acquireFence);
+
+ gralloc1_error_t unlock(buffer_handle_t buffer, sp<Fence>* outFence);
+
+private:
+ std::unordered_set<gralloc1_capability_t> loadCapabilities();
+
+ bool loadFunctions();
+
+ template <typename LockType, typename OutType>
+ gralloc1_error_t lockHelper(LockType pfn, buffer_handle_t buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t* accessRegion, OutType* outData,
+ const sp<Fence>& acquireFence) {
+ int32_t intError = pfn(mDevice, buffer,
+ static_cast<uint64_t>(producerUsage),
+ static_cast<uint64_t>(consumerUsage), accessRegion, outData,
+ acquireFence->dup());
+ return static_cast<gralloc1_error_t>(intError);
+ }
+
+ gralloc1_device_t* const mDevice;
+
+ const std::unordered_set<gralloc1_capability_t> mCapabilities;
+
+ template <typename PFN, gralloc1_function_descriptor_t descriptor>
+ struct FunctionLoader {
+ FunctionLoader() : pfn(nullptr) {}
+
+ bool load(gralloc1_device_t* device, bool errorIfNull) {
+ gralloc1_function_pointer_t rawPointer =
+ device->getFunction(device, descriptor);
+ pfn = reinterpret_cast<PFN>(rawPointer);
+ if (errorIfNull && !rawPointer) {
+ ALOG(LOG_ERROR, GRALLOC1_LOG_TAG,
+ "Failed to load function pointer %d", descriptor);
+ }
+ return rawPointer != nullptr;
+ }
+
+ template <typename ...Args>
+ typename std::result_of<PFN(Args...)>::type operator()(Args... args) {
+ return pfn(args...);
+ }
+
+ PFN pfn;
+ };
+
+ // Function pointers
+ struct Functions {
+ FunctionLoader<GRALLOC1_PFN_DUMP, GRALLOC1_FUNCTION_DUMP> dump;
+ FunctionLoader<GRALLOC1_PFN_CREATE_DESCRIPTOR,
+ GRALLOC1_FUNCTION_CREATE_DESCRIPTOR> createDescriptor;
+ FunctionLoader<GRALLOC1_PFN_DESTROY_DESCRIPTOR,
+ GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR> destroyDescriptor;
+ FunctionLoader<GRALLOC1_PFN_SET_CONSUMER_USAGE,
+ GRALLOC1_FUNCTION_SET_CONSUMER_USAGE> setConsumerUsage;
+ FunctionLoader<GRALLOC1_PFN_SET_DIMENSIONS,
+ GRALLOC1_FUNCTION_SET_DIMENSIONS> setDimensions;
+ FunctionLoader<GRALLOC1_PFN_SET_FORMAT,
+ GRALLOC1_FUNCTION_SET_FORMAT> setFormat;
+ FunctionLoader<GRALLOC1_PFN_SET_PRODUCER_USAGE,
+ GRALLOC1_FUNCTION_SET_PRODUCER_USAGE> setProducerUsage;
+ FunctionLoader<GRALLOC1_PFN_GET_BACKING_STORE,
+ GRALLOC1_FUNCTION_GET_BACKING_STORE> getBackingStore;
+ FunctionLoader<GRALLOC1_PFN_GET_CONSUMER_USAGE,
+ GRALLOC1_FUNCTION_GET_CONSUMER_USAGE> getConsumerUsage;
+ FunctionLoader<GRALLOC1_PFN_GET_DIMENSIONS,
+ GRALLOC1_FUNCTION_GET_DIMENSIONS> getDimensions;
+ FunctionLoader<GRALLOC1_PFN_GET_FORMAT,
+ GRALLOC1_FUNCTION_GET_FORMAT> getFormat;
+ FunctionLoader<GRALLOC1_PFN_GET_PRODUCER_USAGE,
+ GRALLOC1_FUNCTION_GET_PRODUCER_USAGE> getProducerUsage;
+ FunctionLoader<GRALLOC1_PFN_GET_STRIDE,
+ GRALLOC1_FUNCTION_GET_STRIDE> getStride;
+ FunctionLoader<GRALLOC1_PFN_ALLOCATE,
+ GRALLOC1_FUNCTION_ALLOCATE> allocate;
+ FunctionLoader<GRALLOC1_PFN_RETAIN,
+ GRALLOC1_FUNCTION_RETAIN> retain;
+ FunctionLoader<GRALLOC1_PFN_RELEASE,
+ GRALLOC1_FUNCTION_RELEASE> release;
+ FunctionLoader<GRALLOC1_PFN_GET_NUM_FLEX_PLANES,
+ GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES> getNumFlexPlanes;
+ FunctionLoader<GRALLOC1_PFN_LOCK,
+ GRALLOC1_FUNCTION_LOCK> lock;
+ FunctionLoader<GRALLOC1_PFN_LOCK_FLEX,
+ GRALLOC1_FUNCTION_LOCK_FLEX> lockFlex;
+ FunctionLoader<GRALLOC1_PFN_LOCK_YCBCR,
+ GRALLOC1_FUNCTION_LOCK_YCBCR> lockYCbCr;
+ FunctionLoader<GRALLOC1_PFN_UNLOCK,
+ GRALLOC1_FUNCTION_UNLOCK> unlock;
+
+ // Adapter-only functions
+ FunctionLoader<GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER,
+ GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER> retainGraphicBuffer;
+ FunctionLoader<GRALLOC1_PFN_ALLOCATE_WITH_ID,
+ GRALLOC1_FUNCTION_ALLOCATE_WITH_ID> allocateWithId;
+ } mFunctions;
+
+}; // class android::Gralloc1::Device
+
+class Loader
+{
+public:
+ Loader();
+ ~Loader();
+
+ std::unique_ptr<Device> getDevice();
+
+private:
+ static std::unique_ptr<Gralloc1On0Adapter> mAdapter;
+ std::unique_ptr<Device> mDevice;
+};
+
+} // namespace android::Gralloc1
+
+} // namespace android
+
+#endif
diff --git a/include/ui/Gralloc1On0Adapter.h b/include/ui/Gralloc1On0Adapter.h
new file mode 100644
index 0000000..edcfb65
--- /dev/null
+++ b/include/ui/Gralloc1On0Adapter.h
@@ -0,0 +1,478 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
+#define ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <hardware/gralloc1.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+struct gralloc_module_t;
+
+// This is not an "official" capability (i.e., it is not found in gralloc1.h),
+// but we will use it to detect that we are running through the adapter, which
+// is capable of collaborating with GraphicBuffer such that queries on a
+// buffer_handle_t succeed
+static const auto GRALLOC1_CAPABILITY_ON_ADAPTER =
+ static_cast<gralloc1_capability_t>(GRALLOC1_LAST_CAPABILITY + 1);
+
+static const auto GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER =
+ static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 1);
+static const auto GRALLOC1_FUNCTION_ALLOCATE_WITH_ID =
+ static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 2);
+static const auto GRALLOC1_FUNCTION_LOCK_YCBCR =
+ static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 3);
+static const auto GRALLOC1_LAST_ADAPTER_FUNCTION = GRALLOC1_FUNCTION_LOCK_YCBCR;
+
+typedef gralloc1_error_t (*GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER)(
+ gralloc1_device_t* device, const android::GraphicBuffer* buffer);
+typedef gralloc1_error_t (*GRALLOC1_PFN_ALLOCATE_WITH_ID)(
+ gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptor,
+ gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+typedef int32_t /*gralloc1_error_t*/ (*GRALLOC1_PFN_LOCK_YCBCR)(
+ gralloc1_device_t* device, buffer_handle_t buffer,
+ uint64_t /*gralloc1_producer_usage_t*/ producerUsage,
+ uint64_t /*gralloc1_consumer_usage_t*/ consumerUsage,
+ const gralloc1_rect_t* accessRegion, struct android_ycbcr* outYCbCr,
+ int32_t acquireFence);
+
+namespace android {
+
+class Gralloc1On0Adapter : public gralloc1_device_t
+{
+public:
+ Gralloc1On0Adapter(const hw_module_t* module);
+ ~Gralloc1On0Adapter();
+
+ gralloc1_device_t* getDevice() {
+ return static_cast<gralloc1_device_t*>(this);
+ }
+
+private:
+ static inline Gralloc1On0Adapter* getAdapter(gralloc1_device_t* device) {
+ return static_cast<Gralloc1On0Adapter*>(device);
+ }
+
+ // getCapabilities
+
+ void doGetCapabilities(uint32_t* outCount,
+ int32_t* /*gralloc1_capability_t*/ outCapabilities);
+ static void getCapabilitiesHook(gralloc1_device_t* device,
+ uint32_t* outCount,
+ int32_t* /*gralloc1_capability_t*/ outCapabilities) {
+ getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
+ };
+
+ // getFunction
+
+ gralloc1_function_pointer_t doGetFunction(
+ int32_t /*gralloc1_function_descriptor_t*/ descriptor);
+ static gralloc1_function_pointer_t getFunctionHook(
+ gralloc1_device_t* device,
+ int32_t /*gralloc1_function_descriptor_t*/ descriptor) {
+ return getAdapter(device)->doGetFunction(descriptor);
+ }
+
+ // dump
+
+ void dump(uint32_t* outSize, char* outBuffer);
+ static void dumpHook(gralloc1_device_t* device, uint32_t* outSize,
+ char* outBuffer) {
+ return getAdapter(device)->dump(outSize, outBuffer);
+ }
+ std::string mCachedDump;
+
+ // Buffer descriptor lifecycle functions
+
+ class Descriptor;
+
+ gralloc1_error_t createDescriptor(
+ gralloc1_buffer_descriptor_t* outDescriptor);
+ static int32_t createDescriptorHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t* outDescriptor) {
+ auto error = getAdapter(device)->createDescriptor(outDescriptor);
+ return static_cast<int32_t>(error);
+ }
+
+ gralloc1_error_t destroyDescriptor(gralloc1_buffer_descriptor_t descriptor);
+ static int32_t destroyDescriptorHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptor) {
+ auto error = getAdapter(device)->destroyDescriptor(descriptor);
+ return static_cast<int32_t>(error);
+ }
+
+ // Buffer descriptor modification functions
+
+ struct Descriptor : public std::enable_shared_from_this<Descriptor> {
+ Descriptor(Gralloc1On0Adapter* adapter,
+ gralloc1_buffer_descriptor_t id)
+ : adapter(adapter),
+ id(id),
+ width(0),
+ height(0),
+ format(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ producerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
+ consumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
+
+ gralloc1_error_t setDimensions(uint32_t w, uint32_t h) {
+ width = w;
+ height = h;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t setFormat(int32_t f) {
+ format = f;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage) {
+ producerUsage = usage;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage) {
+ consumerUsage = usage;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ Gralloc1On0Adapter* const adapter;
+ const gralloc1_buffer_descriptor_t id;
+
+ uint32_t width;
+ uint32_t height;
+ int32_t format;
+ gralloc1_producer_usage_t producerUsage;
+ gralloc1_consumer_usage_t consumerUsage;
+ };
+
+ template <typename ...Args>
+ static int32_t callDescriptorFunction(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId,
+ gralloc1_error_t (Descriptor::*member)(Args...), Args... args) {
+ auto descriptor = getAdapter(device)->getDescriptor(descriptorId);
+ if (!descriptor) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_DESCRIPTOR);
+ }
+ auto error = ((*descriptor).*member)(std::forward<Args>(args)...);
+ return static_cast<int32_t>(error);
+ }
+
+ static int32_t setConsumerUsageHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
+ auto usage = static_cast<gralloc1_consumer_usage_t>(intUsage);
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setConsumerUsage, usage);
+ }
+
+ static int32_t setDimensionsHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, uint32_t width,
+ uint32_t height) {
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setDimensions, width, height);
+ }
+
+ static int32_t setFormatHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, int32_t format) {
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setFormat, format);
+ }
+
+ static int32_t setProducerUsageHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
+ auto usage = static_cast<gralloc1_producer_usage_t>(intUsage);
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setProducerUsage, usage);
+ }
+
+ // Buffer handle query functions
+
+ class Buffer {
+ public:
+ Buffer(buffer_handle_t handle, gralloc1_backing_store_t store,
+ const Descriptor& descriptor, uint32_t stride,
+ bool wasAllocated);
+
+ buffer_handle_t getHandle() const { return mHandle; }
+
+ void retain() { ++mReferenceCount; }
+
+ // Returns true if the reference count has dropped to 0, indicating that
+ // the buffer needs to be released
+ bool release() { return --mReferenceCount == 0; }
+
+ bool wasAllocated() const { return mWasAllocated; }
+
+ gralloc1_error_t getBackingStore(
+ gralloc1_backing_store_t* outStore) const {
+ *outStore = mStore;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getConsumerUsage(
+ gralloc1_consumer_usage_t* outUsage) const {
+ *outUsage = mDescriptor.consumerUsage;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getDimensions(uint32_t* outWidth,
+ uint32_t* outHeight) const {
+ *outWidth = mDescriptor.width;
+ *outHeight = mDescriptor.height;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getFormat(int32_t* outFormat) const {
+ *outFormat = mDescriptor.format;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getNumFlexPlanes(uint32_t* outNumPlanes) const {
+ // TODO: This is conservative, and we could do better by examining
+ // the format, but it won't hurt anything for now
+ *outNumPlanes = 4;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getProducerUsage(
+ gralloc1_producer_usage_t* outUsage) const {
+ *outUsage = mDescriptor.producerUsage;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getStride(uint32_t* outStride) const {
+ *outStride = mStride;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ private:
+
+ const buffer_handle_t mHandle;
+ size_t mReferenceCount;
+
+ // Since we're adapting to gralloc0, there will always be a 1:1
+ // correspondence between buffer handles and backing stores, and the
+ // backing store ID will be the same as the GraphicBuffer unique ID
+ const gralloc1_backing_store_t mStore;
+
+ const Descriptor mDescriptor;
+ const uint32_t mStride;
+
+ // Whether this buffer allocated in this process (as opposed to just
+ // being retained here), which determines whether to free or unregister
+ // the buffer when this Buffer is released
+ const bool mWasAllocated;
+ };
+
+ template <typename ...Args>
+ static int32_t callBufferFunction(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle,
+ gralloc1_error_t (Buffer::*member)(Args...) const, Args... args) {
+ auto buffer = getAdapter(device)->getBuffer(bufferHandle);
+ if (!buffer) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+ }
+ auto error = ((*buffer).*member)(std::forward<Args>(args)...);
+ return static_cast<int32_t>(error);
+ }
+
+ template <typename MF, MF memFunc, typename ...Args>
+ static int32_t bufferHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle, Args... args) {
+ return Gralloc1On0Adapter::callBufferFunction(device, bufferHandle,
+ memFunc, std::forward<Args>(args)...);
+ }
+
+ static int32_t getConsumerUsageHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle, uint64_t* outUsage) {
+ auto usage = GRALLOC1_CONSUMER_USAGE_NONE;
+ auto error = callBufferFunction(device, bufferHandle,
+ &Buffer::getConsumerUsage, &usage);
+ if (error != GRALLOC1_ERROR_NONE) {
+ *outUsage = static_cast<uint64_t>(usage);
+ }
+ return error;
+ }
+
+ static int32_t getProducerUsageHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle, uint64_t* outUsage) {
+ auto usage = GRALLOC1_PRODUCER_USAGE_NONE;
+ auto error = callBufferFunction(device, bufferHandle,
+ &Buffer::getProducerUsage, &usage);
+ if (error != GRALLOC1_ERROR_NONE) {
+ *outUsage = static_cast<uint64_t>(usage);
+ }
+ return error;
+ }
+
+ // Buffer management functions
+
+ // We don't provide GRALLOC1_FUNCTION_ALLOCATE, since this should always be
+ // called through GRALLOC1_FUNCTION_ALLOCATE_WITH_ID
+ gralloc1_error_t allocate(
+ const std::shared_ptr<Descriptor>& descriptor,
+ gralloc1_backing_store_t id,
+ buffer_handle_t* outBufferHandle);
+ static gralloc1_error_t allocateWithIdHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptors,
+ gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+
+ gralloc1_error_t retain(const std::shared_ptr<Buffer>& buffer);
+ gralloc1_error_t release(const std::shared_ptr<Buffer>& buffer);
+
+ // Member function pointer 'member' will either be retain or release
+ template <gralloc1_error_t (Gralloc1On0Adapter::*member)(
+ const std::shared_ptr<Buffer>& buffer)>
+ static int32_t managementHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle) {
+ auto adapter = getAdapter(device);
+
+ auto buffer = adapter->getBuffer(bufferHandle);
+ if (!buffer) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+ }
+
+ auto error = ((*adapter).*member)(buffer);
+ return static_cast<int32_t>(error);
+ }
+
+ gralloc1_error_t retain(const GraphicBuffer* buffer);
+ static gralloc1_error_t retainGraphicBufferHook(gralloc1_device_t* device,
+ const GraphicBuffer* buffer) {
+ auto adapter = getAdapter(device);
+ return adapter->retain(buffer);
+ }
+
+ // Buffer access functions
+
+ gralloc1_error_t lock(const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion, void** outData,
+ const sp<Fence>& acquireFence);
+ gralloc1_error_t lockFlex(const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion,
+ struct android_flex_layout* outFlex,
+ const sp<Fence>& acquireFence);
+ gralloc1_error_t lockYCbCr(const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion,
+ struct android_ycbcr* outFlex,
+ const sp<Fence>& acquireFence);
+
+ template <typename OUT, gralloc1_error_t (Gralloc1On0Adapter::*member)(
+ const std::shared_ptr<Buffer>&, gralloc1_producer_usage_t,
+ gralloc1_consumer_usage_t, const gralloc1_rect_t&, OUT*,
+ const sp<Fence>&)>
+ static int32_t lockHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle,
+ uint64_t /*gralloc1_producer_usage_t*/ uintProducerUsage,
+ uint64_t /*gralloc1_consumer_usage_t*/ uintConsumerUsage,
+ const gralloc1_rect_t* accessRegion, OUT* outData,
+ int32_t acquireFenceFd) {
+ auto adapter = getAdapter(device);
+
+ // Exactly one of producer and consumer usage must be *_USAGE_NONE,
+ // but we can't check this until the upper levels of the framework
+ // correctly distinguish between producer and consumer usage
+ /*
+ bool hasProducerUsage =
+ uintProducerUsage != GRALLOC1_PRODUCER_USAGE_NONE;
+ bool hasConsumerUsage =
+ uintConsumerUsage != GRALLOC1_CONSUMER_USAGE_NONE;
+ if (hasProducerUsage && hasConsumerUsage ||
+ !hasProducerUsage && !hasConsumerUsage) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+ }
+ */
+
+ auto producerUsage =
+ static_cast<gralloc1_producer_usage_t>(uintProducerUsage);
+ auto consumerUsage =
+ static_cast<gralloc1_consumer_usage_t>(uintConsumerUsage);
+
+ if (!outData) {
+ const auto producerCpuUsage = GRALLOC1_PRODUCER_USAGE_CPU_READ |
+ GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+ if (producerUsage & producerCpuUsage != 0) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+ }
+ if (consumerUsage & GRALLOC1_CONSUMER_USAGE_CPU_READ != 0) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+ }
+ }
+
+ auto buffer = adapter->getBuffer(bufferHandle);
+ if (!buffer) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+ }
+
+ if (!accessRegion) {
+ ALOGE("accessRegion is null");
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+ }
+
+ sp<Fence> acquireFence{new Fence(acquireFenceFd)};
+ auto error = ((*adapter).*member)(buffer, producerUsage, consumerUsage,
+ *accessRegion, outData, acquireFence);
+ return static_cast<int32_t>(error);
+ }
+
+ gralloc1_error_t unlock(const std::shared_ptr<Buffer>& buffer,
+ sp<Fence>* outReleaseFence);
+ static int32_t unlockHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle, int32_t* outReleaseFenceFd) {
+ auto adapter = getAdapter(device);
+
+ auto buffer = adapter->getBuffer(bufferHandle);
+ if (!buffer) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+ }
+
+ sp<Fence> releaseFence = Fence::NO_FENCE;
+ auto error = adapter->unlock(buffer, &releaseFence);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outReleaseFenceFd = releaseFence->dup();
+ }
+ return static_cast<int32_t>(error);
+ }
+
+ // Adapter internals
+ const gralloc_module_t* mModule;
+ uint8_t mMinorVersion;
+ alloc_device_t* mDevice;
+
+ std::shared_ptr<Descriptor> getDescriptor(
+ gralloc1_buffer_descriptor_t descriptorId);
+ std::shared_ptr<Buffer> getBuffer(buffer_handle_t bufferHandle);
+
+ static std::atomic<gralloc1_buffer_descriptor_t> sNextBufferDescriptorId;
+ std::unordered_map<gralloc1_buffer_descriptor_t,
+ std::shared_ptr<Descriptor>> mDescriptors;
+ std::unordered_map<buffer_handle_t, std::shared_ptr<Buffer>> mBuffers;
+};
+
+} // namespace android
+
+#endif
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 5443f09..62ebbd5 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -27,42 +27,41 @@
#include <utils/threads.h>
#include <utils/Singleton.h>
+#include <ui/Gralloc1.h>
#include <ui/PixelFormat.h>
-#include <hardware/gralloc.h>
-
-
namespace android {
-// ---------------------------------------------------------------------------
+class Gralloc1Loader;
class String8;
class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
{
public:
enum {
- USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER,
- USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY,
- USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN,
- USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK,
+ USAGE_SW_READ_NEVER = GRALLOC1_CONSUMER_USAGE_CPU_READ_NEVER,
+ USAGE_SW_READ_RARELY = GRALLOC1_CONSUMER_USAGE_CPU_READ,
+ USAGE_SW_READ_OFTEN = GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN,
+ USAGE_SW_READ_MASK = GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN,
- USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER,
- USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY,
- USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN,
- USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK,
+ USAGE_SW_WRITE_NEVER = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_NEVER,
+ USAGE_SW_WRITE_RARELY = GRALLOC1_PRODUCER_USAGE_CPU_WRITE,
+ USAGE_SW_WRITE_OFTEN = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
+ USAGE_SW_WRITE_MASK = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
- USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE,
- USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER,
- USAGE_HW_2D = GRALLOC_USAGE_HW_2D,
- USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK
+ USAGE_HW_TEXTURE = GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE,
+ USAGE_HW_RENDER = GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET,
+ USAGE_HW_2D = 0x00000400, // Deprecated
+ USAGE_HW_MASK = 0x00071F00, // Deprecated
};
static inline GraphicBufferAllocator& get() { return getInstance(); }
- status_t alloc(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
- buffer_handle_t* handle, uint32_t* stride);
+ status_t allocate(uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t usage, buffer_handle_t* handle, uint32_t* stride,
+ uint64_t graphicBufferId);
status_t free(buffer_handle_t handle);
@@ -86,7 +85,8 @@
GraphicBufferAllocator();
~GraphicBufferAllocator();
- alloc_device_t *mAllocDev;
+ std::unique_ptr<Gralloc1::Loader> mLoader;
+ std::unique_ptr<Gralloc1::Device> mDevice;
};
// ---------------------------------------------------------------------------
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
index 6099548..a25809c 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/include/ui/GraphicBufferMapper.h
@@ -20,13 +20,10 @@
#include <stdint.h>
#include <sys/types.h>
+#include <ui/Gralloc1.h>
+
#include <utils/Singleton.h>
-#include <hardware/gralloc.h>
-
-
-struct gralloc_module_t;
-
namespace android {
// ---------------------------------------------------------------------------
@@ -39,6 +36,7 @@
static inline GraphicBufferMapper& get() { return getInstance(); }
status_t registerBuffer(buffer_handle_t handle);
+ status_t registerBuffer(const GraphicBuffer* buffer);
status_t unregisterBuffer(buffer_handle_t handle);
@@ -59,13 +57,13 @@
status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
- // dumps information about the mapping of this handle
- void dump(buffer_handle_t handle);
-
private:
friend class Singleton<GraphicBufferMapper>;
+
GraphicBufferMapper();
- gralloc_module_t const *mAllocMod;
+
+ std::unique_ptr<Gralloc1::Loader> mLoader;
+ std::unique_ptr<Gralloc1::Device> mDevice;
};
// ---------------------------------------------------------------------------
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 7bf2d17..55ad6cc 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -312,17 +312,17 @@
IInterface::asBinder(this).get(),
parcel_fd, size, err, strerror(-err));
- int fd = dup( parcel_fd );
- ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)",
- parcel_fd, size, err, strerror(errno));
-
- int access = PROT_READ;
- if (!(flags & READ_ONLY)) {
- access |= PROT_WRITE;
- }
-
Mutex::Autolock _l(mLock);
if (mHeapId == -1) {
+ int fd = dup( parcel_fd );
+ ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)",
+ parcel_fd, size, err, strerror(errno));
+
+ int access = PROT_READ;
+ if (!(flags & READ_ONLY)) {
+ access |= PROT_WRITE;
+ }
+
mRealHeap = true;
mBase = mmap(0, size, access, MAP_SHARED, fd, offset);
if (mBase == MAP_FAILED) {
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 2c6b8e3..f5961cf 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -99,12 +99,6 @@
LOCAL_CFLAGS += -DHAVE_NO_SURFACE_FLINGER
endif
-ifeq ($(BOARD_ENABLE_GPU_PROTECTED_CONTENT),true)
- LOCAL_CFLAGS += -DENABLE_GPU_PROTECTED_CONTENT=true
-else
- LOCAL_CFLAGS += -DENABLE_GPU_PROTECTED_CONTENT=false
-endif
-
include $(BUILD_SHARED_LIBRARY)
ifeq (,$(ONE_SHOT_MAKEFILE))
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index ccbb5a2..6de98f5 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -61,6 +61,15 @@
}
}
+bool BufferQueue::ProxyConsumerListener::getFrameTimestamps(
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) const {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ return listener->getFrameTimestamps(frameNumber, outTimestamps);
+ }
+ return false;
+}
+
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
const sp<IGraphicBufferAlloc>& allocator) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 07cfb4f..3a0a283 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1405,6 +1405,22 @@
return NO_ERROR;
}
+bool BufferQueueProducer::getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ ATRACE_CALL();
+ BQ_LOGV("getFrameTimestamps, %" PRIu64, frameNumber);
+ sp<IConsumerListener> listener;
+
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+ listener = mCore->mConsumerListener;
+ }
+ if (listener != NULL) {
+ return listener->getFrameTimestamps(frameNumber, outTimestamps);
+ }
+ return false;
+}
+
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
// If we're here, it means that a producer we were connected to died.
// We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index a06c7b5..553b65c 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -135,8 +135,7 @@
bool atEnd = (cropExtLen+1) < extsLen &&
!strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen+1));
bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
- return ENABLE_GPU_PROTECTED_CONTENT &&
- (equal || atStart || atEnd || inMiddle);
+ return equal || atStart || atEnd || inMiddle;
}
static bool hasEglProtectedContent() {
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 9a0b7a4..3175b91 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -31,6 +31,7 @@
ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
ON_BUFFER_RELEASED,
ON_SIDEBAND_STREAM_CHANGED,
+ GET_FRAME_TIMESTAMPS
};
class BpConsumerListener : public BpInterface<IConsumerListener>
@@ -60,6 +61,42 @@
data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(
+ IConsumerListener::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to write token: %d", result);
+ return false;
+ }
+ result = data.writeUint64(frameNumber);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to write: %d", result);
+ return false;
+ }
+ result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to transact: %d", result);
+ return false;
+ }
+ bool found = false;
+ result = reply.readBool(&found);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to read: %d", result);
+ return false;
+ }
+ if (found) {
+ result = reply.read(*outTimestamps);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to read timestamps: %d",
+ result);
+ return false;
+ }
+ }
+ return found;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -88,6 +125,30 @@
CHECK_INTERFACE(IConsumerListener, data, reply);
onSidebandStreamChanged();
return NO_ERROR; }
+ case GET_FRAME_TIMESTAMPS: {
+ CHECK_INTERFACE(IConsumerListener, data, reply);
+ uint64_t frameNumber = 0;
+ status_t result = data.readUint64(&frameNumber);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to read: %d", result);
+ return result;
+ }
+ FrameTimestamps timestamps;
+ bool found = getFrameTimestamps(frameNumber, ×tamps);
+ result = reply->writeBool(found);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to write: %d", result);
+ return result;
+ }
+ if (found) {
+ result = reply->write(timestamps);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to write timestamps: %d", result);
+ return result;
+ }
+ }
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 81e9407..ab83317 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -55,6 +55,7 @@
SET_AUTO_REFRESH,
SET_DEQUEUE_TIMEOUT,
GET_LAST_QUEUED_BUFFER,
+ GET_FRAME_TIMESTAMPS
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -418,6 +419,42 @@
*outFence = fence;
return result;
}
+
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(
+ IGraphicBufferProducer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to write token: %d", result);
+ return false;
+ }
+ result = data.writeUint64(frameNumber);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to write: %d", result);
+ return false;
+ }
+ result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to transact: %d", result);
+ return false;
+ }
+ bool found = false;
+ result = reply.readBool(&found);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to read: %d", result);
+ return false;
+ }
+ if (found) {
+ result = reply.read(*outTimestamps);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to read timestamps: %d",
+ result);
+ return false;
+ }
+ }
+ return found;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -659,6 +696,30 @@
}
return NO_ERROR;
}
+ case GET_FRAME_TIMESTAMPS: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ uint64_t frameNumber = 0;
+ status_t result = data.readUint64(&frameNumber);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to read: %d", result);
+ return result;
+ }
+ FrameTimestamps timestamps;
+ bool found = getFrameTimestamps(frameNumber, ×tamps);
+ result = reply->writeBool(found);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to write: %d", result);
+ return result;
+ }
+ if (found) {
+ result = reply->write(timestamps);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to write timestamps: %d", result);
+ return result;
+ }
+ }
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9d130cd..4739ca4 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -133,6 +133,39 @@
outTransformMatrix);
}
+bool Surface::getFrameTimestamps(uint64_t frameNumber, nsecs_t* outPostedTime,
+ nsecs_t* outAcquireTime, nsecs_t* outRefreshStartTime,
+ nsecs_t* outGlCompositionDoneTime, nsecs_t* outDisplayRetireTime,
+ nsecs_t* outReleaseTime) {
+ ATRACE_CALL();
+
+ FrameTimestamps timestamps;
+ bool found = mGraphicBufferProducer->getFrameTimestamps(frameNumber,
+ ×tamps);
+ if (found) {
+ if (outPostedTime) {
+ *outPostedTime = timestamps.postedTime;
+ }
+ if (outAcquireTime) {
+ *outAcquireTime = timestamps.acquireTime;
+ }
+ if (outRefreshStartTime) {
+ *outRefreshStartTime = timestamps.refreshStartTime;
+ }
+ if (outGlCompositionDoneTime) {
+ *outGlCompositionDoneTime = timestamps.glCompositionDoneTime;
+ }
+ if (outDisplayRetireTime) {
+ *outDisplayRetireTime = timestamps.displayRetireTime;
+ }
+ if (outReleaseTime) {
+ *outReleaseTime = timestamps.releaseTime;
+ }
+ return true;
+ }
+ return false;
+}
+
int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
Surface* c = getSelf(window);
return c->setSwapInterval(interval);
@@ -617,6 +650,9 @@
case NATIVE_WINDOW_SET_AUTO_REFRESH:
res = dispatchSetAutoRefresh(args);
break;
+ case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
+ res = dispatchGetFrameTimestamps(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -737,6 +773,20 @@
return setAutoRefresh(autoRefresh);
}
+int Surface::dispatchGetFrameTimestamps(va_list args) {
+ uint32_t framesAgo = va_arg(args, uint32_t);
+ nsecs_t* outPostedTime = va_arg(args, int64_t*);
+ nsecs_t* outAcquireTime = va_arg(args, int64_t*);
+ nsecs_t* outRefreshStartTime = va_arg(args, int64_t*);
+ nsecs_t* outGlCompositionDoneTime = va_arg(args, int64_t*);
+ nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
+ nsecs_t* outReleaseTime = va_arg(args, int64_t*);
+ bool ret = getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
+ outPostedTime, outAcquireTime, outRefreshStartTime,
+ outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
+ return ret ? NO_ERROR : BAD_VALUE;
+}
+
int Surface::connect(int api) {
static sp<IProducerListener> listener = new DummyProducerListener();
return connect(api, listener);
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index ee6c093..e690ede 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -17,7 +17,7 @@
LOCAL_CLANG := true
LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror
-LOCAL_SANITIZE := integer
+# LOCAL_SANITIZE := integer
# The static constructors and destructors in this library have not been noted to
# introduce significant overheads
@@ -37,6 +37,8 @@
LOCAL_SRC_FILES := \
Fence.cpp \
FrameStats.cpp \
+ Gralloc1.cpp \
+ Gralloc1On0Adapter.cpp \
GraphicBuffer.cpp \
GraphicBufferAllocator.cpp \
GraphicBufferMapper.cpp \
diff --git a/libs/ui/Gralloc1.cpp b/libs/ui/Gralloc1.cpp
new file mode 100644
index 0000000..4c73ce4
--- /dev/null
+++ b/libs/ui/Gralloc1.cpp
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+
+#include <ui/Gralloc1.h>
+
+#include <vector>
+
+#undef LOG_TAG
+#define LOG_TAG GRALLOC1_LOG_TAG
+
+namespace android {
+
+namespace Gralloc1 {
+
+Descriptor::~Descriptor()
+{
+ int32_t intError = mShimDevice.mFunctions.destroyDescriptor(
+ mShimDevice.mDevice, mDeviceId);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("destroyDescriptor failed: %d", intError);
+ }
+}
+
+gralloc1_error_t Descriptor::setDimensions(uint32_t width, uint32_t height)
+{
+ int32_t intError = mShimDevice.mFunctions.setDimensions(mShimDevice.mDevice,
+ mDeviceId, width, height);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error != GRALLOC1_ERROR_NONE) {
+ return error;
+ }
+ mWidth = width;
+ mHeight = height;
+ return error;
+}
+
+template <typename ApiType>
+struct Setter {
+ typedef int32_t (*Type)(gralloc1_device_t*, gralloc1_buffer_descriptor_t,
+ ApiType);
+};
+
+template <typename ApiType, typename ValueType>
+static inline gralloc1_error_t setHelper(
+ typename Setter<ApiType>::Type setter, gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t id, ValueType newValue,
+ ValueType* cacheVariable)
+{
+ int32_t intError = setter(device, id, static_cast<ApiType>(newValue));
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error != GRALLOC1_ERROR_NONE) {
+ return error;
+ }
+ *cacheVariable = newValue;
+ return error;
+}
+
+gralloc1_error_t Descriptor::setFormat(android_pixel_format_t format)
+{
+ return setHelper<int32_t>(mShimDevice.mFunctions.setFormat.pfn,
+ mShimDevice.mDevice, mDeviceId, format, &mFormat);
+}
+
+gralloc1_error_t Descriptor::setProducerUsage(gralloc1_producer_usage_t usage)
+{
+ return setHelper<uint64_t>(mShimDevice.mFunctions.setProducerUsage.pfn,
+ mShimDevice.mDevice, mDeviceId, usage, &mProducerUsage);
+}
+
+gralloc1_error_t Descriptor::setConsumerUsage(gralloc1_consumer_usage_t usage)
+{
+ return setHelper<uint64_t>(mShimDevice.mFunctions.setConsumerUsage.pfn,
+ mShimDevice.mDevice, mDeviceId, usage, &mConsumerUsage);
+}
+
+Device::Device(gralloc1_device_t* device)
+ : mDevice(device),
+ mCapabilities(loadCapabilities()),
+ mFunctions()
+{
+ if (!loadFunctions()) {
+ ALOGE("Failed to load a required function, aborting");
+ abort();
+ }
+}
+
+bool Device::hasCapability(gralloc1_capability_t capability) const
+{
+ return mCapabilities.count(capability) > 0;
+}
+
+std::string Device::dump()
+{
+ uint32_t length = 0;
+ mFunctions.dump(mDevice, &length, nullptr);
+
+ std::vector<char> output;
+ output.resize(length);
+ mFunctions.dump(mDevice, &length, output.data());
+
+ return std::string(output.cbegin(), output.cend());
+}
+
+std::shared_ptr<Descriptor> Device::createDescriptor()
+{
+ gralloc1_buffer_descriptor_t descriptorId;
+ int32_t intError = mFunctions.createDescriptor(mDevice, &descriptorId);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error != GRALLOC1_ERROR_NONE) {
+ return nullptr;
+ }
+ auto descriptor = std::make_shared<Descriptor>(*this, descriptorId);
+ return descriptor;
+}
+
+gralloc1_error_t Device::getStride(buffer_handle_t buffer, uint32_t* outStride)
+{
+ int32_t intError = mFunctions.getStride(mDevice, buffer, outStride);
+ return static_cast<gralloc1_error_t>(intError);
+}
+
+static inline bool allocationSucceded(gralloc1_error_t error)
+{
+ return error == GRALLOC1_ERROR_NONE || error == GRALLOC1_ERROR_NOT_SHARED;
+}
+
+gralloc1_error_t Device::allocate(
+ const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
+ std::vector<buffer_handle_t>* outBuffers)
+{
+ if (mFunctions.allocate.pfn == nullptr) {
+ // Allocation is not supported on this device
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+
+ std::vector<gralloc1_buffer_descriptor_t> deviceIds;
+ for (const auto& descriptor : descriptors) {
+ deviceIds.emplace_back(descriptor->getDeviceId());
+ }
+
+ std::vector<buffer_handle_t> buffers(descriptors.size());
+ int32_t intError = mFunctions.allocate(mDevice,
+ static_cast<uint32_t>(descriptors.size()), deviceIds.data(),
+ buffers.data());
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (allocationSucceded(error)) {
+ *outBuffers = std::move(buffers);
+ }
+
+ return error;
+}
+
+gralloc1_error_t Device::allocate(
+ const std::shared_ptr<const Descriptor>& descriptor,
+ gralloc1_backing_store_t id, buffer_handle_t* outBuffer)
+{
+ gralloc1_error_t error = GRALLOC1_ERROR_NONE;
+
+ if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+ buffer_handle_t buffer = nullptr;
+ int32_t intError = mFunctions.allocateWithId(mDevice,
+ descriptor->getDeviceId(), id, &buffer);
+ error = static_cast<gralloc1_error_t>(intError);
+ if (allocationSucceded(error)) {
+ *outBuffer = buffer;
+ }
+ } else {
+ std::vector<std::shared_ptr<const Descriptor>> descriptors;
+ descriptors.emplace_back(descriptor);
+ std::vector<buffer_handle_t> buffers;
+ error = allocate(descriptors, &buffers);
+ if (allocationSucceded(error)) {
+ *outBuffer = buffers[0];
+ }
+ }
+
+ return error;
+}
+
+gralloc1_error_t Device::retain(buffer_handle_t buffer)
+{
+ int32_t intError = mFunctions.retain(mDevice, buffer);
+ return static_cast<gralloc1_error_t>(intError);
+}
+
+gralloc1_error_t Device::retain(const GraphicBuffer* buffer)
+{
+ if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+ return mFunctions.retainGraphicBuffer(mDevice, buffer);
+ } else {
+ return retain(buffer->getNativeBuffer()->handle);
+ }
+}
+
+gralloc1_error_t Device::release(buffer_handle_t buffer)
+{
+ int32_t intError = mFunctions.release(mDevice, buffer);
+ return static_cast<gralloc1_error_t>(intError);
+}
+
+gralloc1_error_t Device::getNumFlexPlanes(buffer_handle_t buffer,
+ uint32_t* outNumPlanes)
+{
+ uint32_t numPlanes = 0;
+ int32_t intError = mFunctions.getNumFlexPlanes(mDevice, buffer, &numPlanes);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outNumPlanes = numPlanes;
+ }
+ return error;
+}
+
+gralloc1_error_t Device::lock(buffer_handle_t buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t* accessRegion, void** outData,
+ const sp<Fence>& acquireFence)
+{
+ ALOGV("Calling lock(%p)", buffer);
+ return lockHelper(mFunctions.lock.pfn, buffer, producerUsage,
+ consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::lockFlex(buffer_handle_t buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t* accessRegion,
+ struct android_flex_layout* outData,
+ const sp<Fence>& acquireFence)
+{
+ ALOGV("Calling lockFlex(%p)", buffer);
+ return lockHelper(mFunctions.lockFlex.pfn, buffer, producerUsage,
+ consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::lockYCbCr(buffer_handle_t buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t* accessRegion,
+ struct android_ycbcr* outData,
+ const sp<Fence>& acquireFence)
+{
+ ALOGV("Calling lockYCbCr(%p)", buffer);
+ return lockHelper(mFunctions.lockYCbCr.pfn, buffer, producerUsage,
+ consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::unlock(buffer_handle_t buffer, sp<Fence>* outFence)
+{
+ int32_t fenceFd = -1;
+ int32_t intError = mFunctions.unlock(mDevice, buffer, &fenceFd);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outFence = new Fence(fenceFd);
+ }
+ return error;
+}
+
+std::unordered_set<gralloc1_capability_t> Device::loadCapabilities()
+{
+ std::vector<int32_t> intCapabilities;
+ uint32_t numCapabilities = 0;
+ mDevice->getCapabilities(mDevice, &numCapabilities, nullptr);
+
+ intCapabilities.resize(numCapabilities);
+ mDevice->getCapabilities(mDevice, &numCapabilities, intCapabilities.data());
+
+ std::unordered_set<gralloc1_capability_t> capabilities;
+ for (const auto intCapability : intCapabilities) {
+ capabilities.emplace(static_cast<gralloc1_capability_t>(intCapability));
+ }
+ return capabilities;
+}
+
+bool Device::loadFunctions()
+{
+ // Functions which must always be present
+ if (!mFunctions.dump.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.createDescriptor.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.destroyDescriptor.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.setConsumerUsage.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.setDimensions.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.setFormat.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.setProducerUsage.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.getBackingStore.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.getConsumerUsage.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.getDimensions.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.getFormat.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.getProducerUsage.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.getStride.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.retain.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.release.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.getNumFlexPlanes.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.lock.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.lockFlex.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.unlock.load(mDevice, true)) {
+ return false;
+ }
+
+ if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+ // These should always be present on the adapter
+ if (!mFunctions.retainGraphicBuffer.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.lockYCbCr.load(mDevice, true)) {
+ return false;
+ }
+
+ // allocateWithId may not be present if we're only able to map in this
+ // process
+ mFunctions.allocateWithId.load(mDevice, false);
+ } else {
+ // allocate may not be present if we're only able to map in this process
+ mFunctions.allocate.load(mDevice, false);
+ }
+
+ return true;
+}
+
+std::unique_ptr<Gralloc1On0Adapter> Loader::mAdapter = nullptr;
+
+Loader::Loader()
+ : mDevice(nullptr)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ uint8_t majorVersion = (module->module_api_version >> 8) & 0xFF;
+ uint8_t minorVersion = module->module_api_version & 0xFF;
+ gralloc1_device_t* device = nullptr;
+ if (majorVersion == 1) {
+ gralloc1_open(module, &device);
+ } else {
+ if (!mAdapter) {
+ mAdapter = std::make_unique<Gralloc1On0Adapter>(module);
+ }
+ device = mAdapter->getDevice();
+ }
+ mDevice = std::make_unique<Gralloc1::Device>(device);
+}
+
+Loader::~Loader() {}
+
+std::unique_ptr<Device> Loader::getDevice()
+{
+ return std::move(mDevice);
+}
+
+} // namespace android::Gralloc1
+
+} // namespace android
diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
new file mode 100644
index 0000000..6e69df1
--- /dev/null
+++ b/libs/ui/Gralloc1On0Adapter.cpp
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "Gralloc1On0Adapter"
+//#define LOG_NDEBUG 0
+
+#include <hardware/gralloc.h>
+
+#include <ui/Gralloc1On0Adapter.h>
+
+#include <utils/Log.h>
+
+#include <inttypes.h>
+
+template <typename PFN, typename T>
+static gralloc1_function_pointer_t asFP(T function)
+{
+ static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+ return reinterpret_cast<gralloc1_function_pointer_t>(function);
+}
+
+namespace android {
+
+Gralloc1On0Adapter::Gralloc1On0Adapter(const hw_module_t* module)
+ : mModule(reinterpret_cast<const gralloc_module_t*>(module)),
+ mMinorVersion(mModule->common.module_api_version & 0xFF),
+ mDevice(nullptr)
+{
+ ALOGV("Constructing");
+ getCapabilities = getCapabilitiesHook;
+ getFunction = getFunctionHook;
+ int error = ::gralloc_open(&(mModule->common), &mDevice);
+ if (error) {
+ ALOGE("Failed to open gralloc0 module: %d", error);
+ }
+ ALOGV("Opened gralloc0 device %p", mDevice);
+}
+
+Gralloc1On0Adapter::~Gralloc1On0Adapter()
+{
+ ALOGV("Destructing");
+ if (mDevice) {
+ ALOGV("Closing gralloc0 device %p", mDevice);
+ ::gralloc_close(mDevice);
+ }
+}
+
+void Gralloc1On0Adapter::doGetCapabilities(uint32_t* outCount,
+ int32_t* outCapabilities)
+{
+ if (outCapabilities == nullptr) {
+ *outCount = 1;
+ return;
+ }
+ if (*outCount >= 1) {
+ *outCapabilities = GRALLOC1_CAPABILITY_ON_ADAPTER;
+ *outCount = 1;
+ }
+}
+
+gralloc1_function_pointer_t Gralloc1On0Adapter::doGetFunction(
+ int32_t intDescriptor)
+{
+ constexpr auto lastDescriptor =
+ static_cast<int32_t>(GRALLOC1_LAST_ADAPTER_FUNCTION);
+ if (intDescriptor < 0 || intDescriptor > lastDescriptor) {
+ ALOGE("Invalid function descriptor");
+ return nullptr;
+ }
+
+ auto descriptor =
+ static_cast<gralloc1_function_descriptor_t>(intDescriptor);
+ switch (descriptor) {
+ case GRALLOC1_FUNCTION_DUMP:
+ return asFP<GRALLOC1_PFN_DUMP>(dumpHook);
+ case GRALLOC1_FUNCTION_CREATE_DESCRIPTOR:
+ return asFP<GRALLOC1_PFN_CREATE_DESCRIPTOR>(createDescriptorHook);
+ case GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR:
+ return asFP<GRALLOC1_PFN_DESTROY_DESCRIPTOR>(destroyDescriptorHook);
+ case GRALLOC1_FUNCTION_SET_CONSUMER_USAGE:
+ return asFP<GRALLOC1_PFN_SET_CONSUMER_USAGE>(setConsumerUsageHook);
+ case GRALLOC1_FUNCTION_SET_DIMENSIONS:
+ return asFP<GRALLOC1_PFN_SET_DIMENSIONS>(setDimensionsHook);
+ case GRALLOC1_FUNCTION_SET_FORMAT:
+ return asFP<GRALLOC1_PFN_SET_FORMAT>(setFormatHook);
+ case GRALLOC1_FUNCTION_SET_PRODUCER_USAGE:
+ return asFP<GRALLOC1_PFN_SET_PRODUCER_USAGE>(setProducerUsageHook);
+ case GRALLOC1_FUNCTION_GET_BACKING_STORE:
+ return asFP<GRALLOC1_PFN_GET_BACKING_STORE>(
+ bufferHook<decltype(&Buffer::getBackingStore),
+ &Buffer::getBackingStore, gralloc1_backing_store_t*>);
+ case GRALLOC1_FUNCTION_GET_CONSUMER_USAGE:
+ return asFP<GRALLOC1_PFN_GET_CONSUMER_USAGE>(getConsumerUsageHook);
+ case GRALLOC1_FUNCTION_GET_DIMENSIONS:
+ return asFP<GRALLOC1_PFN_GET_DIMENSIONS>(
+ bufferHook<decltype(&Buffer::getDimensions),
+ &Buffer::getDimensions, uint32_t*, uint32_t*>);
+ case GRALLOC1_FUNCTION_GET_FORMAT:
+ return asFP<GRALLOC1_PFN_GET_FORMAT>(
+ bufferHook<decltype(&Buffer::getFormat),
+ &Buffer::getFormat, int32_t*>);
+ case GRALLOC1_FUNCTION_GET_PRODUCER_USAGE:
+ return asFP<GRALLOC1_PFN_GET_PRODUCER_USAGE>(getProducerUsageHook);
+ case GRALLOC1_FUNCTION_GET_STRIDE:
+ return asFP<GRALLOC1_PFN_GET_STRIDE>(
+ bufferHook<decltype(&Buffer::getStride),
+ &Buffer::getStride, uint32_t*>);
+ case GRALLOC1_FUNCTION_ALLOCATE:
+ // Not provided, since we'll use ALLOCATE_WITH_ID
+ return nullptr;
+ case GRALLOC1_FUNCTION_ALLOCATE_WITH_ID:
+ if (mDevice != nullptr) {
+ return asFP<GRALLOC1_PFN_ALLOCATE_WITH_ID>(allocateWithIdHook);
+ } else {
+ return nullptr;
+ }
+ case GRALLOC1_FUNCTION_RETAIN:
+ return asFP<GRALLOC1_PFN_RETAIN>(
+ managementHook<&Gralloc1On0Adapter::retain>);
+ case GRALLOC1_FUNCTION_RELEASE:
+ return asFP<GRALLOC1_PFN_RELEASE>(
+ managementHook<&Gralloc1On0Adapter::release>);
+ case GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER:
+ return asFP<GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER>(
+ retainGraphicBufferHook);
+ case GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES:
+ return asFP<GRALLOC1_PFN_GET_NUM_FLEX_PLANES>(
+ bufferHook<decltype(&Buffer::getNumFlexPlanes),
+ &Buffer::getNumFlexPlanes, uint32_t*>);
+ case GRALLOC1_FUNCTION_LOCK:
+ return asFP<GRALLOC1_PFN_LOCK>(
+ lockHook<void*, &Gralloc1On0Adapter::lock>);
+ case GRALLOC1_FUNCTION_LOCK_FLEX:
+ return asFP<GRALLOC1_PFN_LOCK_FLEX>(
+ lockHook<struct android_flex_layout,
+ &Gralloc1On0Adapter::lockFlex>);
+ case GRALLOC1_FUNCTION_LOCK_YCBCR:
+ return asFP<GRALLOC1_PFN_LOCK_YCBCR>(
+ lockHook<struct android_ycbcr,
+ &Gralloc1On0Adapter::lockYCbCr>);
+ case GRALLOC1_FUNCTION_UNLOCK:
+ return asFP<GRALLOC1_PFN_UNLOCK>(unlockHook);
+ case GRALLOC1_FUNCTION_INVALID:
+ ALOGE("Invalid function descriptor");
+ return nullptr;
+ }
+
+ ALOGE("Unknown function descriptor: %d", intDescriptor);
+ return nullptr;
+}
+
+void Gralloc1On0Adapter::dump(uint32_t* outSize, char* outBuffer)
+{
+ ALOGV("dump(%u (%p), %p", outSize ? *outSize : 0, outSize, outBuffer);
+
+ if (!mDevice->dump) {
+ // dump is optional on gralloc0 implementations
+ *outSize = 0;
+ return;
+ }
+
+ if (!outBuffer) {
+ constexpr int32_t BUFFER_LENGTH = 4096;
+ char buffer[BUFFER_LENGTH] = {};
+ mDevice->dump(mDevice, buffer, BUFFER_LENGTH);
+ buffer[BUFFER_LENGTH - 1] = 0; // Ensure the buffer is null-terminated
+ size_t actualLength = std::strlen(buffer);
+ mCachedDump.resize(actualLength);
+ std::copy_n(buffer, actualLength, mCachedDump.begin());
+ *outSize = static_cast<uint32_t>(actualLength);
+ } else {
+ *outSize = std::min(*outSize,
+ static_cast<uint32_t>(mCachedDump.size()));
+ outBuffer = std::copy_n(mCachedDump.cbegin(), *outSize, outBuffer);
+ }
+}
+
+gralloc1_error_t Gralloc1On0Adapter::createDescriptor(
+ gralloc1_buffer_descriptor_t* outDescriptor)
+{
+ auto descriptorId = sNextBufferDescriptorId++;
+ mDescriptors.emplace(descriptorId,
+ std::make_shared<Descriptor>(this, descriptorId));
+
+ ALOGV("Created descriptor %" PRIu64, descriptorId);
+
+ *outDescriptor = descriptorId;
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::destroyDescriptor(
+ gralloc1_buffer_descriptor_t descriptor)
+{
+ ALOGV("Destroying descriptor %" PRIu64, descriptor);
+
+ if (mDescriptors.count(descriptor) == 0) {
+ return GRALLOC1_ERROR_BAD_DESCRIPTOR;
+ }
+
+ mDescriptors.erase(descriptor);
+ return GRALLOC1_ERROR_NONE;
+}
+
+Gralloc1On0Adapter::Buffer::Buffer(buffer_handle_t handle,
+ gralloc1_backing_store_t store, const Descriptor& descriptor,
+ uint32_t stride, bool wasAllocated)
+ : mHandle(handle),
+ mReferenceCount(1),
+ mStore(store),
+ mDescriptor(descriptor),
+ mStride(stride),
+ mWasAllocated(wasAllocated) {}
+
+gralloc1_error_t Gralloc1On0Adapter::allocate(
+ const std::shared_ptr<Descriptor>& descriptor,
+ gralloc1_backing_store_t store,
+ buffer_handle_t* outBufferHandle)
+{
+ ALOGV("allocate(%" PRIu64 ", %#" PRIx64 ")", descriptor->id, store);
+
+ // If this function is being called, it's because we handed out its function
+ // pointer, which only occurs when mDevice has been loaded successfully and
+ // we are permitted to allocate
+
+ int usage = static_cast<int>(descriptor->producerUsage) |
+ static_cast<int>(descriptor->consumerUsage);
+ buffer_handle_t handle = nullptr;
+ int stride = 0;
+ ALOGV("Calling alloc(%p, %u, %u, %i, %u)", mDevice, descriptor->width,
+ descriptor->height, descriptor->format, usage);
+ auto error = mDevice->alloc(mDevice,
+ static_cast<int>(descriptor->width),
+ static_cast<int>(descriptor->height), descriptor->format,
+ usage, &handle, &stride);
+ if (error != 0) {
+ ALOGE("gralloc0 allocation failed: %d (%s)", error,
+ strerror(-error));
+ return GRALLOC1_ERROR_NO_RESOURCES;
+ }
+
+ *outBufferHandle = handle;
+ auto buffer = std::make_shared<Buffer>(handle, store, *descriptor, stride,
+ true);
+ mBuffers.emplace(handle, std::move(buffer));
+
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::allocateWithIdHook(
+ gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptorId,
+ gralloc1_backing_store_t store, buffer_handle_t* outBuffer)
+{
+ auto adapter = getAdapter(device);
+
+ auto descriptor = adapter->getDescriptor(descriptorId);
+ if (!descriptor) {
+ return GRALLOC1_ERROR_BAD_DESCRIPTOR;
+ }
+
+ buffer_handle_t bufferHandle = nullptr;
+ auto error = adapter->allocate(descriptor, store, &bufferHandle);
+ if (error != GRALLOC1_ERROR_NONE) {
+ return error;
+ }
+
+ *outBuffer = bufferHandle;
+ return error;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::retain(
+ const std::shared_ptr<Buffer>& buffer)
+{
+ buffer->retain();
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::release(
+ const std::shared_ptr<Buffer>& buffer)
+{
+ if (!buffer->release()) {
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ buffer_handle_t handle = buffer->getHandle();
+ if (buffer->wasAllocated()) {
+ ALOGV("Calling free(%p)", handle);
+ int result = mDevice->free(mDevice, handle);
+ if (result != 0) {
+ ALOGE("gralloc0 free failed: %d", result);
+ }
+ } else {
+ ALOGV("Calling unregisterBuffer(%p)", handle);
+ int result = mModule->unregisterBuffer(mModule, handle);
+ if (result != 0) {
+ ALOGE("gralloc0 unregister failed: %d", result);
+ }
+ }
+ mBuffers.erase(handle);
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::retain(
+ const android::GraphicBuffer* graphicBuffer)
+{
+ ALOGV("retainGraphicBuffer(%p, %#" PRIx64 ")",
+ graphicBuffer->getNativeBuffer()->handle, graphicBuffer->getId());
+
+ buffer_handle_t handle = graphicBuffer->getNativeBuffer()->handle;
+ if (mBuffers.count(handle) != 0) {
+ mBuffers[handle]->retain();
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ ALOGV("Calling registerBuffer(%p)", handle);
+ int result = mModule->registerBuffer(mModule, handle);
+ if (result != 0) {
+ ALOGE("gralloc0 register failed: %d", result);
+ return GRALLOC1_ERROR_NO_RESOURCES;
+ }
+
+ Descriptor descriptor{this, sNextBufferDescriptorId++};
+ descriptor.setDimensions(graphicBuffer->getWidth(),
+ graphicBuffer->getHeight());
+ descriptor.setFormat(graphicBuffer->getPixelFormat());
+ descriptor.setProducerUsage(
+ static_cast<gralloc1_producer_usage_t>(graphicBuffer->getUsage()));
+ descriptor.setConsumerUsage(
+ static_cast<gralloc1_consumer_usage_t>(graphicBuffer->getUsage()));
+ auto buffer = std::make_shared<Buffer>(handle,
+ static_cast<gralloc1_backing_store_t>(graphicBuffer->getId()),
+ descriptor, graphicBuffer->getStride(), false);
+ mBuffers.emplace(handle, std::move(buffer));
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lock(
+ const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion, void** outData,
+ const sp<Fence>& acquireFence)
+{
+ if (mMinorVersion >= 3) {
+ int result = mModule->lockAsync(mModule, buffer->getHandle(),
+ static_cast<int32_t>(producerUsage | consumerUsage),
+ accessRegion.left, accessRegion.top, accessRegion.width,
+ accessRegion.height, outData, acquireFence->dup());
+ if (result != 0) {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ } else {
+ acquireFence->waitForever("Gralloc1On0Adapter::lock");
+ int result = mModule->lock(mModule, buffer->getHandle(),
+ static_cast<int32_t>(producerUsage | consumerUsage),
+ accessRegion.left, accessRegion.top, accessRegion.width,
+ accessRegion.height, outData);
+ ALOGV("gralloc0 lock returned %d", result);
+ if (result != 0) {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ }
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lockFlex(
+ const std::shared_ptr<Buffer>& /*buffer*/,
+ gralloc1_producer_usage_t /*producerUsage*/,
+ gralloc1_consumer_usage_t /*consumerUsage*/,
+ const gralloc1_rect_t& /*accessRegion*/,
+ struct android_flex_layout* /*outData*/,
+ const sp<Fence>& /*acquireFence*/)
+{
+ // TODO
+ return GRALLOC1_ERROR_UNSUPPORTED;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lockYCbCr(
+ const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion, struct android_ycbcr* outData,
+ const sp<Fence>& acquireFence)
+{
+ if (mMinorVersion >= 3 && mModule->lockAsync_ycbcr) {
+ int result = mModule->lockAsync_ycbcr(mModule, buffer->getHandle(),
+ static_cast<int>(producerUsage | consumerUsage),
+ accessRegion.left, accessRegion.top, accessRegion.width,
+ accessRegion.height, outData, acquireFence->dup());
+ if (result != 0) {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ } else if (mModule->lock_ycbcr) {
+ acquireFence->waitForever("Gralloc1On0Adapter::lockYCbCr");
+ int result = mModule->lock_ycbcr(mModule, buffer->getHandle(),
+ static_cast<int>(producerUsage | consumerUsage),
+ accessRegion.left, accessRegion.top, accessRegion.width,
+ accessRegion.height, outData);
+ ALOGV("gralloc0 lockYCbCr returned %d", result);
+ if (result != 0) {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ } else {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::unlock(
+ const std::shared_ptr<Buffer>& buffer,
+ sp<Fence>* outReleaseFence)
+{
+ if (mMinorVersion >= 3) {
+ int fenceFd = -1;
+ int result = mModule->unlockAsync(mModule, buffer->getHandle(),
+ &fenceFd);
+ if (result != 0) {
+ close(fenceFd);
+ ALOGE("gralloc0 unlockAsync failed: %d", result);
+ } else {
+ *outReleaseFence = new Fence(fenceFd);
+ }
+ } else {
+ int result = mModule->unlock(mModule, buffer->getHandle());
+ if (result != 0) {
+ ALOGE("gralloc0 unlock failed: %d", result);
+ }
+ }
+ return GRALLOC1_ERROR_NONE;
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Descriptor>
+Gralloc1On0Adapter::getDescriptor(gralloc1_buffer_descriptor_t descriptorId)
+{
+ if (mDescriptors.count(descriptorId) == 0) {
+ return nullptr;
+ }
+
+ return mDescriptors[descriptorId];
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Buffer> Gralloc1On0Adapter::getBuffer(
+ buffer_handle_t bufferHandle)
+{
+ if (mBuffers.count(bufferHandle) == 0) {
+ return nullptr;
+ }
+
+ return mBuffers[bufferHandle];
+}
+
+std::atomic<gralloc1_buffer_descriptor_t>
+ Gralloc1On0Adapter::sNextBufferDescriptorId(1);
+
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 4fe0946..f28af6e 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -169,8 +169,8 @@
{
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
uint32_t outStride = 0;
- status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage,
- &handle, &outStride);
+ status_t err = allocator.allocate(inWidth, inHeight, inFormat, inUsage,
+ &handle, &outStride, mId);
if (err == NO_ERROR) {
width = static_cast<int>(inWidth);
height = static_cast<int>(inHeight);
@@ -390,7 +390,7 @@
mOwner = ownHandle;
if (handle != 0) {
- status_t err = mBufferMapper.registerBuffer(handle);
+ status_t err = mBufferMapper.registerBuffer(this);
if (err != NO_ERROR) {
width = height = stride = format = usage = 0;
handle = NULL;
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 9b265af..3b83fb6 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -25,6 +25,7 @@
#include <utils/Trace.h>
#include <ui/GraphicBufferAllocator.h>
+#include <ui/Gralloc1On0Adapter.h>
namespace android {
// ---------------------------------------------------------------------------
@@ -36,20 +37,10 @@
GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
GraphicBufferAllocator::GraphicBufferAllocator()
- : mAllocDev(0)
-{
- hw_module_t const* module;
- int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
- ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
- if (err == 0) {
- gralloc_open(module, &mAllocDev);
- }
-}
+ : mLoader(std::make_unique<Gralloc1::Loader>()),
+ mDevice(mLoader->getDevice()) {}
-GraphicBufferAllocator::~GraphicBufferAllocator()
-{
- gralloc_close(mAllocDev);
-}
+GraphicBufferAllocator::~GraphicBufferAllocator() {}
void GraphicBufferAllocator::dump(String8& result) const
{
@@ -77,10 +68,8 @@
}
snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f);
result.append(buffer);
- if (mAllocDev->common.version >= 1 && mAllocDev->dump) {
- mAllocDev->dump(mAllocDev, buffer, SIZE);
- result.append(buffer);
- }
+ std::string deviceDump = mDevice->dump();
+ result.append(deviceDump.c_str(), deviceDump.size());
}
void GraphicBufferAllocator::dumpToSystemLog()
@@ -90,9 +79,9 @@
ALOGD("%s", s.string());
}
-status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
+status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage, buffer_handle_t* handle,
- uint32_t* stride)
+ uint32_t* stride, uint64_t graphicBufferId)
{
ATRACE_CALL();
@@ -101,22 +90,46 @@
if (!width || !height)
width = height = 1;
- // we have a h/w allocator and h/w buffer is requested
- status_t err;
-
// Filter out any usage bits that should not be passed to the gralloc module
usage &= GRALLOC_USAGE_ALLOC_MASK;
- int outStride = 0;
- err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
- static_cast<int>(height), format, static_cast<int>(usage), handle,
- &outStride);
- *stride = static_cast<uint32_t>(outStride);
+ auto descriptor = mDevice->createDescriptor();
+ auto error = descriptor->setDimensions(width, height);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set dimensions to (%u, %u): %d", width, height, error);
+ return BAD_VALUE;
+ }
+ error = descriptor->setFormat(static_cast<android_pixel_format_t>(format));
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set format to %d: %d", format, error);
+ return BAD_VALUE;
+ }
+ error = descriptor->setProducerUsage(
+ static_cast<gralloc1_producer_usage_t>(usage));
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set producer usage to %u: %d", usage, error);
+ return BAD_VALUE;
+ }
+ error = descriptor->setConsumerUsage(
+ static_cast<gralloc1_consumer_usage_t>(usage));
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set consumer usage to %u: %d", usage, error);
+ return BAD_VALUE;
+ }
- ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
- width, height, format, usage, err, strerror(-err));
+ error = mDevice->allocate(descriptor, graphicBufferId, handle);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to allocate (%u x %u) format %d usage %u: %d",
+ width, height, format, usage, error);
+ return NO_MEMORY;
+ }
- if (err == NO_ERROR) {
+ error = mDevice->getStride(*handle, stride);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGW("Failed to get stride from buffer: %d", error);
+ }
+
+ if (error == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
uint32_t bpp = bytesPerPixel(format);
@@ -130,24 +143,23 @@
list.add(*handle, rec);
}
- return err;
+ return NO_ERROR;
}
status_t GraphicBufferAllocator::free(buffer_handle_t handle)
{
ATRACE_CALL();
- status_t err;
- err = mAllocDev->free(mAllocDev, handle);
-
- ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
- if (err == NO_ERROR) {
- Mutex::Autolock _l(sLock);
- KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
- list.removeItem(handle);
+ auto error = mDevice->release(handle);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to free buffer: %d", error);
}
- return err;
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ list.removeItem(handle);
+
+ return NO_ERROR;
}
// ---------------------------------------------------------------------------
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 90a1c11..481d43c 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "GraphicBufferMapper"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
#include <stdint.h>
#include <errno.h>
@@ -31,11 +32,11 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <ui/Gralloc1On0Adapter.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/Rect.h>
-#include <hardware/gralloc.h>
-
+#include <system/graphics.h>
namespace android {
// ---------------------------------------------------------------------------
@@ -43,151 +44,247 @@
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
GraphicBufferMapper::GraphicBufferMapper()
- : mAllocMod(0)
-{
- hw_module_t const* module;
- int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
- ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
- if (err == 0) {
- mAllocMod = reinterpret_cast<gralloc_module_t const *>(module);
- }
-}
+ : mLoader(std::make_unique<Gralloc1::Loader>()),
+ mDevice(mLoader->getDevice()) {}
+
+
status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
{
ATRACE_CALL();
- status_t err;
- err = mAllocMod->registerBuffer(mAllocMod, handle);
+ gralloc1_error_t error = mDevice->retain(handle);
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
+ handle, error);
- ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
- handle, err, strerror(-err));
- return err;
+ return error;
+}
+
+status_t GraphicBufferMapper::registerBuffer(const GraphicBuffer* buffer)
+{
+ ATRACE_CALL();
+
+ gralloc1_error_t error = mDevice->retain(buffer);
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
+ buffer->getNativeBuffer()->handle, error);
+
+ return error;
}
status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
{
ATRACE_CALL();
- status_t err;
- err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+ gralloc1_error_t error = mDevice->release(handle);
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "unregisterBuffer(%p): failed %d",
+ handle, error);
- ALOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
- handle, err, strerror(-err));
- return err;
+ return error;
}
-status_t GraphicBufferMapper::lock(buffer_handle_t handle,
- uint32_t usage, const Rect& bounds, void** vaddr)
-{
- ATRACE_CALL();
- status_t err;
-
- err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage),
- bounds.left, bounds.top, bounds.width(), bounds.height(),
- vaddr);
-
- ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
- return err;
+static inline gralloc1_rect_t asGralloc1Rect(const Rect& rect) {
+ gralloc1_rect_t outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
}
-status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle,
- uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr)
+status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
+ const Rect& bounds, void** vaddr)
{
- ATRACE_CALL();
- status_t err;
+ return lockAsync(handle, usage, bounds, vaddr, -1);
+}
- if (mAllocMod->lock_ycbcr == NULL) {
- return -EINVAL; // do not log failure
- }
-
- err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage),
- bounds.left, bounds.top, bounds.width(), bounds.height(),
- ycbcr);
-
- ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
- return err;
+status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage,
+ const Rect& bounds, android_ycbcr *ycbcr)
+{
+ return lockAsyncYCbCr(handle, usage, bounds, ycbcr, -1);
}
status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
{
- ATRACE_CALL();
- status_t err;
-
- err = mAllocMod->unlock(mAllocMod, handle);
-
- ALOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
- return err;
+ int32_t fenceFd = -1;
+ status_t error = unlockAsync(handle, &fenceFd);
+ if (error == NO_ERROR) {
+ sync_wait(fenceFd, -1);
+ close(fenceFd);
+ }
+ return error;
}
status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
{
ATRACE_CALL();
- status_t err;
- if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
- err = mAllocMod->lockAsync(mAllocMod, handle, static_cast<int>(usage),
- bounds.left, bounds.top, bounds.width(), bounds.height(),
- vaddr, fenceFd);
- } else {
- if (fenceFd >= 0) {
- sync_wait(fenceFd, -1);
- close(fenceFd);
- }
- err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage),
- bounds.left, bounds.top, bounds.width(), bounds.height(),
- vaddr);
+ gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
+ sp<Fence> fence = new Fence(fenceFd);
+ gralloc1_error_t error = mDevice->lock(handle,
+ static_cast<gralloc1_producer_usage_t>(usage),
+ static_cast<gralloc1_consumer_usage_t>(usage),
+ &accessRegion, vaddr, fence);
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lock(%p, ...) failed: %d", handle,
+ error);
+
+ return error;
+}
+
+static inline bool isValidYCbCrPlane(const android_flex_plane_t& plane) {
+ if (plane.bits_per_component != 8) {
+ ALOGV("Invalid number of bits per component: %d",
+ plane.bits_per_component);
+ return false;
+ }
+ if (plane.bits_used != 8) {
+ ALOGV("Invalid number of bits used: %d", plane.bits_used);
+ return false;
}
- ALOGW_IF(err, "lockAsync(...) failed %d (%s)", err, strerror(-err));
- return err;
+ bool hasValidIncrement = plane.h_increment == 1 ||
+ (plane.component != FLEX_COMPONENT_Y && plane.h_increment == 2);
+ hasValidIncrement = hasValidIncrement && plane.v_increment > 0;
+ if (!hasValidIncrement) {
+ ALOGV("Invalid increment: h %d v %d", plane.h_increment,
+ plane.v_increment);
+ return false;
+ }
+
+ return true;
}
status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd)
{
ATRACE_CALL();
- status_t err;
- if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3
- && mAllocMod->lockAsync_ycbcr != NULL) {
- err = mAllocMod->lockAsync_ycbcr(mAllocMod, handle,
- static_cast<int>(usage), bounds.left, bounds.top,
- bounds.width(), bounds.height(), ycbcr, fenceFd);
- } else if (mAllocMod->lock_ycbcr != NULL) {
- if (fenceFd >= 0) {
- sync_wait(fenceFd, -1);
- close(fenceFd);
- }
- err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage),
- bounds.left, bounds.top, bounds.width(), bounds.height(),
- ycbcr);
- } else {
- if (fenceFd >= 0) {
- close(fenceFd);
- }
- return -EINVAL; // do not log failure
+ gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
+ sp<Fence> fence = new Fence(fenceFd);
+
+ if (mDevice->hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+ gralloc1_error_t error = mDevice->lockYCbCr(handle,
+ static_cast<gralloc1_producer_usage_t>(usage),
+ static_cast<gralloc1_consumer_usage_t>(usage),
+ &accessRegion, ycbcr, fence);
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lockYCbCr(%p, ...) failed: %d",
+ handle, error);
+ return error;
}
- ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
- return err;
+ uint32_t numPlanes = 0;
+ gralloc1_error_t error = mDevice->getNumFlexPlanes(handle, &numPlanes);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGV("Failed to retrieve number of flex planes: %d", error);
+ return error;
+ }
+ if (numPlanes < 3) {
+ ALOGV("Not enough planes for YCbCr (%u found)", numPlanes);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+
+ std::vector<android_flex_plane_t> planes(numPlanes);
+ android_flex_layout_t flexLayout{};
+ flexLayout.num_planes = numPlanes;
+ flexLayout.planes = planes.data();
+
+ error = mDevice->lockFlex(handle,
+ static_cast<gralloc1_producer_usage_t>(usage),
+ static_cast<gralloc1_consumer_usage_t>(usage),
+ &accessRegion, &flexLayout, fence);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGW("lockFlex(%p, ...) failed: %d", handle, error);
+ return error;
+ }
+ if (flexLayout.format != FLEX_FORMAT_YCbCr) {
+ ALOGV("Unable to convert flex-format buffer to YCbCr");
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+
+ // Find planes
+ auto yPlane = planes.cend();
+ auto cbPlane = planes.cend();
+ auto crPlane = planes.cend();
+ for (auto planeIter = planes.cbegin(); planeIter != planes.cend();
+ ++planeIter) {
+ if (planeIter->component == FLEX_COMPONENT_Y) {
+ yPlane = planeIter;
+ } else if (planeIter->component == FLEX_COMPONENT_Cb) {
+ cbPlane = planeIter;
+ } else if (planeIter->component == FLEX_COMPONENT_Cr) {
+ crPlane = planeIter;
+ }
+ }
+ if (yPlane == planes.cend()) {
+ ALOGV("Unable to find Y plane");
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ if (cbPlane == planes.cend()) {
+ ALOGV("Unable to find Cb plane");
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ if (crPlane == planes.cend()) {
+ ALOGV("Unable to find Cr plane");
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+
+ // Validate planes
+ if (!isValidYCbCrPlane(*yPlane)) {
+ ALOGV("Y plane is invalid");
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ if (!isValidYCbCrPlane(*cbPlane)) {
+ ALOGV("Cb plane is invalid");
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ if (!isValidYCbCrPlane(*crPlane)) {
+ ALOGV("Cr plane is invalid");
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ if (cbPlane->v_increment != crPlane->v_increment) {
+ ALOGV("Cb and Cr planes have different step (%d vs. %d)",
+ cbPlane->v_increment, crPlane->v_increment);
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ if (cbPlane->h_increment != crPlane->h_increment) {
+ ALOGV("Cb and Cr planes have different stride (%d vs. %d)",
+ cbPlane->h_increment, crPlane->h_increment);
+ unlock(handle);
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+
+ // Pack plane data into android_ycbcr struct
+ ycbcr->y = yPlane->top_left;
+ ycbcr->cb = cbPlane->top_left;
+ ycbcr->cr = crPlane->top_left;
+ ycbcr->ystride = static_cast<size_t>(yPlane->v_increment);
+ ycbcr->cstride = static_cast<size_t>(cbPlane->v_increment);
+ ycbcr->chroma_step = static_cast<size_t>(cbPlane->h_increment);
+
+ return error;
}
status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
{
ATRACE_CALL();
- status_t err;
- if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
- err = mAllocMod->unlockAsync(mAllocMod, handle, fenceFd);
- } else {
- *fenceFd = -1;
- err = mAllocMod->unlock(mAllocMod, handle);
+ sp<Fence> fence = Fence::NO_FENCE;
+ gralloc1_error_t error = mDevice->unlock(handle, &fence);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("unlock(%p) failed: %d", handle, error);
+ return error;
}
- ALOGW_IF(err, "unlockAsync(...) failed %d (%s)", err, strerror(-err));
- return err;
+ *fenceFd = fence->dup();
+ return error;
}
// ---------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 24394a9..e793852 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1847,7 +1847,7 @@
}
} else if (red_size == 5 && green_size == 6 && blue_size == 5 &&
alpha_size == 0) {
- format == HAL_PIXEL_FORMAT_RGB_565;
+ format = HAL_PIXEL_FORMAT_RGB_565;
} else {
ALOGE("Invalid native pixel format { r=%d, g=%d, b=%d, a=%d }",
red_size, green_size, blue_size, alpha_size);
diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp
index d415bd5..0e18a93 100644
--- a/services/surfaceflinger/FenceTracker.cpp
+++ b/services/surfaceflinger/FenceTracker.cpp
@@ -26,7 +26,9 @@
FenceTracker::FenceTracker() :
mFrameCounter(0),
mOffset(0),
- mFrames() {}
+ mFrames(),
+ mMutex() {
+}
void FenceTracker::dump(String8* outString) {
Mutex::Autolock lock(mMutex);
@@ -135,31 +137,30 @@
nsecs_t postedTime;
sp<Fence> acquireFence;
sp<Fence> prevReleaseFence;
- int32_t key = layers[i]->getSequence();
+ int32_t layerId = layers[i]->getSequence();
layers[i]->getFenceData(&name, &frameNumber, &glesComposition,
&postedTime, &acquireFence, &prevReleaseFence);
#ifdef USE_HWC2
if (glesComposition) {
frame.layers.emplace(std::piecewise_construct,
- std::forward_as_tuple(key),
+ std::forward_as_tuple(layerId),
std::forward_as_tuple(name, frameNumber, glesComposition,
postedTime, 0, 0, acquireFence, prevReleaseFence));
wasGlesCompositionDone = true;
} else {
frame.layers.emplace(std::piecewise_construct,
- std::forward_as_tuple(key),
+ std::forward_as_tuple(layerId),
std::forward_as_tuple(name, frameNumber, glesComposition,
postedTime, 0, 0, acquireFence, Fence::NO_FENCE));
-
- auto prevLayer = prevFrame.layers.find(key);
+ auto prevLayer = prevFrame.layers.find(layerId);
if (prevLayer != prevFrame.layers.end()) {
prevLayer->second.releaseFence = prevReleaseFence;
}
}
#else
frame.layers.emplace(std::piecewise_construct,
- std::forward_as_tuple(key),
+ std::forward_as_tuple(layerId),
std::forward_as_tuple(name, frameNumber, glesComposition,
postedTime, 0, 0, acquireFence,
glesComposition ? Fence::NO_FENCE : prevReleaseFence));
@@ -168,7 +169,7 @@
}
#endif
frame.layers.emplace(std::piecewise_construct,
- std::forward_as_tuple(key),
+ std::forward_as_tuple(layerId),
std::forward_as_tuple(name, frameNumber, glesComposition,
postedTime, 0, 0, acquireFence, prevReleaseFence));
}
@@ -186,4 +187,33 @@
mFrameCounter++;
}
+bool FenceTracker::getFrameTimestamps(const Layer& layer,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+ Mutex::Autolock lock(mMutex);
+ checkFencesForCompletion();
+ int32_t layerId = layer.getSequence();
+
+ size_t i = 0;
+ for (; i < MAX_FRAME_HISTORY; i++) {
+ if (mFrames[i].layers.count(layerId) &&
+ mFrames[i].layers[layerId].frameNumber == frameNumber) {
+ break;
+ }
+ }
+ if (i == MAX_FRAME_HISTORY) {
+ return false;
+ }
+
+ const FrameRecord& frameRecord = mFrames[i];
+ const LayerRecord& layerRecord = mFrames[i].layers[layerId];
+ outTimestamps->frameNumber = frameNumber;
+ outTimestamps->postedTime = layerRecord.postedTime;
+ outTimestamps->acquireTime = layerRecord.acquireTime;
+ outTimestamps->refreshStartTime = frameRecord.refreshStartTime;
+ outTimestamps->glCompositionDoneTime = frameRecord.glesCompositionDoneTime;
+ outTimestamps->displayRetireTime = frameRecord.retireTime;
+ outTimestamps->releaseTime = layerRecord.releaseTime;
+ return true;
+}
+
} // namespace android
diff --git a/services/surfaceflinger/FenceTracker.h b/services/surfaceflinger/FenceTracker.h
index 2fcc314..4cb14a5 100644
--- a/services/surfaceflinger/FenceTracker.h
+++ b/services/surfaceflinger/FenceTracker.h
@@ -29,7 +29,7 @@
namespace android {
class Layer;
-
+struct FrameTimestamps;
/*
* Keeps a circular buffer of fence/timestamp data for the last N frames in
* SurfaceFlinger. Gets timestamps for fences after they have signaled.
@@ -40,6 +40,8 @@
void dump(String8* outString);
void addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence);
+ bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
+ FrameTimestamps* outTimestamps);
protected:
static constexpr size_t MAX_FRAME_HISTORY = 8;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ada1649..1554d70 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -155,7 +155,8 @@
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
mProducer = new MonitoredProducer(producer, mFlinger);
- mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
+ mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName,
+ this);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index dbff834..4257c37 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -409,6 +409,11 @@
std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush);
+ bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ return mFlinger->getFrameTimestamps(*this, frameNumber, outTimestamps);
+ }
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 481d7e3..7ce7777 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3609,6 +3609,11 @@
}
}
+bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+ return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
+}
+
// ---------------------------------------------------------------------------
SurfaceFlinger::LayerVector::LayerVector() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8263994..28666e2 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -440,6 +440,9 @@
std::vector<OccupancyTracker::Segment>&& history);
void dumpBufferingStats(String8& result) const;
+ bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
+ FrameTimestamps* outTimestamps);
+
/* ------------------------------------------------------------------------
* Attributes
*/
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index c71b3bc..ba0a527 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include "SurfaceFlingerConsumer.h"
+#include "Layer.h"
#include <private/gui/SyncFeatures.h>
@@ -251,6 +252,12 @@
}
}
+bool SurfaceFlingerConsumer::getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ sp<const Layer> l = mLayer.promote();
+ return l.get() ? l->getFrameTimestamps(frameNumber, outTimestamps) : false;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 51b002f..3762659 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -23,6 +23,8 @@
namespace android {
// ----------------------------------------------------------------------------
+class Layer;
+
/*
* This is a thin wrapper around GLConsumer.
*/
@@ -35,10 +37,10 @@
};
SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
- uint32_t tex)
+ uint32_t tex, const Layer* layer)
: GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
mTransformToDisplayInverse(false), mSurfaceDamage(),
- mPrevReleaseFence(Fence::NO_FENCE)
+ mPrevReleaseFence(Fence::NO_FENCE), mLayer(layer)
{}
class BufferRejecter {
@@ -82,6 +84,9 @@
void releasePendingBuffer();
#endif
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const override;
+
private:
virtual void onSidebandStreamChanged();
@@ -103,6 +108,9 @@
// The release fence of the already displayed buffer (previous frame).
sp<Fence> mPrevReleaseFence;
+
+ // The layer for this SurfaceFlingerConsumer
+ wp<const Layer> mLayer;
};
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 21955d5..b49f8af 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -3596,6 +3596,11 @@
return result;
}
+bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+ return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
+}
+
void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
const sp<const DisplayDevice>& hw, uint32_t minLayerZ, uint32_t maxLayerZ) {
if (DEBUG_SCREENSHOTS) {