Add gyroscope support to wearable core hw support am: e1b59c3465
am: 34dd55302a
Change-Id: I32776761a3639d9d82b14c745d723df0dbd6c2a4
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 290d7a8..946048d 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -365,7 +365,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;
@@ -975,7 +975,7 @@
" -s N sleep for N seconds before tracing [default 0]\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"
@@ -1150,7 +1150,7 @@
fflush(stdout);
int outFd = STDOUT_FILENO;
if (g_outputFile) {
- outFd = open(g_outputFile, O_WRONLY | O_CREAT);
+ outFd = open(g_outputFile, O_WRONLY | O_CREAT, 0644);
}
if (outFd == -1) {
printf("Failed to open '%s', err=%d", g_outputFile, errno);
diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md
index ca7d574..c33fc1f 100644
--- a/cmds/dumpstate/bugreport-format.md
+++ b/cmds/dumpstate/bugreport-format.md
@@ -22,7 +22,7 @@
file as the `ACTION_SEND_MULTIPLE` attachment.
## Version 1.0 (Android N)
-On _Android N (TBD)_, `dumpstate` generates a zip file directly (unless there
+On _Android N (Nougat)_, `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).
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 3c6d67a..8a4ebf3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -103,8 +103,8 @@
return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
}
-/* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
- * otherwise gets just those modified in the last half an hour. */
+/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
+ * otherwise, gets just those modified in the last half an hour. */
static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
time_t thirty_minutes_ago = now - 60*30;
for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
@@ -112,11 +112,11 @@
int fd = TEMP_FAILURE_RETRY(open(data[i].name,
O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
struct stat st;
- if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
+ if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
(zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
- data[i].fd = fd;
+ data[i].fd = fd;
} else {
- close(fd);
+ close(fd);
data[i].fd = -1;
}
}
@@ -267,6 +267,45 @@
return false;
}
+static void _run_dumpsys(const std::string& title, RootMode root_mode, int timeout_seconds,
+ const std::vector<std::string>& args) {
+ DurationReporter duration_reporter(title.c_str());
+
+ std::string timeout_string = std::to_string(timeout_seconds);
+
+ const char *dumpsys_args[ARG_MAX] = { "/system/bin/dumpsys", "-t", timeout_string.c_str()};
+
+ int index = 3; // 'dumpsys' '-t' 'TIMEOUT'
+ for (const std::string& arg : args) {
+ if (index > ARG_MAX - 2) {
+ MYLOGE("Too many arguments for '%s': %d\n", title.c_str(), (int) args.size());
+ return;
+ }
+ dumpsys_args[index++] = arg.c_str();
+ }
+ // Always terminate with nullptr.
+ dumpsys_args[index] = nullptr;
+
+ std::string args_string;
+ format_args(index, dumpsys_args, &args_string);
+ printf("------ %s (%s) ------\n", title.c_str(), args_string.c_str());
+ fflush(stdout);
+
+ ON_DRY_RUN({ update_progress(timeout_seconds); return; });
+
+ run_command_always(title.c_str(), root_mode, NORMAL_STDOUT, timeout_seconds, dumpsys_args);
+}
+
+static void run_dumpsys(const std::string& title, int timeout_seconds,
+ const std::vector<std::string>& args) {
+ _run_dumpsys(title, DONT_DROP_ROOT, timeout_seconds, args);
+}
+
+static void run_dumpsys_as_shell(const std::string& title, int timeout_seconds,
+ const std::vector<std::string>& args) {
+ _run_dumpsys(title, DROP_ROOT, timeout_seconds, args);
+}
+
static const char mmcblk0[] = "/sys/block/mmcblk0/";
unsigned long worst_write_perf = 20000; /* in KB/s */
@@ -724,7 +763,12 @@
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();
@@ -884,7 +928,7 @@
#endif
dump_file("INTERRUPTS (1)", "/proc/interrupts");
- run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
+ run_dumpsys("NETWORK DIAGNOSTICS", 10, {"connectivity", "--diag"});
#ifdef FWDUMP_bcmdhd
run_command("DUMP WIFI STATUS", 20,
@@ -954,36 +998,36 @@
printf("== Android Framework Services\n");
printf("========================================================\n");
- run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
+ run_dumpsys("DUMPSYS", 60, {"--skip", "meminfo", "cpuinfo"});
printf("========================================================\n");
printf("== Checkins\n");
printf("========================================================\n");
- run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
- run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
- run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
- run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
- run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
- run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
+ run_dumpsys("CHECKIN BATTERYSTATS", 30, {"batterystats", "-c"});
+ run_dumpsys("CHECKIN MEMINFO", 30, {"meminfo", "--checkin"});
+ run_dumpsys("CHECKIN NETSTATS", 30, {"netstats", "--checkin"});
+ run_dumpsys("CHECKIN PROCSTATS", 30, {"procstats", "-c"});
+ run_dumpsys("CHECKIN USAGESTATS", 30, {"usagestats", "-c"});
+ run_dumpsys("CHECKIN PACKAGE", 30, {"package", "--checkin"});
printf("========================================================\n");
printf("== Running Application Activities\n");
printf("========================================================\n");
- run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
+ run_dumpsys("APP ACTIVITIES", 30, {"activity", "all"});
printf("========================================================\n");
printf("== Running Application Services\n");
printf("========================================================\n");
- run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
+ run_dumpsys("APP SERVICES", 30, {"activity", "service", "all"});
printf("========================================================\n");
printf("== Running Application Providers\n");
printf("========================================================\n");
- run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
+ run_dumpsys("APP PROVIDERS", 30, {"activity", "provider", "all"});
printf("========================================================\n");
@@ -1026,7 +1070,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;
@@ -1036,6 +1080,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));
@@ -1206,7 +1260,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 */
@@ -1350,8 +1404,8 @@
// 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 CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
+ run_dumpsys_as_shell("DUMPSYS MEMINFO", 90, {"meminfo", "-a"});
+ run_dumpsys_as_shell("DUMPSYS CPUINFO", 10, {"cpuinfo", "-a"});
/* collect stack traces from Dalvik and native processes (needs root) */
dump_traces_path = dump_traces();
@@ -1416,7 +1470,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 5e083cc..a7d14f7 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -151,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);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index a4e9c05..3c9693f 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[] = {
@@ -642,7 +644,7 @@
DurationReporter duration_reporter(title);
fflush(stdout);
- const char *args[1024] = {command};
+ const char *args[ARG_MAX] = {command};
size_t arg;
va_list ap;
va_start(ap, command);
@@ -665,6 +667,7 @@
std::string cmd;
format_args(command, args, &cmd);
MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
+ va_end(ap);
return -1;
}
@@ -679,7 +682,7 @@
DurationReporter duration_reporter(title);
fflush(stdout);
- const char *args[1024] = {command};
+ const char *args[ARG_MAX] = {command};
size_t arg;
va_list ap;
va_start(ap, command);
@@ -702,6 +705,7 @@
std::string cmd;
format_args(command, args, &cmd);
MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
+ va_end(ap);
return -1;
}
@@ -867,14 +871,18 @@
MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size());
return;
}
- const char *am_args[1024] = { "/system/bin/am", "broadcast", "--user", "0", "-a",
- action.c_str() };
+ const char *am_args[ARG_MAX] = { "/system/bin/am", "broadcast", "--user", "0", "-a",
+ action.c_str() };
size_t am_index = 5; // Starts at the index of last initial value above.
for (const std::string& arg : args) {
+ if (am_index > ARG_MAX - 2) {
+ MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size());
+ return;
+ }
am_args[++am_index] = arg.c_str();
}
- // Always terminate with NULL.
- am_args[am_index + 1] = NULL;
+ // Always terminate with nullptr.
+ am_args[am_index + 1] = nullptr;
std::string args_string;
format_args(am_index + 1, am_args, &args_string);
MYLOGD("send_broadcast command: %s\n", args_string.c_str());
@@ -973,11 +981,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));
@@ -988,6 +996,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)) {
@@ -1091,7 +1107,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) {
@@ -1379,7 +1395,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/installd/commands.cpp b/cmds/installd/commands.cpp
index 2c37ea8..52dc833 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -60,6 +60,8 @@
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";
+static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
+
static constexpr const char* PKG_LIB_POSTFIX = "/lib";
static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
@@ -80,8 +82,6 @@
static constexpr int DEXOPT_PATCHOAT_NEEDED = 2;
static constexpr int DEXOPT_SELF_PATCHOAT_NEEDED = 3;
-#define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
-
typedef int fd_t;
static bool property_get_bool(const char* property_name, bool default_value = false) {
diff --git a/cmds/surfacereplayer/proto/Android.mk b/cmds/surfacereplayer/proto/Android.mk
new file mode 100644
index 0000000..b87d34f
--- /dev/null
+++ b/cmds/surfacereplayer/proto/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-proto-files-under, src)
+
+LOCAL_SHARED_LIBRARIES := \
+ libprotobuf-cpp-full
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := full
+
+LOCAL_MODULE := libtrace_proto
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
new file mode 100644
index 0000000..ce08ecf
--- /dev/null
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -0,0 +1,136 @@
+syntax = "proto2";
+
+message Trace {
+ repeated Increment increment = 1;
+}
+
+message Increment {
+ required int64 time_stamp = 1;
+
+ oneof increment {
+ Transaction transaction = 2;
+ Create create = 3;
+ Delete delete = 4;
+ BufferUpdate buffer_update = 5;
+ VSyncEvent vsync_event = 6;
+ }
+}
+
+message Transaction {
+ repeated Change change = 1;
+
+ required bool synchronous = 2;
+ required bool animation = 3;
+}
+
+message Change {
+ required uint32 id = 1;
+
+ oneof Change {
+ PositionChange position = 2;
+ SizeChange size = 3;
+ AlphaChange alpha = 4;
+ LayerChange layer = 5;
+ CropChange crop = 6;
+ FinalCropChange final_crop = 7;
+ MatrixChange matrix = 8;
+ OverrideScalingModeChange override_scaling_mode = 9;
+ TransparentRegionHintChange transparent_region_hint = 10;
+ LayerStackChange layer_stack = 11;
+ HiddenFlagChange hidden_flag = 12;
+ OpaqueFlagChange opaque_flag = 13;
+ SecureFlagChange secure_flag = 14;
+ DeferredTransactionChange deferred_transaction = 15;
+ }
+}
+
+message PositionChange {
+ required float x = 1;
+ required float y = 2;
+}
+
+message SizeChange {
+ required uint32 w = 1;
+ required uint32 h = 2;
+}
+
+message AlphaChange {
+ required float alpha = 1;
+}
+
+message LayerChange {
+ required uint32 layer = 1;
+}
+
+message CropChange {
+ required Rectangle rectangle = 1;
+}
+
+message FinalCropChange {
+ required Rectangle rectangle = 1;
+}
+
+message MatrixChange {
+ required float dsdx = 1;
+ required float dtdx = 2;
+ required float dsdy = 3;
+ required float dtdy = 4;
+}
+
+message OverrideScalingModeChange {
+ required int32 override_scaling_mode = 1;
+}
+
+message TransparentRegionHintChange {
+ repeated Rectangle region = 1;
+}
+
+message LayerStackChange {
+ required uint32 layer_stack = 1;
+}
+
+message HiddenFlagChange {
+ required bool hidden_flag = 1;
+}
+
+message OpaqueFlagChange {
+ required bool opaque_flag = 1;
+}
+
+message SecureFlagChange {
+ required bool secure_flag = 1;
+}
+
+message DeferredTransactionChange {
+ required uint32 layer_id = 1;
+ required uint64 frame_number = 2;
+}
+
+message Rectangle {
+ required int32 left = 1;
+ required int32 top = 2;
+ required int32 right = 3;
+ required int32 bottom = 4;
+}
+
+message Create {
+ required uint32 id = 1;
+ required string name = 2;
+ required uint32 w = 3;
+ required uint32 h = 4;
+}
+
+message Delete {
+ required uint32 id = 1;
+}
+
+message BufferUpdate {
+ required uint32 id = 1;
+ required uint32 w = 2;
+ required uint32 h = 3;
+ required uint64 frame_number = 4;
+}
+
+message VSyncEvent {
+ required int64 when = 1;
+}
diff --git a/cmds/surfacereplayer/replayer/Android.mk b/cmds/surfacereplayer/replayer/Android.mk
new file mode 100644
index 0000000..28d4481
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Android.mk
@@ -0,0 +1,71 @@
+# 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.
+
+LOCAL_TARGET_DIR := $(TARGET_OUT_DATA)/local/tmp
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(call first-makefiles-under, /frameworks/native/cmds/surfacereplayer/proto)
+
+include $(CLEAR_VARS)
+
+LOCAL_CPPFLAGS := -Weverything -Werror
+LOCAL_CPPFLAGS := -Wno-unused-parameter
+LOCAL_CPPFLAGS := -Wno-format
+
+LOCAL_MODULE := libsurfacereplayer
+
+LOCAL_SRC_FILES := \
+ BufferQueueScheduler.cpp \
+ Event.cpp \
+ Replayer.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libEGL \
+ libGLESv2 \
+ libbinder \
+ libcutils \
+ libgui \
+ libui \
+ libutils \
+ libprotobuf-cpp-full \
+
+LOCAL_STATIC_LIBRARIES := \
+ libtrace_proto \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/..
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := surfacereplayer
+
+LOCAL_SRC_FILES := \
+ Main.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libprotobuf-cpp-full \
+ libsurfacereplayer \
+ libutils \
+
+LOCAL_STATIC_LIBRARIES := \
+ libtrace_proto \
+
+LOCAL_CPPFLAGS := -Weverything -Werror
+LOCAL_CPPFLAGS := -Wno-unused-parameter
+
+LOCAL_MODULE_PATH := $(LOCAL_TARGET_DIR)
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp b/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp
new file mode 100644
index 0000000..cad11a0
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BufferQueueScheduler"
+
+#include "BufferQueueScheduler.h"
+
+#include <android/native_window.h>
+#include <gui/Surface.h>
+
+using namespace android;
+
+BufferQueueScheduler::BufferQueueScheduler(
+ const sp<SurfaceControl>& surfaceControl, const RGB& color, int id)
+ : mSurfaceControl(surfaceControl), mColor(color), mSurfaceId(id), mContinueScheduling(true) {}
+
+void BufferQueueScheduler::startScheduling() {
+ ALOGV("Starting Scheduler for %d Layer", mSurfaceId);
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mSurfaceControl == nullptr) {
+ mCondition.wait(lock, [&] { return (mSurfaceControl != nullptr); });
+ }
+
+ while (mContinueScheduling) {
+ while (true) {
+ if (mBufferEvents.empty()) {
+ break;
+ }
+
+ BufferEvent event = mBufferEvents.front();
+ lock.unlock();
+
+ bufferUpdate(event.dimensions);
+ fillSurface(event.event);
+ lock.lock();
+ mBufferEvents.pop();
+ }
+ mCondition.wait(lock);
+ }
+}
+
+void BufferQueueScheduler::addEvent(const BufferEvent& event) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mBufferEvents.push(event);
+ mCondition.notify_one();
+}
+
+void BufferQueueScheduler::stopScheduling() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mContinueScheduling = false;
+ mCondition.notify_one();
+}
+
+void BufferQueueScheduler::setSurfaceControl(
+ const sp<SurfaceControl>& surfaceControl, const RGB& color) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mSurfaceControl = surfaceControl;
+ mColor = color;
+ mCondition.notify_one();
+}
+
+void BufferQueueScheduler::bufferUpdate(const Dimensions& dimensions) {
+ sp<Surface> s = mSurfaceControl->getSurface();
+ s->setBuffersDimensions(dimensions.width, dimensions.height);
+}
+
+void BufferQueueScheduler::fillSurface(std::shared_ptr<Event> event) {
+ ANativeWindow_Buffer outBuffer;
+ sp<Surface> s = mSurfaceControl->getSurface();
+
+ status_t status = s->lock(&outBuffer, nullptr);
+
+ if (status != NO_ERROR) {
+ ALOGE("fillSurface: failed to lock buffer, (%d)", status);
+ return;
+ }
+
+ auto img = reinterpret_cast<uint8_t*>(outBuffer.bits);
+ for (int y = 0; y < outBuffer.height; y++) {
+ for (int x = 0; x < outBuffer.width; x++) {
+ uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
+ pixel[0] = mColor.r;
+ pixel[1] = mColor.g;
+ pixel[2] = mColor.b;
+ pixel[3] = LAYER_ALPHA;
+ }
+ }
+
+ event->readyToExecute();
+
+ status = s->unlockAndPost();
+
+ ALOGE_IF(status != NO_ERROR, "fillSurface: failed to unlock and post buffer, (%d)", status);
+}
diff --git a/cmds/surfacereplayer/replayer/BufferQueueScheduler.h b/cmds/surfacereplayer/replayer/BufferQueueScheduler.h
new file mode 100644
index 0000000..fc8e20c
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/BufferQueueScheduler.h
@@ -0,0 +1,82 @@
+/*
+ * 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_SURFACEREPLAYER_BUFFERQUEUESCHEDULER_H
+#define ANDROID_SURFACEREPLAYER_BUFFERQUEUESCHEDULER_H
+
+#include "Color.h"
+#include "Event.h"
+
+#include <gui/SurfaceControl.h>
+
+#include <utils/StrongPointer.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <utility>
+
+namespace android {
+
+auto constexpr LAYER_ALPHA = 190;
+
+struct Dimensions {
+ Dimensions() = default;
+ Dimensions(int w, int h) : width(w), height(h) {}
+
+ int width = 0;
+ int height = 0;
+};
+
+struct BufferEvent {
+ BufferEvent() = default;
+ BufferEvent(std::shared_ptr<Event> e, Dimensions d) : event(e), dimensions(d) {}
+
+ std::shared_ptr<Event> event;
+ Dimensions dimensions;
+};
+
+class BufferQueueScheduler {
+ public:
+ BufferQueueScheduler(const sp<SurfaceControl>& surfaceControl, const RGB& color, int id);
+
+ void startScheduling();
+ void addEvent(const BufferEvent&);
+ void stopScheduling();
+
+ void setSurfaceControl(const sp<SurfaceControl>& surfaceControl, const RGB& color);
+
+ private:
+ void bufferUpdate(const Dimensions& dimensions);
+
+ // Lock and fill the surface, block until the event is signaled by the main loop,
+ // then unlock and post the buffer.
+ void fillSurface(std::shared_ptr<Event>);
+
+ sp<SurfaceControl> mSurfaceControl;
+ RGB mColor;
+ const int mSurfaceId;
+
+ bool mContinueScheduling;
+
+ std::queue<BufferEvent> mBufferEvents;
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+};
+
+} // namespace android
+#endif
diff --git a/cmds/surfacereplayer/replayer/Color.h b/cmds/surfacereplayer/replayer/Color.h
new file mode 100644
index 0000000..d644b8d
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Color.h
@@ -0,0 +1,104 @@
+/*
+ * 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_SURFACEREPLAYER_COLOR_H
+#define ANDROID_SURFACEREPLAYER_COLOR_H
+
+#include <cmath>
+#include <cstdlib>
+
+namespace android {
+
+typedef struct RGB {
+ RGB() = default;
+ RGB(uint8_t rIn, uint8_t gIn, uint8_t bIn) : r(rIn), g(gIn), b(bIn) {}
+
+ uint8_t r = 0;
+ uint8_t g = 0;
+ uint8_t b = 0;
+} RGB;
+
+typedef struct HSV {
+ HSV() = default;
+ HSV(double hIn, double sIn, double vIn) : h(hIn), s(sIn), v(vIn) {}
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+} HSV;
+
+static inline RGB HSVToRGB(HSV hsv) {
+ using namespace std;
+ double r = 0, g = 0, b = 0;
+
+ if (hsv.s == 0) {
+ r = hsv.v;
+ g = hsv.v;
+ b = hsv.v;
+ } else {
+ hsv.h = static_cast<int>(hsv.h) % 360;
+ hsv.h = hsv.h / 60;
+
+ int i = static_cast<int>(trunc(hsv.h));
+ double f = hsv.h - i;
+
+ double x = hsv.v * (1.0 - hsv.s);
+ double y = hsv.v * (1.0 - (hsv.s * f));
+ double z = hsv.v * (1.0 - (hsv.s * (1.0 - f)));
+
+ switch (i) {
+ case 0:
+ r = hsv.v;
+ g = z;
+ b = x;
+ break;
+
+ case 1:
+ r = y;
+ g = hsv.v;
+ b = x;
+ break;
+
+ case 2:
+ r = x;
+ g = hsv.v;
+ b = z;
+ break;
+
+ case 3:
+ r = x;
+ g = y;
+ b = hsv.v;
+ break;
+
+ case 4:
+ r = z;
+ g = x;
+ b = hsv.v;
+ break;
+
+ default:
+ r = hsv.v;
+ g = x;
+ b = y;
+ break;
+ }
+ }
+
+ return RGB(round(r * 255), round(g * 255), round(b * 255));
+}
+}
+#endif
diff --git a/cmds/surfacereplayer/replayer/Event.cpp b/cmds/surfacereplayer/replayer/Event.cpp
new file mode 100644
index 0000000..390d398
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Event.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#include "Event.h"
+
+using namespace android;
+
+Event::Event(Increment::IncrementCase type) : mIncrementType(type) {}
+
+void Event::readyToExecute() {
+ changeState(Event::EventState::Waiting);
+ waitUntil(Event::EventState::Signaled);
+ changeState(Event::EventState::Running);
+}
+
+void Event::complete() {
+ waitUntil(Event::EventState::Waiting);
+ changeState(Event::EventState::Signaled);
+ waitUntil(Event::EventState::Running);
+}
+
+void Event::waitUntil(Event::EventState state) {
+ std::unique_lock<std::mutex> lock(mLock);
+ mCond.wait(lock, [this, state] { return (mState == state); });
+}
+
+void Event::changeState(Event::EventState state) {
+ std::unique_lock<std::mutex> lock(mLock);
+ mState = state;
+ lock.unlock();
+
+ mCond.notify_one();
+}
+
+Increment::IncrementCase Event::getIncrementType() {
+ return mIncrementType;
+}
diff --git a/cmds/surfacereplayer/replayer/Event.h b/cmds/surfacereplayer/replayer/Event.h
new file mode 100644
index 0000000..44b60f5
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Event.h
@@ -0,0 +1,55 @@
+/*
+ * 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_SURFACEREPLAYER_EVENT_H
+#define ANDROID_SURFACEREPLAYER_EVENT_H
+
+#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
+
+#include <condition_variable>
+#include <mutex>
+
+namespace android {
+
+class Event {
+ public:
+ Event(Increment::IncrementCase);
+
+ enum class EventState {
+ SettingUp, // Completing as much time-independent work as possible
+ Waiting, // Waiting for signal from main thread to finish execution
+ Signaled, // Signaled by main thread, about to immediately switch to Running
+ Running // Finishing execution of rest of work
+ };
+
+ void readyToExecute();
+ void complete();
+
+ Increment::IncrementCase getIncrementType();
+
+ private:
+ void waitUntil(EventState state);
+ void changeState(EventState state);
+
+ std::mutex mLock;
+ std::condition_variable mCond;
+
+ EventState mState = EventState::SettingUp;
+
+ Increment::IncrementCase mIncrementType;
+};
+}
+#endif
diff --git a/cmds/surfacereplayer/replayer/Main.cpp b/cmds/surfacereplayer/replayer/Main.cpp
new file mode 100644
index 0000000..bf5da52
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Main.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/*
+ * Replayer - Main.cpp
+ *
+ * 1. Get flags from command line
+ * 2. Commit actions or settings based on the flags
+ * 3. Initalize a replayer object with the filename passed in
+ * 4. Replay
+ * 5. Exit successfully or print error statement
+ */
+
+#include <replayer/Replayer.h>
+
+#include <csignal>
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+
+using namespace android;
+
+void printHelpMenu() {
+ std::cout << "SurfaceReplayer options:\n";
+ std::cout << "Usage: surfacereplayer [OPTIONS...] <TRACE FILE>\n";
+ std::cout << " File path must be absolute" << std::endl << std::endl;
+
+ std::cout << " -m Stops the replayer at the start of the trace and switches ";
+ "to manual replay\n";
+
+ std::cout << " -t [Number of Threads] Specifies the number of threads to be used while "
+ "replaying (default is " << android::DEFAULT_THREADS << ")\n";
+
+ std::cout << " -h Display help menu\n";
+
+ std::cout << std::endl;
+}
+
+int main(int argc, char** argv) {
+ std::string filename;
+ bool pauseBeginning = false;
+ int numThreads = DEFAULT_THREADS;
+
+ int opt = 0;
+ while ((opt = getopt(argc, argv, "pt:h?")) != -1) {
+ switch (opt) {
+ case 'm':
+ pauseBeginning = true;
+ break;
+ case 't':
+ numThreads = atoi(optarg);
+ break;
+ case 'h':
+ case '?':
+ printHelpMenu();
+ exit(0);
+ default:
+ std::cerr << "Invalid argument...exiting" << std::endl;
+ printHelpMenu();
+ exit(0);
+ }
+ }
+
+ char** input = argv + optind;
+ if (input[0] == NULL) {
+ std::cerr << "No trace file provided...exiting" << std::endl;
+ abort();
+ }
+ filename.assign(input[0]);
+
+ android::Replayer r(filename, pauseBeginning, numThreads);
+ auto status = r.replay();
+
+ if (status == NO_ERROR) {
+ std::cout << "Successfully finished replaying trace" << std::endl;
+ } else {
+ std::cerr << "Trace replayer returned error: " << status << std::endl;
+ }
+
+ return 0;
+}
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
new file mode 100644
index 0000000..950ebbb
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -0,0 +1,514 @@
+/* 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
+#define LOG_TAG "SurfaceReplayer"
+
+#include "Replayer.h"
+
+#include <android/native_window.h>
+
+#include <binder/IMemory.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <private/gui/ComposerService.h>
+#include <private/gui/LayerState.h>
+
+#include <ui/DisplayInfo.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+#include <chrono>
+#include <cmath>
+#include <condition_variable>
+#include <cstdlib>
+#include <fstream>
+#include <functional>
+#include <iostream>
+#include <mutex>
+#include <string>
+#include <thread>
+
+using namespace android;
+
+std::atomic_bool Replayer::sReplayingManually(false);
+
+Replayer::Replayer(const std::string& filename, bool replayManually, int numThreads)
+ : mTrace(), mLoaded(false), mIncrementIndex(0), mCurrentTime(0), mNumThreads(numThreads) {
+ srand(RAND_COLOR_SEED);
+
+ std::fstream input(filename, std::ios::in | std::ios::binary);
+
+ mLoaded = mTrace.ParseFromIstream(&input);
+ if (!mLoaded) {
+ std::cerr << "Trace did not load. Does " << filename << " exist?" << std::endl;
+ abort();
+ }
+
+ mCurrentTime = mTrace.increment(0).time_stamp();
+
+ sReplayingManually.store(replayManually);
+}
+
+Replayer::Replayer(const Trace& t, bool replayManually, int numThreads)
+ : mTrace(t), mLoaded(true), mIncrementIndex(0), mCurrentTime(0), mNumThreads(numThreads) {
+ srand(RAND_COLOR_SEED);
+ mCurrentTime = mTrace.increment(0).time_stamp();
+
+ sReplayingManually.store(replayManually);
+}
+
+status_t Replayer::replay() {
+ // for manual control
+ signal(SIGINT, Replayer::stopAutoReplayHandler);
+
+ ALOGV("There are %d increments.", mTrace.increment_size());
+
+ status_t status = loadSurfaceComposerClient();
+
+ if (status != NO_ERROR) {
+ ALOGE("Couldn't create SurfaceComposerClient (%d)", status);
+ return status;
+ }
+
+ SurfaceComposerClient::enableVSyncInjections(true);
+
+ initReplay();
+
+ ALOGV("Starting actual Replay!");
+ while (!mPendingIncrements.empty()) {
+ waitForConsoleCommmand();
+
+ auto pastIncrement = mTrace.increment(mIncrementIndex);
+
+ waitUntilTimestamp(pastIncrement.time_stamp());
+
+ auto event = mPendingIncrements.front();
+ mPendingIncrements.pop();
+
+ event->complete();
+
+ if (event->getIncrementType() == Increment::kVsyncEvent) {
+ mWaitingForNextVSync = false;
+ }
+
+ if (mIncrementIndex + mNumThreads < mTrace.increment_size()) {
+ status = dispatchEvent(mIncrementIndex + mNumThreads);
+
+ if (status != NO_ERROR) {
+ SurfaceComposerClient::enableVSyncInjections(false);
+ return status;
+ }
+ }
+
+ mIncrementIndex++;
+ mCurrentTime = pastIncrement.time_stamp();
+ }
+
+ SurfaceComposerClient::enableVSyncInjections(false);
+
+ return status;
+}
+
+status_t Replayer::initReplay() {
+ for (int i = 0; i < mNumThreads && i < mTrace.increment_size(); i++) {
+ status_t status = dispatchEvent(i);
+
+ if (status != NO_ERROR) {
+ ALOGE("Unable to dispatch event (%d)", status);
+ return status;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+void Replayer::stopAutoReplayHandler(int /*signal*/) {
+ if (sReplayingManually) {
+ SurfaceComposerClient::enableVSyncInjections(false);
+ exit(0);
+ }
+
+ sReplayingManually.store(true);
+}
+
+void Replayer::waitForConsoleCommmand() {
+ if (!sReplayingManually || mWaitingForNextVSync) {
+ return;
+ }
+
+ while (true) {
+ std::string input = "";
+ std::cout << "> ";
+ getline(std::cin, input);
+
+ if (input.empty()) {
+ input = mLastInput;
+ }
+
+ input = mLastInput;
+ if (input == "n") { // next vsync
+ mWaitingForNextVSync = true;
+ break;
+ } else if (input == "c") { // continue
+ sReplayingManually.store(false);
+ mWaitingForNextVSync = false;
+ break;
+ } else if (input == "h") { // help
+ // add help menu
+ }
+
+ std::cout << "Invalid Command" << std::endl;
+ }
+}
+
+status_t Replayer::dispatchEvent(int index) {
+ auto increment = mTrace.increment(index);
+ std::shared_ptr<Event> event = std::make_shared<Event>(increment.increment_case());
+ mPendingIncrements.push(event);
+
+ status_t status = NO_ERROR;
+ switch (increment.increment_case()) {
+ case increment.kTransaction: {
+ std::thread(&Replayer::doTransaction, this, increment.transaction(), event).detach();
+ } break;
+ case increment.kCreate: {
+ std::thread(&Replayer::createSurfaceControl, this, increment.create(), event).detach();
+ } break;
+ case increment.kDelete: {
+ std::thread(&Replayer::deleteSurfaceControl, this, increment.delete_(), event).detach();
+ } break;
+ case increment.kBufferUpdate: {
+ std::lock_guard<std::mutex> lock1(mLayerLock);
+ std::lock_guard<std::mutex> lock2(mBufferQueueSchedulerLock);
+
+ Dimensions dimensions(increment.buffer_update().w(), increment.buffer_update().h());
+ BufferEvent bufferEvent(event, dimensions);
+
+ auto layerId = increment.buffer_update().id();
+ if (mBufferQueueSchedulers.count(layerId) == 0) {
+ mBufferQueueSchedulers[layerId] = std::make_shared<BufferQueueScheduler>(
+ mLayers[layerId], mColors[layerId], layerId);
+ mBufferQueueSchedulers[layerId]->addEvent(bufferEvent);
+
+ std::thread(&BufferQueueScheduler::startScheduling,
+ mBufferQueueSchedulers[increment.buffer_update().id()].get())
+ .detach();
+ } else {
+ auto bqs = mBufferQueueSchedulers[increment.buffer_update().id()];
+ bqs->addEvent(bufferEvent);
+ }
+ } break;
+ case increment.kVsyncEvent: {
+ std::thread(&Replayer::injectVSyncEvent, this, increment.vsync_event(), event).detach();
+ } break;
+ default:
+ ALOGE("Unknown Increment Type: %d", increment.increment_case());
+ status = BAD_VALUE;
+ break;
+ }
+
+ return status;
+}
+
+status_t Replayer::doTransaction(const Transaction& t, const std::shared_ptr<Event>& event) {
+ ALOGV("Started Transaction");
+
+ if (t.change_size() == 0) {
+ event->readyToExecute();
+ return NO_ERROR;
+ }
+
+ Change change = t.change(0);
+
+ std::unique_lock<std::mutex> lock(mLayerLock);
+ if (mLayers[change.id()] == nullptr) {
+ mLayerCond.wait(lock, [&] { return (mLayers[change.id()] != nullptr); });
+ }
+ lock.unlock();
+
+ SurfaceComposerClient::openGlobalTransaction();
+
+ status_t status = NO_ERROR;
+
+ for (const Change& change : t.change()) {
+ std::unique_lock<std::mutex> lock(mLayerLock);
+ if (mLayers[change.id()] == nullptr) {
+ mLayerCond.wait(lock, [&] { return (mLayers[change.id()] != nullptr); });
+ }
+
+ switch (change.Change_case()) {
+ case Change::ChangeCase::kPosition:
+ status = setPosition(change.id(), change.position());
+ break;
+ case Change::ChangeCase::kSize:
+ status = setSize(change.id(), change.size());
+ break;
+ case Change::ChangeCase::kAlpha:
+ status = setAlpha(change.id(), change.alpha());
+ break;
+ case Change::ChangeCase::kLayer:
+ status = setLayer(change.id(), change.layer());
+ break;
+ case Change::ChangeCase::kCrop:
+ status = setCrop(change.id(), change.crop());
+ break;
+ case Change::ChangeCase::kMatrix:
+ status = setMatrix(change.id(), change.matrix());
+ break;
+ case Change::ChangeCase::kFinalCrop:
+ status = setFinalCrop(change.id(), change.final_crop());
+ break;
+ case Change::ChangeCase::kOverrideScalingMode:
+ status = setOverrideScalingMode(change.id(), change.override_scaling_mode());
+ break;
+ case Change::ChangeCase::kTransparentRegionHint:
+ status = setTransparentRegionHint(change.id(), change.transparent_region_hint());
+ break;
+ case Change::ChangeCase::kLayerStack:
+ status = setLayerStack(change.id(), change.layer_stack());
+ break;
+ case Change::ChangeCase::kHiddenFlag:
+ status = setHiddenFlag(change.id(), change.hidden_flag());
+ break;
+ case Change::ChangeCase::kOpaqueFlag:
+ status = setOpaqueFlag(change.id(), change.opaque_flag());
+ break;
+ case Change::ChangeCase::kSecureFlag:
+ status = setSecureFlag(change.id(), change.secure_flag());
+ break;
+ case Change::ChangeCase::kDeferredTransaction:
+ waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock);
+ status = setDeferredTransaction(change.id(), change.deferred_transaction());
+ break;
+ default:
+ status = NO_ERROR;
+ break;
+ }
+
+ if (status != NO_ERROR) {
+ ALOGE("SET TRANSACTION FAILED");
+ return status;
+ }
+ }
+
+ if (t.animation()) {
+ SurfaceComposerClient::setAnimationTransaction();
+ }
+
+ event->readyToExecute();
+
+ SurfaceComposerClient::closeGlobalTransaction(t.synchronous());
+
+ ALOGV("Ended Transaction");
+
+ return status;
+}
+
+status_t Replayer::setPosition(uint32_t id, const PositionChange& pc) {
+ ALOGV("Layer %d: Setting Position -- x=%f, y=%f", id, pc.x(), pc.y());
+ return mLayers[id]->setPosition(pc.x(), pc.y());
+}
+
+status_t Replayer::setSize(uint32_t id, const SizeChange& sc) {
+ ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h());
+ return mLayers[id]->setSize(sc.w(), sc.h());
+}
+
+status_t Replayer::setLayer(uint32_t id, const LayerChange& lc) {
+ ALOGV("Layer %d: Setting Layer -- layer=%d", id, lc.layer());
+ return mLayers[id]->setLayer(lc.layer());
+}
+
+status_t Replayer::setAlpha(uint32_t id, const AlphaChange& ac) {
+ ALOGV("Layer %d: Setting Alpha -- alpha=%f", id, ac.alpha());
+ return mLayers[id]->setAlpha(ac.alpha());
+}
+
+status_t Replayer::setCrop(uint32_t id, const CropChange& cc) {
+ ALOGV("Layer %d: Setting Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
+ cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
+ cc.rectangle().bottom());
+
+ Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
+ cc.rectangle().bottom());
+ return mLayers[id]->setCrop(r);
+}
+
+status_t Replayer::setFinalCrop(uint32_t id, const FinalCropChange& fcc) {
+ ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
+ fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
+ fcc.rectangle().bottom());
+ Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
+ fcc.rectangle().bottom());
+ return mLayers[id]->setFinalCrop(r);
+}
+
+status_t Replayer::setMatrix(uint32_t id, const MatrixChange& mc) {
+ ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
+ mc.dtdx(), mc.dsdy(), mc.dtdy());
+ return mLayers[id]->setMatrix(mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
+}
+
+status_t Replayer::setOverrideScalingMode(uint32_t id, const OverrideScalingModeChange& osmc) {
+ ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode());
+ return mLayers[id]->setOverrideScalingMode(osmc.override_scaling_mode());
+}
+
+status_t Replayer::setTransparentRegionHint(uint32_t id, const TransparentRegionHintChange& trhc) {
+ ALOGV("Setting Transparent Region Hint");
+ Region re = Region();
+
+ for (auto r : trhc.region()) {
+ Rect rect = Rect(r.left(), r.top(), r.right(), r.bottom());
+ re.merge(rect);
+ }
+
+ return mLayers[id]->setTransparentRegionHint(re);
+}
+
+status_t Replayer::setLayerStack(uint32_t id, const LayerStackChange& lsc) {
+ ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack());
+ return mLayers[id]->setLayerStack(lsc.layer_stack());
+}
+
+status_t Replayer::setHiddenFlag(uint32_t id, const HiddenFlagChange& hfc) {
+ ALOGV("Layer %d: Setting Hidden Flag -- hidden_flag=%d", id, hfc.hidden_flag());
+ uint32_t flag = hfc.hidden_flag() ? layer_state_t::eLayerHidden : 0;
+
+ return mLayers[id]->setFlags(flag, layer_state_t::eLayerHidden);
+}
+
+status_t Replayer::setOpaqueFlag(uint32_t id, const OpaqueFlagChange& ofc) {
+ ALOGV("Layer %d: Setting Opaque Flag -- opaque_flag=%d", id, ofc.opaque_flag());
+ uint32_t flag = ofc.opaque_flag() ? layer_state_t::eLayerOpaque : 0;
+
+ return mLayers[id]->setFlags(flag, layer_state_t::eLayerOpaque);
+}
+
+status_t Replayer::setSecureFlag(uint32_t id, const SecureFlagChange& sfc) {
+ ALOGV("Layer %d: Setting Secure Flag -- secure_flag=%d", id, sfc.secure_flag());
+ uint32_t flag = sfc.secure_flag() ? layer_state_t::eLayerSecure : 0;
+
+ return mLayers[id]->setFlags(flag, layer_state_t::eLayerSecure);
+}
+
+status_t Replayer::setDeferredTransaction(uint32_t id, const DeferredTransactionChange& dtc) {
+ ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, "
+ "frame_number=%llu",
+ id, dtc.layer_id(), dtc.frame_number());
+ if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
+ ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id());
+ return BAD_VALUE;
+ }
+
+ auto handle = mLayers[dtc.layer_id()]->getHandle();
+
+ return mLayers[id]->deferTransactionUntil(handle, dtc.frame_number());
+}
+
+status_t Replayer::createSurfaceControl(const Create& create, const std::shared_ptr<Event>& event) {
+ event->readyToExecute();
+
+ ALOGV("Creating Surface Control: ID: %d", create.id());
+ sp<SurfaceControl> surfaceControl = mComposerClient->createSurface(
+ String8(create.name().c_str()), create.w(), create.h(), PIXEL_FORMAT_RGBA_8888, 0);
+
+ if (surfaceControl == nullptr) {
+ ALOGE("CreateSurfaceControl: unable to create surface control");
+ return BAD_VALUE;
+ }
+
+ std::lock_guard<std::mutex> lock1(mLayerLock);
+ auto& layer = mLayers[create.id()];
+ layer = surfaceControl;
+
+ mColors[create.id()] = HSVToRGB(HSV(rand() % 360, 1, 1));
+
+ mLayerCond.notify_all();
+
+ std::lock_guard<std::mutex> lock2(mBufferQueueSchedulerLock);
+ if (mBufferQueueSchedulers.count(create.id()) != 0) {
+ mBufferQueueSchedulers[create.id()]->setSurfaceControl(
+ mLayers[create.id()], mColors[create.id()]);
+ }
+
+ return NO_ERROR;
+}
+
+status_t Replayer::deleteSurfaceControl(
+ const Delete& delete_, const std::shared_ptr<Event>& event) {
+ ALOGV("Deleting %d Surface Control", delete_.id());
+ event->readyToExecute();
+
+ std::lock_guard<std::mutex> lock1(mPendingLayersLock);
+
+ mLayersPendingRemoval.push_back(delete_.id());
+
+ auto iterator = mBufferQueueSchedulers.find(delete_.id());
+ if (iterator != mBufferQueueSchedulers.end()) {
+ (*iterator).second->stopScheduling();
+ }
+
+ std::lock_guard<std::mutex> lock2(mLayerLock);
+ mComposerClient->destroySurface(mLayers[delete_.id()]->getHandle());
+
+ return NO_ERROR;
+}
+
+void Replayer::doDeleteSurfaceControls() {
+ std::lock_guard<std::mutex> lock1(mPendingLayersLock);
+ std::lock_guard<std::mutex> lock2(mLayerLock);
+ if (!mLayersPendingRemoval.empty()) {
+ for (int id : mLayersPendingRemoval) {
+ mLayers.erase(id);
+ mColors.erase(id);
+ mBufferQueueSchedulers.erase(id);
+ }
+ mLayersPendingRemoval.clear();
+ }
+}
+
+status_t Replayer::injectVSyncEvent(
+ const VSyncEvent& vSyncEvent, const std::shared_ptr<Event>& event) {
+ ALOGV("Injecting VSync Event");
+
+ doDeleteSurfaceControls();
+
+ event->readyToExecute();
+
+ SurfaceComposerClient::injectVSync(vSyncEvent.when());
+
+ return NO_ERROR;
+}
+
+void Replayer::waitUntilTimestamp(int64_t timestamp) {
+ ALOGV("Waiting for %lld nanoseconds...", static_cast<int64_t>(timestamp - mCurrentTime));
+ std::this_thread::sleep_for(std::chrono::nanoseconds(timestamp - mCurrentTime));
+}
+
+void Replayer::waitUntilDeferredTransactionLayerExists(
+ const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock) {
+ if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
+ mLayerCond.wait(lock, [&] { return (mLayers[dtc.layer_id()] != nullptr); });
+ }
+}
+
+status_t Replayer::loadSurfaceComposerClient() {
+ mComposerClient = new SurfaceComposerClient;
+ return mComposerClient->initCheck();
+}
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
new file mode 100644
index 0000000..ff951d1
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -0,0 +1,117 @@
+/*
+ * 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_SURFACEREPLAYER_H
+#define ANDROID_SURFACEREPLAYER_H
+
+#include "BufferQueueScheduler.h"
+#include "Color.h"
+#include "Event.h"
+
+#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+#include <utility>
+
+namespace android {
+
+const auto DEFAULT_PATH = "/data/local/tmp/SurfaceTrace.dat";
+const auto RAND_COLOR_SEED = 1000;
+const auto DEFAULT_THREADS = 3;
+
+typedef uint32_t layer_id;
+
+class Replayer {
+ public:
+ Replayer(const std::string& filename, bool replayManually = false,
+ int numThreads = DEFAULT_THREADS);
+ Replayer(const Trace& trace, bool replayManually = false, int numThreads = DEFAULT_THREADS);
+
+ status_t replay();
+
+ private:
+ status_t initReplay();
+
+ void waitForConsoleCommmand();
+ static void stopAutoReplayHandler(int signal);
+
+ status_t dispatchEvent(int index);
+
+ status_t doTransaction(const Transaction& transaction, const std::shared_ptr<Event>& event);
+ status_t createSurfaceControl(const Create& create, const std::shared_ptr<Event>& event);
+ status_t deleteSurfaceControl(const Delete& delete_, const std::shared_ptr<Event>& event);
+ status_t injectVSyncEvent(const VSyncEvent& vsyncEvent, const std::shared_ptr<Event>& event);
+
+ status_t setPosition(uint32_t id, const PositionChange& pc);
+ status_t setSize(uint32_t id, const SizeChange& sc);
+ status_t setAlpha(uint32_t id, const AlphaChange& ac);
+ status_t setLayer(uint32_t id, const LayerChange& lc);
+ status_t setCrop(uint32_t id, const CropChange& cc);
+ status_t setFinalCrop(uint32_t id, const FinalCropChange& fcc);
+ status_t setMatrix(uint32_t id, const MatrixChange& mc);
+ status_t setOverrideScalingMode(uint32_t id, const OverrideScalingModeChange& osmc);
+ status_t setTransparentRegionHint(uint32_t id, const TransparentRegionHintChange& trgc);
+ status_t setLayerStack(uint32_t id, const LayerStackChange& lsc);
+ status_t setHiddenFlag(uint32_t id, const HiddenFlagChange& hfc);
+ status_t setOpaqueFlag(uint32_t id, const OpaqueFlagChange& ofc);
+ status_t setSecureFlag(uint32_t id, const SecureFlagChange& sfc);
+ status_t setDeferredTransaction(uint32_t id, const DeferredTransactionChange& dtc);
+
+ void doDeleteSurfaceControls();
+ void waitUntilTimestamp(int64_t timestamp);
+ void waitUntilDeferredTransactionLayerExists(
+ const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock);
+ status_t loadSurfaceComposerClient();
+
+ Trace mTrace;
+ bool mLoaded = false;
+ int32_t mIncrementIndex = 0;
+ int64_t mCurrentTime = 0;
+ int32_t mNumThreads = DEFAULT_THREADS;
+
+ std::string mLastInput;
+
+ static atomic_bool sReplayingManually;
+ bool mWaitingForNextVSync;
+
+ std::mutex mLayerLock;
+ std::condition_variable mLayerCond;
+ std::unordered_map<layer_id, sp<SurfaceControl>> mLayers;
+ std::unordered_map<layer_id, RGB> mColors;
+
+ std::mutex mPendingLayersLock;
+ std::vector<layer_id> mLayersPendingRemoval;
+
+ std::mutex mBufferQueueSchedulerLock;
+ std::unordered_map<layer_id, std::shared_ptr<BufferQueueScheduler>> mBufferQueueSchedulers;
+
+ sp<SurfaceComposerClient> mComposerClient;
+ std::queue<std::shared_ptr<Event>> mPendingIncrements;
+};
+
+} // namespace android
+#endif
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index fe4b1fa..2bfb649 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -79,7 +79,8 @@
// needed gralloc buffers.
static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
- const sp<IGraphicBufferAlloc>& allocator = NULL);
+ const sp<IGraphicBufferAlloc>& allocator = NULL,
+ bool consumerIsSurfaceFlinger = false);
private:
BufferQueue(); // Create through createBufferQueue
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 838632c..d2bd32e 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -29,7 +29,7 @@
public:
friend class BufferQueue; // Needed to access binderDied
- BufferQueueProducer(const sp<BufferQueueCore>& core);
+ BufferQueueProducer(const sp<BufferQueueCore>& core, bool consumerIsSurfaceFlinger = false);
virtual ~BufferQueueProducer();
// requestBuffer returns the GraphicBuffer for slot N.
@@ -225,6 +225,10 @@
uint32_t mStickyTransform;
+ // This controls whether the GraphicBuffer pointer in the BufferItem is
+ // cleared after being queued
+ bool mConsumerIsSurfaceFlinger;
+
// This saves the fence from the last queueBuffer, such that the
// next queueBuffer call can throttle buffer production. The prior
// queueBuffer's fence is not nessessarily available elsewhere,
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 1efcf3c..9b0d919 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -49,7 +49,8 @@
// previous frames are pending. Frames queued while in synchronous mode
// always trigger the callback. The item passed to the callback will contain
// all of the information about the queued frame except for its
- // GraphicBuffer pointer, which will always be null.
+ // GraphicBuffer pointer, which will always be null (except if the consumer
+ // is SurfaceFlinger).
//
// This is called without any lock held and can be called concurrently
// by multiple threads.
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index c62bc58..9353042 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -339,20 +339,19 @@
void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; }
private:
- int64_t timestamp;
- int isAutoTimestamp;
- android_dataspace dataSpace;
+ int64_t timestamp{0};
+ int isAutoTimestamp{0};
+ android_dataspace dataSpace{HAL_DATASPACE_UNKNOWN};
Rect crop;
- int scalingMode;
- uint32_t transform;
- uint32_t stickyTransform;
+ int scalingMode{0};
+ uint32_t transform{0};
+ uint32_t stickyTransform{0};
sp<Fence> fence;
Region surfaceDamage;
};
// QueueBufferOutput must be a POD structure
struct __attribute__ ((__packed__)) QueueBufferOutput {
- inline QueueBufferOutput() { }
// outWidth - filled with default width applied to the buffer
// outHeight - filled with default height applied to the buffer
// outTransformHint - filled with default transform applied to the buffer
@@ -379,10 +378,10 @@
nextFrameNumber = inNextFrameNumber;
}
private:
- uint32_t width;
- uint32_t height;
- uint32_t transformHint;
- uint32_t numPendingBuffers;
+ uint32_t width{0};
+ uint32_t height{0};
+ uint32_t transformHint{0};
+ uint32_t numPendingBuffers{0};
uint64_t nextFrameNumber{0};
};
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 74a4123..74ccf95 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -171,6 +171,10 @@
*/
virtual status_t getHdrCapabilities(const sp<IBinder>& display,
HdrCapabilities* outCapabilities) const = 0;
+
+ virtual status_t enableVSyncInjections(bool enable) = 0;
+
+ virtual status_t injectVSync(nsecs_t when) = 0;
};
// ----------------------------------------------------------------------------
@@ -202,6 +206,8 @@
GET_DISPLAY_COLOR_MODES,
GET_ACTIVE_COLOR_MODE,
SET_ACTIVE_COLOR_MODE,
+ ENABLE_VSYNC_INJECTIONS,
+ INJECT_VSYNC
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 8177ec6..8574390 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -205,7 +205,6 @@
virtual int connect(int api);
virtual int disconnect(int api);
virtual int setBufferCount(int bufferCount);
- virtual int setBuffersDimensions(uint32_t width, uint32_t height);
virtual int setBuffersUserDimensions(uint32_t width, uint32_t height);
virtual int setBuffersFormat(PixelFormat format);
virtual int setBuffersTransform(uint32_t transform);
@@ -221,6 +220,7 @@
virtual int setAsyncMode(bool async);
virtual int setSharedBufferMode(bool sharedBufferMode);
virtual int setAutoRefresh(bool autoRefresh);
+ virtual int setBuffersDimensions(uint32_t width, uint32_t height);
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
virtual int unlockAndPost();
virtual int query(int what, int* value) const;
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index b8ee331..8f4ab7a 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -131,6 +131,10 @@
//! Close a composer transaction on all active SurfaceComposerClients.
static void closeGlobalTransaction(bool synchronous = false);
+ static status_t enableVSyncInjections(bool enable);
+
+ static status_t injectVSync(nsecs_t when);
+
//! Flag the currently open transaction as an animation transaction.
static void setAnimationTransaction();
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 7ae07ad..4c74bc5 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -107,6 +107,7 @@
case OMX_AUDIO_AACObjectLTP: return "LTP";
case OMX_AUDIO_AACObjectHE: return "HE";
case OMX_AUDIO_AACObjectScalable: return "Scalable";
+ case OMX_AUDIO_AACObjectER_Scalable: return "ER_Scalable";
case OMX_AUDIO_AACObjectERLC: return "ERLC";
case OMX_AUDIO_AACObjectLD: return "LD";
case OMX_AUDIO_AACObjectHE_PS: return "HE_PS";
diff --git a/include/media/openmax/OMX_Audio.h b/include/media/openmax/OMX_Audio.h
index d8bee76..9c0296b 100644
--- a/include/media/openmax/OMX_Audio.h
+++ b/include/media/openmax/OMX_Audio.h
@@ -259,6 +259,7 @@
OMX_AUDIO_AACObjectHE, /**< AAC High Efficiency (object type SBR, HE-AAC profile) */
OMX_AUDIO_AACObjectScalable, /**< AAC Scalable object */
OMX_AUDIO_AACObjectERLC = 17, /**< ER AAC Low Complexity object (Error Resilient AAC-LC) */
+ OMX_AUDIO_AACObjectER_Scalable = 20, /**< ER AAC scalable object */
OMX_AUDIO_AACObjectLD = 23, /**< AAC Low Delay object (Error Resilient) */
OMX_AUDIO_AACObjectHE_PS = 29, /**< AAC High Efficiency with Parametric Stereo coding (HE-AAC v2, object type PS) */
OMX_AUDIO_AACObjectELD = 39, /** AAC Enhanced Low Delay. NOTE: Pending Khronos standardization **/
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index b688d1d..78d1f5d 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -75,6 +75,8 @@
OMX_IndexConfigVideoVp8ReferenceFrame, /**< reference: OMX_VIDEO_VP8REFERENCEFRAMETYPE */
OMX_IndexConfigVideoVp8ReferenceFrameType, /**< reference: OMX_VIDEO_VP8REFERENCEFRAMEINFOTYPE */
OMX_IndexParamVideoAndroidVp8Encoder, /**< reference: OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE */
+ OMX_IndexParamVideoVp9, /**< reference: OMX_VIDEO_PARAM_VP9TYPE */
+ OMX_IndexParamVideoAndroidVp9Encoder, /**< reference: OMX_VIDEO_PARAM_ANDROID_VP9ENCODERTYPE */
OMX_IndexParamVideoHevc, /**< reference: OMX_VIDEO_PARAM_HEVCTYPE */
OMX_IndexParamSliceSegments, /**< reference: OMX_VIDEO_SLICESEGMENTSTYPE */
OMX_IndexConfigAndroidIntraRefresh, /**< reference: OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE */
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 2c02431..128dd2d 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -75,39 +75,6 @@
OMX_VIDEO_VP8LevelMax = 0x7FFFFFFF
} OMX_VIDEO_VP8LEVELTYPE;
-/** VP9 profiles */
-typedef enum OMX_VIDEO_VP9PROFILETYPE {
- OMX_VIDEO_VP9Profile0 = 0x1,
- OMX_VIDEO_VP9Profile1 = 0x2,
- OMX_VIDEO_VP9Profile2 = 0x4,
- OMX_VIDEO_VP9Profile3 = 0x8,
- // HDR profiles also support passing HDR metadata
- OMX_VIDEO_VP9Profile2HDR = 0x1000,
- OMX_VIDEO_VP9Profile3HDR = 0x2000,
- OMX_VIDEO_VP9ProfileUnknown = 0x6EFFFFFF,
- OMX_VIDEO_VP9ProfileMax = 0x7FFFFFFF
-} OMX_VIDEO_VP9PROFILETYPE;
-
-/** VP9 levels */
-typedef enum OMX_VIDEO_VP9LEVELTYPE {
- OMX_VIDEO_VP9Level1 = 0x1,
- OMX_VIDEO_VP9Level11 = 0x2,
- OMX_VIDEO_VP9Level2 = 0x4,
- OMX_VIDEO_VP9Level21 = 0x8,
- OMX_VIDEO_VP9Level3 = 0x10,
- OMX_VIDEO_VP9Level31 = 0x20,
- OMX_VIDEO_VP9Level4 = 0x40,
- OMX_VIDEO_VP9Level41 = 0x80,
- OMX_VIDEO_VP9Level5 = 0x100,
- OMX_VIDEO_VP9Level51 = 0x200,
- OMX_VIDEO_VP9Level52 = 0x400,
- OMX_VIDEO_VP9Level6 = 0x800,
- OMX_VIDEO_VP9Level61 = 0x1000,
- OMX_VIDEO_VP9Level62 = 0x2000,
- OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF,
- OMX_VIDEO_VP9LevelMax = 0x7FFFFFFF
-} OMX_VIDEO_VP9LEVELTYPE;
-
/** VP8 Param */
typedef struct OMX_VIDEO_PARAM_VP8TYPE {
OMX_U32 nSize;
@@ -152,7 +119,7 @@
} OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE;
/**
- * Android specific VP8 encoder params
+ * Android specific VP8/VP9 encoder params
*
* STRUCT MEMBERS:
* nSize : Size of the structure in bytes
@@ -182,6 +149,59 @@
OMX_U32 nMaxQuantizer;
} OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE;
+/** VP9 profiles */
+typedef enum OMX_VIDEO_VP9PROFILETYPE {
+ OMX_VIDEO_VP9Profile0 = 0x1,
+ OMX_VIDEO_VP9Profile1 = 0x2,
+ OMX_VIDEO_VP9Profile2 = 0x4,
+ OMX_VIDEO_VP9Profile3 = 0x8,
+ // HDR profiles also support passing HDR metadata
+ OMX_VIDEO_VP9Profile2HDR = 0x1000,
+ OMX_VIDEO_VP9Profile3HDR = 0x2000,
+ OMX_VIDEO_VP9ProfileUnknown = 0x6EFFFFFF,
+ OMX_VIDEO_VP9ProfileMax = 0x7FFFFFFF
+} OMX_VIDEO_VP9PROFILETYPE;
+
+/** VP9 levels */
+typedef enum OMX_VIDEO_VP9LEVELTYPE {
+ OMX_VIDEO_VP9Level1 = 0x0,
+ OMX_VIDEO_VP9Level11 = 0x1,
+ OMX_VIDEO_VP9Level2 = 0x2,
+ OMX_VIDEO_VP9Level21 = 0x4,
+ OMX_VIDEO_VP9Level3 = 0x8,
+ OMX_VIDEO_VP9Level31 = 0x10,
+ OMX_VIDEO_VP9Level4 = 0x20,
+ OMX_VIDEO_VP9Level41 = 0x40,
+ OMX_VIDEO_VP9Level5 = 0x80,
+ OMX_VIDEO_VP9Level51 = 0x100,
+ OMX_VIDEO_VP9Level52 = 0x200,
+ OMX_VIDEO_VP9Level6 = 0x400,
+ OMX_VIDEO_VP9Level61 = 0x800,
+ OMX_VIDEO_VP9Level62 = 0x1000,
+ OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF,
+ OMX_VIDEO_VP9LevelMax = 0x7FFFFFFF
+} OMX_VIDEO_VP9LEVELTYPE;
+
+/**
+* VP9 Parameters.
+* Encoder specific parameters (decoders should ignore these fields):
+* - bErrorResilientMode
+* - nTileRows
+* - nTileColumns
+* - bEnableFrameParallelDecoding
+*/
+typedef struct OMX_VIDEO_PARAM_VP9TYPE {
+ OMX_U32 nSize;
+ OMX_VERSIONTYPE nVersion;
+ OMX_U32 nPortIndex;
+ OMX_VIDEO_VP9PROFILETYPE eProfile;
+ OMX_VIDEO_VP9LEVELTYPE eLevel;
+ OMX_BOOL bErrorResilientMode;
+ OMX_U32 nTileRows;
+ OMX_U32 nTileColumns;
+ OMX_BOOL bEnableFrameParallelDecoding;
+} OMX_VIDEO_PARAM_VP9TYPE;
+
/** HEVC Profile enum type */
typedef enum OMX_VIDEO_HEVCPROFILETYPE {
OMX_VIDEO_HEVCProfileUnknown = 0x0,
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 4b3fcc6..292dd3b 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -74,10 +74,10 @@
status_t read(const Parcel& input);
struct matrix22_t {
- float dsdx;
- float dtdx;
- float dsdy;
- float dtdy;
+ float dsdx{0};
+ float dtdx{0};
+ float dsdy{0};
+ float dtdy{0};
};
sp<IBinder> surface;
uint32_t what;
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
index 799944f..842806e 100644
--- a/include/ui/DisplayInfo.h
+++ b/include/ui/DisplayInfo.h
@@ -26,16 +26,16 @@
namespace android {
struct DisplayInfo {
- uint32_t w;
- uint32_t h;
- float xdpi;
- float ydpi;
- float fps;
- float density;
- uint8_t orientation;
- bool secure;
- nsecs_t appVsyncOffset;
- nsecs_t presentationDeadline;
+ uint32_t w{0};
+ uint32_t h{0};
+ float xdpi{0};
+ float ydpi{0};
+ float fps{0};
+ float density{0};
+ uint8_t orientation{0};
+ bool secure{false};
+ nsecs_t appVsyncOffset{0};
+ nsecs_t presentationDeadline{0};
};
/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
diff --git a/include/ui/DisplayStatInfo.h b/include/ui/DisplayStatInfo.h
index 0549a83..09543ec 100644
--- a/include/ui/DisplayStatInfo.h
+++ b/include/ui/DisplayStatInfo.h
@@ -22,8 +22,8 @@
namespace android {
struct DisplayStatInfo {
- nsecs_t vsyncTime;
- nsecs_t vsyncPeriod;
+ nsecs_t vsyncTime{0};
+ nsecs_t vsyncPeriod{0};
};
}; // namespace android
diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp
index 4800f5b..77e3d23 100644
--- a/libs/binder/IMediaResourceMonitor.cpp
+++ b/libs/binder/IMediaResourceMonitor.cpp
@@ -25,7 +25,7 @@
class BpMediaResourceMonitor : public BpInterface<IMediaResourceMonitor> {
public:
- BpMediaResourceMonitor(const sp<IBinder>& impl)
+ explicit BpMediaResourceMonitor(const sp<IBinder>& impl)
: BpInterface<IMediaResourceMonitor>(impl) {}
virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type)
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index 2a22b69..646809e 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -31,7 +31,7 @@
class BpResultReceiver : public BpInterface<IResultReceiver>
{
public:
- BpResultReceiver(const sp<IBinder>& impl)
+ explicit BpResultReceiver(const sp<IBinder>& impl)
: BpInterface<IResultReceiver>(impl)
{
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index d566456..f04f754 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -784,7 +784,7 @@
const uint8_t* strData = (uint8_t*)str.data();
const size_t strLen= str.length();
const ssize_t utf16Len = utf8_to_utf16_length(strData, strLen);
- if (utf16Len < 0 || utf16Len> std::numeric_limits<int32_t>::max()) {
+ if (utf16Len < 0 || utf16Len > std::numeric_limits<int32_t>::max()) {
return BAD_VALUE;
}
@@ -799,7 +799,7 @@
return NO_MEMORY;
}
- utf8_to_utf16(strData, strLen, (char16_t*)dst);
+ utf8_to_utf16(strData, strLen, (char16_t*)dst, (size_t) utf16Len + 1);
return NO_ERROR;
}
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 5e3924a..2ffeb0d 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -66,6 +66,9 @@
addAligned(size, mIsDroppable);
addAligned(size, mAcquireCalled);
addAligned(size, mTransformToDisplayInverse);
+ addAligned(size, mAutoRefresh);
+ addAligned(size, mQueuedBuffer);
+ addAligned(size, mIsStale);
return size;
}
@@ -151,6 +154,9 @@
writeAligned(buffer, size, mIsDroppable);
writeAligned(buffer, size, mAcquireCalled);
writeAligned(buffer, size, mTransformToDisplayInverse);
+ writeAligned(buffer, size, mAutoRefresh);
+ writeAligned(buffer, size, mQueuedBuffer);
+ writeAligned(buffer, size, mIsStale);
return NO_ERROR;
}
@@ -207,6 +213,9 @@
readAligned(buffer, size, mIsDroppable);
readAligned(buffer, size, mAcquireCalled);
readAligned(buffer, size, mTransformToDisplayInverse);
+ readAligned(buffer, size, mAutoRefresh);
+ readAligned(buffer, size, mQueuedBuffer);
+ readAligned(buffer, size, mIsStale);
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 6de98f5..47f5eba 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -72,7 +72,8 @@
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
- const sp<IGraphicBufferAlloc>& allocator) {
+ const sp<IGraphicBufferAlloc>& allocator,
+ bool consumerIsSurfaceFlinger) {
LOG_ALWAYS_FATAL_IF(outProducer == NULL,
"BufferQueue: outProducer must not be NULL");
LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
@@ -82,7 +83,7 @@
LOG_ALWAYS_FATAL_IF(core == NULL,
"BufferQueue: failed to create BufferQueueCore");
- sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
+ sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
LOG_ALWAYS_FATAL_IF(producer == NULL,
"BufferQueue: failed to create BufferQueueProducer");
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 3367830..83ec7ef 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -92,6 +92,7 @@
mSharedBufferSlot(INVALID_BUFFER_SLOT),
mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
HAL_DATASPACE_UNKNOWN),
+ mLastQueuedSlot(INVALID_BUFFER_SLOT),
mUniqueId(getUniqueId())
{
if (allocator == NULL) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index b7b56f0..3411dca 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -41,12 +41,15 @@
namespace android {
-BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core) :
+BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
+ bool consumerIsSurfaceFlinger) :
mCore(core),
mSlots(core->mSlots),
mConsumerName(),
mStickyTransform(0),
+ mConsumerIsSurfaceFlinger(consumerIsSurfaceFlinger),
mLastQueueBufferFence(Fence::NO_FENCE),
+ mLastQueuedTransform(0),
mCallbackMutex(),
mNextCallbackTicket(0),
mCurrentCallbackTicket(0),
@@ -912,9 +915,14 @@
VALIDATE_CONSISTENCY();
} // Autolock scope
- // Don't send the GraphicBuffer through the callback, and don't send
- // the slot number, since the consumer shouldn't need it
- item.mGraphicBuffer.clear();
+ // It is okay not to clear the GraphicBuffer when the consumer is SurfaceFlinger because
+ // it is guaranteed that the BufferQueue is inside SurfaceFlinger's process and
+ // there will be no Binder call
+ if (!mConsumerIsSurfaceFlinger) {
+ item.mGraphicBuffer.clear();
+ }
+
+ // Don't send the slot number through the callback since the consumer shouldn't need it
item.mSlot = BufferItem::INVALID_BUFFER_SLOT;
// Call back without the main BufferQueue lock held, but with the callback
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index d4d4702..ac6ace6 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -101,7 +101,7 @@
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
uint32_t usage = data.readUint32();
- status_t error;
+ status_t error = NO_ERROR;
sp<GraphicBuffer> result =
createGraphicBuffer(width, height, format, usage, &error);
reply->writeInt32(error);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 0a8e6a5..6c1662c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -383,6 +383,48 @@
}
return result;
}
+
+ virtual status_t enableVSyncInjections(bool enable) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("enableVSyncInjections failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeBool(enable);
+ if (result != NO_ERROR) {
+ ALOGE("enableVSyncInjections failed to writeBool: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS,
+ data, &reply, TF_ONE_WAY);
+ if (result != NO_ERROR) {
+ ALOGE("enableVSyncInjections failed to transact: %d", result);
+ return result;
+ }
+ return result;
+ }
+
+ virtual status_t injectVSync(nsecs_t when) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("injectVSync failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeInt64(when);
+ if (result != NO_ERROR) {
+ ALOGE("injectVSync failed to writeInt64: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply, TF_ONE_WAY);
+ if (result != NO_ERROR) {
+ ALOGE("injectVSync failed to transact: %d", result);
+ return result;
+ }
+ return result;
+ }
+
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -635,6 +677,26 @@
}
return NO_ERROR;
}
+ case ENABLE_VSYNC_INJECTIONS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ bool enable = false;
+ status_t result = data.readBool(&enable);
+ if (result != NO_ERROR) {
+ ALOGE("enableVSyncInjections failed to readBool: %d", result);
+ return result;
+ }
+ return enableVSyncInjections(enable);
+ }
+ case INJECT_VSYNC: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int64_t when = 0;
+ status_t result = data.readInt64(&when);
+ if (result != NO_ERROR) {
+ ALOGE("enableVSyncInjections failed to readInt64: %d", result);
+ return result;
+ }
+ return injectVSync(when);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1c460e8..f87fd18 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -129,6 +129,8 @@
void openGlobalTransactionImpl();
void closeGlobalTransactionImpl(bool synchronous);
void setAnimationTransactionImpl();
+ status_t enableVSyncInjectionsImpl(bool enable);
+ status_t injectVSyncImpl(nsecs_t when);
layer_state_t* getLayerStateLocked(
const sp<SurfaceComposerClient>& client, const sp<IBinder>& id);
@@ -190,6 +192,14 @@
static void closeGlobalTransaction(bool synchronous) {
Composer::getInstance().closeGlobalTransactionImpl(synchronous);
}
+
+ static status_t enableVSyncInjections(bool enable) {
+ return Composer::getInstance().enableVSyncInjectionsImpl(enable);
+ }
+
+ static status_t injectVSync(nsecs_t when) {
+ return Composer::getInstance().injectVSyncImpl(when);
+ }
};
ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
@@ -253,6 +263,16 @@
sm->setTransactionState(transaction, displayTransaction, flags);
}
+status_t Composer::enableVSyncInjectionsImpl(bool enable) {
+ sp<ISurfaceComposer> sm(ComposerService::getComposerService());
+ return sm->enableVSyncInjections(enable);
+}
+
+status_t Composer::injectVSyncImpl(nsecs_t when) {
+ sp<ISurfaceComposer> sm(ComposerService::getComposerService());
+ return sm->injectVSync(when);
+}
+
void Composer::setAnimationTransactionImpl() {
Mutex::Autolock _l(mLock);
mAnimation = true;
@@ -640,6 +660,14 @@
Composer::setAnimationTransaction();
}
+status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
+ return Composer::enableVSyncInjections(enable);
+}
+
+status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
+ return Composer::injectVSync(when);
+}
+
// ----------------------------------------------------------------------------
status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) {
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 4fbaa50..04127ac 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -53,13 +53,15 @@
SENSORS_HARDWARE_MODULE_ID, strerror(-err));
if (mSensorDevice) {
- if (mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_1 ||
- mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_2) {
- ALOGE(">>>> WARNING <<< Upgrade sensor HAL to version 1_3");
- }
sensor_t const* list;
ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
+
+ if (mSensorDevice->common.version < SENSORS_DEVICE_API_VERSION_1_3) {
+ ALOGE(">>>> WARNING <<< Upgrade sensor HAL to version 1_3, ignoring sensors reported by this device");
+ count = 0;
+ }
+
mActivationCount.setCapacity(count);
Info model;
for (size_t i=0 ; i<size_t(count) ; i++) {
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index dc708e8..6c48b28 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -18,6 +18,7 @@
MessageQueue.cpp \
MonitoredProducer.cpp \
SurfaceFlingerConsumer.cpp \
+ SurfaceInterceptor.cpp \
Transform.cpp \
DisplayHardware/FramebufferSurface.cpp \
DisplayHardware/HWC2.cpp \
@@ -36,11 +37,12 @@
RenderEngine/Texture.cpp \
RenderEngine/GLES10RenderEngine.cpp \
RenderEngine/GLES11RenderEngine.cpp \
- RenderEngine/GLES20RenderEngine.cpp
+ RenderEngine/GLES20RenderEngine.cpp \
+LOCAL_MODULE := libsurfaceflinger
LOCAL_C_INCLUDES := \
- frameworks/native/vulkan/include \
- external/vulkan-validation-layers/libs/vkjson
+ frameworks/native/vulkan/include \
+ external/vulkan-validation-layers/libs/vkjson \
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
@@ -108,7 +110,7 @@
LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
LOCAL_CFLAGS += -std=c++14
-LOCAL_STATIC_LIBRARIES := libvkjson
+LOCAL_STATIC_LIBRARIES := libtrace_proto libvkjson
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
@@ -122,9 +124,8 @@
libui \
libgui \
libpowermanager \
- libvulkan
-
-LOCAL_MODULE := libsurfaceflinger
+ libvulkan \
+ libprotobuf-cpp-full
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
@@ -163,6 +164,7 @@
libdl
LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
+LOCAL_STATIC_LIBRARIES := libtrace_proto
LOCAL_MODULE := surfaceflinger
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index c67feb3..245c27b 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -64,7 +64,7 @@
class DispSyncThread: public Thread {
public:
- DispSyncThread(const char* name):
+ explicit DispSyncThread(const char* name):
mName(name),
mStop(false),
mPeriod(0),
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index 8bcee39..7bca0f1 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -93,7 +93,7 @@
class HWC2On1Adapter::Callbacks : public hwc_procs_t {
public:
- Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
+ explicit Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
invalidate = &invalidateHook;
vsync = &vsyncHook;
hotplug = &hotplugHook;
@@ -560,6 +560,7 @@
mHwc1Id(-1),
mConfigs(),
mActiveConfig(nullptr),
+ mActiveColorMode(static_cast<android_color_mode_t>(-1)),
mName(),
mType(type),
mPowerMode(PowerMode::Off),
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
index bdacc73..e447c3c 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
@@ -247,6 +247,7 @@
public:
Config(Display& display)
: mDisplay(display),
+ mId(0),
mAttributes() {}
bool isOnDisplay(const Display& display) const {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
index ef41658..2102457 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -933,7 +933,7 @@
protected:
HWCTYPE* const mLayerList;
HWCTYPE* mCurrentLayer;
- Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer),
+ explicit Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer),
mIndex(0) { }
inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
inline HWCTYPE* getLayer() { return mCurrentLayer; }
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index dd88adb..bdd94e3 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -226,6 +226,7 @@
timestamp = mVSyncEvent[i].header.timestamp;
if (timestamp) {
// we have a vsync event to dispatch
+ mFlinger.mInterceptor.saveVSyncEvent(timestamp);
*event = mVSyncEvent[i];
mVSyncEvent[i].header.timestamp = 0;
vsyncCount = mVSyncEvent[i].vsync.count;
diff --git a/services/surfaceflinger/GpuService.cpp b/services/surfaceflinger/GpuService.cpp
index 70d9682..b993dfb 100644
--- a/services/surfaceflinger/GpuService.cpp
+++ b/services/surfaceflinger/GpuService.cpp
@@ -27,7 +27,7 @@
class BpGpuService : public BpInterface<IGpuService>
{
public:
- BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
+ explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
};
IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService");
@@ -92,82 +92,27 @@
}
fprintf(outs,
"GPU Service commands:\n"
- " vkjson dump Vulkan device capabilities as JSON\n");
+ " vkjson dump Vulkan properties as JSON\n");
fclose(outs);
return NO_ERROR;
}
-VkResult vkjsonPrint(FILE* out, FILE* err) {
- VkResult result;
-
- const VkApplicationInfo app_info = {
- VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr,
- "vkjson", 1, /* app name, version */
- "", 0, /* engine name, version */
- VK_API_VERSION_1_0
- };
- const VkInstanceCreateInfo instance_info = {
- VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, nullptr,
- 0, /* flags */
- &app_info,
- 0, nullptr, /* layers */
- 0, nullptr, /* extensions */
- };
- VkInstance instance;
- result = vkCreateInstance(&instance_info, nullptr, &instance);
- if (result != VK_SUCCESS) {
- fprintf(err, "vkCreateInstance failed: %d\n", result);
- return result;
- }
-
- uint32_t ngpu = 0;
- result = vkEnumeratePhysicalDevices(instance, &ngpu, nullptr);
- if (result != VK_SUCCESS) {
- fprintf(err, "vkEnumeratePhysicalDevices failed: %d\n", result);
- return result;
- }
- std::vector<VkPhysicalDevice> gpus(ngpu, VK_NULL_HANDLE);
- result = vkEnumeratePhysicalDevices(instance, &ngpu, gpus.data());
- if (result != VK_SUCCESS) {
- fprintf(err, "vkEnumeratePhysicalDevices failed: %d\n", result);
- return result;
- }
-
- for (size_t i = 0, n = gpus.size(); i < n; i++) {
- auto props = VkJsonGetAllProperties(gpus[i]);
- std::string json = VkJsonAllPropertiesToJson(props);
- fwrite(json.data(), 1, json.size(), out);
- if (i < n - 1)
- fputc(',', out);
- fputc('\n', out);
- }
-
- vkDestroyInstance(instance, nullptr);
-
- return VK_SUCCESS;
+void vkjsonPrint(FILE* out) {
+ std::string json = VkJsonInstanceToJson(VkJsonGetInstance());
+ fwrite(json.data(), 1, json.size(), out);
+ fputc('\n', out);
}
-status_t cmd_vkjson(int out, int err) {
- int errnum;
+status_t cmd_vkjson(int out, int /*err*/) {
FILE* outs = fdopen(out, "w");
if (!outs) {
- errnum = errno;
+ int errnum = errno;
ALOGE("vkjson: failed to create output stream: %s", strerror(errnum));
return -errnum;
}
- FILE* errs = fdopen(err, "w");
- if (!errs) {
- errnum = errno;
- ALOGE("vkjson: failed to create error stream: %s", strerror(errnum));
- fclose(outs);
- return -errnum;
- }
- fprintf(outs, "[\n");
- VkResult result = vkjsonPrint(outs, errs);
- fprintf(outs, "]\n");
- fclose(errs);
+ vkjsonPrint(outs);
fclose(outs);
- return result >= 0 ? NO_ERROR : UNKNOWN_ERROR;
+ return NO_ERROR;
}
} // anonymous namespace
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index efcbe80..15150e6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -155,10 +155,9 @@
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
+ BufferQueue::createBufferQueue(&producer, &consumer, nullptr, true);
mProducer = new MonitoredProducer(producer, mFlinger);
- mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName,
- this);
+ mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
@@ -212,7 +211,8 @@
// Add this buffer from our internal queue tracker
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
-
+ mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+ item.mGraphicBuffer->getHeight(), item.mFrameNumber);
// Reset the frame number tracker when we receive the first buffer after
// a frame number reset
if (item.mFrameNumber == 1) {
@@ -312,22 +312,6 @@
return NO_ERROR;
}
-/*
- * The layer handle is just a BBinder object passed to the client
- * (remote process) -- we don't keep any reference on our side such that
- * the dtor is called when the remote side let go of its reference.
- *
- * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
- * this layer when the handle is destroyed.
- */
-class Layer::Handle : public BBinder, public LayerCleaner {
- public:
- Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
- : LayerCleaner(flinger, layer), owner(layer) {}
-
- wp<Layer> owner;
-};
-
sp<IBinder> Layer::getHandle() {
Mutex::Autolock _l(mLock);
@@ -2281,17 +2265,6 @@
// ---------------------------------------------------------------------------
-Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
- const sp<Layer>& layer)
- : mFlinger(flinger), mLayer(layer) {
-}
-
-Layer::LayerCleaner::~LayerCleaner() {
- // destroy client resources
- mFlinger->onLayerDestroyed(mLayer);
-}
-
-// ---------------------------------------------------------------------------
}; // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c070539..a63656e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -180,11 +180,6 @@
Rect computeBounds(const Region& activeTransparentRegion) const;
Rect computeBounds() const;
- class Handle;
- sp<IBinder> getHandle();
- sp<IGraphicBufferProducer> getProducer() const;
- const String8& getName() const;
-
int32_t getSequence() const { return sequence; }
// -----------------------------------------------------------------------
@@ -423,9 +418,6 @@
protected:
// constant
sp<SurfaceFlinger> mFlinger;
-
- virtual void onFirstRef();
-
/*
* Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer)
* is called.
@@ -434,13 +426,24 @@
sp<SurfaceFlinger> mFlinger;
wp<Layer> mLayer;
protected:
- ~LayerCleaner();
+ ~LayerCleaner() {
+ // destroy client resources
+ mFlinger->onLayerDestroyed(mLayer);
+ }
public:
- LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer);
+ LayerCleaner(const sp<SurfaceFlinger>& flinger,
+ const sp<Layer>& layer)
+ : mFlinger(flinger), mLayer(layer) {
+ }
};
+ virtual void onFirstRef();
+
+
+
private:
+ friend class SurfaceInterceptor;
// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
virtual void onFrameAvailable(const BufferItem& item) override;
virtual void onFrameReplaced(const BufferItem& item) override;
@@ -527,6 +530,25 @@
// the Surface Controller) if set.
uint32_t getEffectiveScalingMode() const;
public:
+ /*
+ * The layer handle is just a BBinder object passed to the client
+ * (remote process) -- we don't keep any reference on our side such that
+ * the dtor is called when the remote side let go of its reference.
+ *
+ * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
+ * this layer when the handle is destroyed.
+ */
+ class Handle : public BBinder, public LayerCleaner {
+ public:
+ Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+ : LayerCleaner(flinger, layer), owner(layer) {}
+
+ wp<Layer> owner;
+ };
+
+ sp<IBinder> getHandle();
+ sp<IGraphicBufferProducer> getProducer() const;
+ const String8& getName() const;
void notifyAvailableFrames();
private:
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index d6a032f..ed6f6cd 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -317,7 +317,7 @@
KeyedVector<Attribute, EGLint> mList;
struct Attribute {
Attribute() : v(0) {};
- Attribute(EGLint v) : v(v) { }
+ explicit Attribute(EGLint v) : v(v) { }
EGLint v;
bool operator < (const Attribute& other) const {
// this places EGL_NONE at the end
@@ -338,18 +338,18 @@
public:
void operator = (EGLint value) {
if (attribute != EGL_NONE) {
- v.mList.add(attribute, value);
+ v.mList.add(Attribute(attribute), value);
}
}
operator EGLint () const { return v.mList[attribute]; }
};
public:
EGLAttributeVector() {
- mList.add(EGL_NONE, EGL_NONE);
+ mList.add(Attribute(EGL_NONE), EGL_NONE);
}
void remove(EGLint attribute) {
if (attribute != EGL_NONE) {
- mList.removeItem(attribute);
+ mList.removeItem(Attribute(attribute));
}
}
Adder operator [] (EGLint attribute) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 13e440d..2cf8fb2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <errno.h>
#include <math.h>
+#include <mutex>
#include <dlfcn.h>
#include <inttypes.h>
#include <stdatomic.h>
@@ -162,6 +163,7 @@
mLastTransactionTime(0),
mBootFinished(false),
mForceFullDamage(false),
+ mInterceptor(),
mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
@@ -244,7 +246,7 @@
flinger->setTransactionFlags(eDisplayTransactionNeeded);
}
public:
- DisplayToken(const sp<SurfaceFlinger>& flinger)
+ explicit DisplayToken(const sp<SurfaceFlinger>& flinger)
: flinger(flinger) {
}
};
@@ -458,6 +460,30 @@
bool mEnabled;
};
+class InjectVSyncSource : public VSyncSource {
+public:
+ InjectVSyncSource() {}
+
+ virtual ~InjectVSyncSource() {}
+
+ virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ std::lock_guard<std::mutex> lock(mCallbackMutex);
+ mCallback = callback;
+ }
+
+ virtual void onInjectSyncEvent(nsecs_t when) {
+ std::lock_guard<std::mutex> lock(mCallbackMutex);
+ mCallback->onVSyncEvent(when);
+ }
+
+ virtual void setVSyncEnabled(bool) {}
+ virtual void setPhaseOffset(nsecs_t) {}
+
+private:
+ std::mutex mCallbackMutex; // Protects the following
+ sp<VSyncSource::Callback> mCallback;
+};
+
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
@@ -855,6 +881,40 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
+ if (enable == mInjectVSyncs) {
+ return NO_ERROR;
+ }
+
+ if (enable) {
+ mInjectVSyncs = enable;
+ ALOGV("VSync Injections enabled");
+ if (mVSyncInjector.get() == nullptr) {
+ mVSyncInjector = new InjectVSyncSource();
+ mInjectorEventThread = new EventThread(mVSyncInjector, *this);
+ }
+ mEventQueue.setEventThread(mInjectorEventThread);
+ } else {
+ mInjectVSyncs = enable;
+ ALOGV("VSync Injections disabled");
+ mEventQueue.setEventThread(mSFEventThread);
+ mVSyncInjector.clear();
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::injectVSync(nsecs_t when) {
+ if (!mInjectVSyncs) {
+ ALOGE("VSync Injections not enabled");
+ return BAD_VALUE;
+ }
+ if (mInjectVSyncs && mInjectorEventThread.get() != nullptr) {
+ ALOGV("Injecting VSync inside SurfaceFlinger");
+ mVSyncInjector->onInjectSyncEvent(when);
+ }
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@@ -2305,6 +2365,8 @@
}
if (transactionFlags) {
+ mInterceptor.saveLayerUpdates(state, flags);
+
// this triggers the transaction
setTransactionFlags(transactionFlags);
@@ -2465,7 +2527,6 @@
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{
- //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
if (int32_t(w|h) < 0) {
ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
int(w), int(h));
@@ -2500,6 +2561,7 @@
if (result != NO_ERROR) {
return result;
}
+ mInterceptor.saveLayerCreate(layer);
setTransactionFlags(eTransactionNeeded);
return result;
@@ -2547,6 +2609,7 @@
status_t err = NO_ERROR;
sp<Layer> l(client->getLayerUser(handle));
if (l != NULL) {
+ mInterceptor.saveLayerDelete(l);
err = removeLayer(l);
ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
"error removing layer=%p (%s)", l.get(), strerror(-err));
@@ -2597,7 +2660,7 @@
class MessageScreenInitialized : public MessageBase {
SurfaceFlinger* flinger;
public:
- MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
+ explicit MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
virtual bool handler() {
flinger->onInitializeDisplays();
return true;
@@ -3277,6 +3340,18 @@
mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
return NO_ERROR;
}
+ case 1020: { // Layer updates interceptor
+ n = data.readInt32();
+ if (n) {
+ ALOGV("Interceptor enabled");
+ mInterceptor.enable(mDrawingState.layersSortedByZ);
+ }
+ else{
+ ALOGV("Interceptor disabled");
+ mInterceptor.disable();
+ }
+ return NO_ERROR;
+ }
}
}
return err;
@@ -3373,7 +3448,7 @@
}
public:
- GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
+ explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
: impl(impl),
looper(new Looper(true)),
result(NO_ERROR),
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f50f9e7..664c28f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -56,6 +56,7 @@
#include "FenceTracker.h"
#include "FrameTracker.h"
#include "MessageQueue.h"
+#include "SurfaceInterceptor.h"
#include "DisplayHardware/HWComposer.h"
#include "Effects/Daltonizer.h"
@@ -76,6 +77,8 @@
class Surface;
class RenderEngine;
class EventControlThread;
+class VSyncSource;
+class InjectVSyncSource;
// ---------------------------------------------------------------------------
@@ -148,6 +151,7 @@
private:
friend class Client;
friend class DisplayEventConnection;
+ friend class EventThread;
friend class Layer;
friend class MonitoredProducer;
@@ -234,6 +238,9 @@
virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
virtual status_t getHdrCapabilities(const sp<IBinder>& display,
HdrCapabilities* outCapabilities) const;
+ virtual status_t enableVSyncInjections(bool enable);
+ virtual status_t injectVSync(nsecs_t when);
+
/* ------------------------------------------------------------------------
* DeathRecipient interface
@@ -489,6 +496,8 @@
bool mGpuToCpuSupported;
sp<EventThread> mEventThread;
sp<EventThread> mSFEventThread;
+ sp<EventThread> mInjectorEventThread;
+ sp<InjectVSyncSource> mVSyncInjector;
sp<EventControlThread> mEventControlThread;
EGLContext mEGLContext;
EGLDisplay mEGLDisplay;
@@ -529,6 +538,7 @@
#ifdef USE_HWC2
bool mPropagateBackpressure = true;
#endif
+ SurfaceInterceptor mInterceptor;
// these are thread safe
mutable MessageQueue mEventQueue;
@@ -548,6 +558,8 @@
* Feature prototyping
*/
+ bool mInjectVSyncs;
+
Daltonizer mDaltonizer;
#ifndef USE_HWC2
bool mDaltonize;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index e7f911e..2cf1828 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <errno.h>
#include <math.h>
+#include <mutex>
#include <dlfcn.h>
#include <inttypes.h>
#include <stdatomic.h>
@@ -92,6 +93,19 @@
EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+// Workaround for b/30067360: /proc/self/environ inaccessible in SurfaceFlinger
+// => ASan fails to read ASAN_OPTIONS => alloc-dealloc-mismatch bug is not
+// suppressed and prevents the device from booting.
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+#if __has_feature(address_sanitizer)
+__attribute__((visibility("default")))
+extern "C" const char *__asan_default_options() {
+ return "alloc_dealloc_mismatch=0";
+}
+#endif
+
namespace android {
// This is the phase offset in nanoseconds of the software vsync event
@@ -150,6 +164,7 @@
mLastTransactionTime(0),
mBootFinished(false),
mForceFullDamage(false),
+ mInterceptor(),
mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
@@ -229,7 +244,7 @@
flinger->setTransactionFlags(eDisplayTransactionNeeded);
}
public:
- DisplayToken(const sp<SurfaceFlinger>& flinger)
+ explicit DisplayToken(const sp<SurfaceFlinger>& flinger)
: flinger(flinger) {
}
};
@@ -442,6 +457,30 @@
bool mEnabled;
};
+class InjectVSyncSource : public VSyncSource {
+public:
+ InjectVSyncSource() {}
+
+ virtual ~InjectVSyncSource() {}
+
+ virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ std::lock_guard<std::mutex> lock(mCallbackMutex);
+ mCallback = callback;
+ }
+
+ virtual void onInjectSyncEvent(nsecs_t when) {
+ std::lock_guard<std::mutex> lock(mCallbackMutex);
+ mCallback->onVSyncEvent(when);
+ }
+
+ virtual void setVSyncEnabled(bool) {}
+ virtual void setPhaseOffset(nsecs_t) {}
+
+private:
+ std::mutex mCallbackMutex; // Protects the following
+ sp<VSyncSource::Callback> mCallback;
+};
+
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
@@ -805,6 +844,40 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
+ if (enable == mInjectVSyncs) {
+ return NO_ERROR;
+ }
+
+ if (enable) {
+ mInjectVSyncs = enable;
+ ALOGV("VSync Injections enabled");
+ if (mVSyncInjector.get() == nullptr) {
+ mVSyncInjector = new InjectVSyncSource();
+ mInjectorEventThread = new EventThread(mVSyncInjector, *this);
+ }
+ mEventQueue.setEventThread(mInjectorEventThread);
+ } else {
+ mInjectVSyncs = enable;
+ ALOGV("VSync Injections disabled");
+ mEventQueue.setEventThread(mSFEventThread);
+ mVSyncInjector.clear();
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::injectVSync(nsecs_t when) {
+ if (!mInjectVSyncs) {
+ ALOGE("VSync Injections not enabled");
+ return BAD_VALUE;
+ }
+ if (mInjectVSyncs && mInjectorEventThread.get() != nullptr) {
+ ALOGV("Injecting VSync inside SurfaceFlinger");
+ mVSyncInjector->onInjectSyncEvent(when);
+ }
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@@ -2209,6 +2282,8 @@
}
if (transactionFlags) {
+ mInterceptor.saveLayerUpdates(state, flags);
+
// this triggers the transaction
setTransactionFlags(transactionFlags);
@@ -2369,7 +2444,6 @@
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{
- //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
if (int32_t(w|h) < 0) {
ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
int(w), int(h));
@@ -2404,6 +2478,7 @@
if (result != NO_ERROR) {
return result;
}
+ mInterceptor.saveLayerCreate(layer);
setTransactionFlags(eTransactionNeeded);
return result;
@@ -2451,6 +2526,7 @@
status_t err = NO_ERROR;
sp<Layer> l(client->getLayerUser(handle));
if (l != NULL) {
+ mInterceptor.saveLayerDelete(l);
err = removeLayer(l);
ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
"error removing layer=%p (%s)", l.get(), strerror(-err));
@@ -2501,7 +2577,7 @@
class MessageScreenInitialized : public MessageBase {
SurfaceFlinger* flinger;
public:
- MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
+ explicit MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
virtual bool handler() {
flinger->onInitializeDisplays();
return true;
@@ -3178,6 +3254,18 @@
mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
return NO_ERROR;
}
+ case 1020: { // Layer updates interceptor
+ n = data.readInt32();
+ if (n) {
+ ALOGV("Interceptor enabled");
+ mInterceptor.enable(mDrawingState.layersSortedByZ);
+ }
+ else{
+ ALOGV("Interceptor disabled");
+ mInterceptor.disable();
+ }
+ return NO_ERROR;
+ }
}
}
return err;
@@ -3274,7 +3362,7 @@
}
public:
- GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
+ explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
: impl(impl),
looper(new Looper(true)),
result(NO_ERROR),
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
new file mode 100644
index 0000000..c860228
--- /dev/null
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -0,0 +1,411 @@
+/*
+ * 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 "SurfaceInterceptor"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "Layer.h"
+#include "SurfaceFlinger.h"
+#include "SurfaceInterceptor.h"
+
+#include <cutils/log.h>
+
+#include <utils/Trace.h>
+
+#include <fstream>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+void SurfaceInterceptor::enable(const SortedVector<sp<Layer>>& layers) {
+ ATRACE_CALL();
+ if (mEnabled) {
+ return;
+ }
+ mEnabled = true;
+ saveExistingLayers(layers);
+}
+
+void SurfaceInterceptor::disable() {
+ ATRACE_CALL();
+ if (!mEnabled) {
+ return;
+ }
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ mEnabled = false;
+ status_t err(writeProtoFileLocked());
+ ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
+ ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
+ mTrace.Clear();
+}
+
+void SurfaceInterceptor::saveExistingLayers(const SortedVector<sp<Layer>>& layers) {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ for (const auto& layer : layers) {
+ saveLayerCreateLocked(layer);
+ saveInitialLayerStateLocked(layer);
+ }
+}
+
+void SurfaceInterceptor::saveInitialLayerStateLocked(const sp<const Layer>& layer) {
+ ATRACE_CALL();
+ if (layer == nullptr) {
+ return;
+ }
+ Increment* increment(addTraceIncrementLocked());
+ Transaction* transaction(increment->mutable_transaction());
+ transaction->set_synchronous(layer->mTransactionFlags & BnSurfaceComposer::eSynchronous);
+ transaction->set_animation(layer->mTransactionFlags & BnSurfaceComposer::eAnimation);
+
+ const int32_t layerId(getLayerId(layer));
+ addPositionLocked(transaction, layerId, layer->mCurrentState.active.transform.tx(),
+ layer->mCurrentState.active.transform.ty());
+ addDepthLocked(transaction, layerId, layer->mCurrentState.z);
+ addSizeLocked(transaction, layerId, layer->mCurrentState.active.w,
+ layer->mCurrentState.active.h);
+ addAlphaLocked(transaction, layerId, layer->mCurrentState.alpha);
+ addTransparentRegionLocked(transaction, layerId, layer->mCurrentState.activeTransparentRegion);
+ addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
+ addCropLocked(transaction, layerId, layer->mCurrentState.crop);
+ if (layer->mCurrentState.handle != NULL) {
+ addDeferTransactionLocked(transaction, layerId, layer->mCurrentState.handle,
+ layer->mCurrentState.frameNumber);
+ }
+ addFinalCropLocked(transaction, layerId, layer->mCurrentState.finalCrop);
+ addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
+ addFlagsLocked(transaction, layerId, layer->mCurrentState.flags);
+}
+
+status_t SurfaceInterceptor::writeProtoFileLocked() {
+ ATRACE_CALL();
+ std::ofstream output(mOutputFileName, std::ios::out | std::ios::trunc | std::ios::binary);
+ // SerializeToOstream returns false when it's missing required data or when it could not write
+ if (!mTrace.IsInitialized()) {
+ return NOT_ENOUGH_DATA;
+ }
+ if (!mTrace.SerializeToOstream(&output)) {
+ return PERMISSION_DENIED;
+ }
+ return NO_ERROR;
+}
+
+void SurfaceInterceptor::setOutputFileName(const std::string& outputFileName) {
+ mOutputFileName = outputFileName;
+}
+
+const sp<const Layer> SurfaceInterceptor::getLayer(const sp<const IBinder>& handle) {
+ const auto layerHandle(static_cast<const Layer::Handle*>(handle.get()));
+ const sp<const Layer> layer(layerHandle->owner.promote());
+ // layer could be a nullptr at this point
+ return layer;
+}
+
+const std::string SurfaceInterceptor::getLayerName(const sp<const Layer>& layer) {
+ return layer->getName().string();
+}
+
+int32_t SurfaceInterceptor::getLayerId(const sp<const Layer>& layer) {
+ return layer->sequence;
+}
+
+Increment* SurfaceInterceptor::addTraceIncrementLocked() {
+ Increment* increment(mTrace.add_increment());
+ increment->set_time_stamp(systemTime());
+ return increment;
+}
+
+Change* SurfaceInterceptor::addChangeLocked(Transaction* transaction, int32_t layerId) {
+ Change* change(transaction->add_change());
+ change->set_id(layerId);
+ return change;
+}
+
+void SurfaceInterceptor::setProtoRectLocked(Rectangle* protoRect, const Rect& rect) {
+ protoRect->set_left(rect.left);
+ protoRect->set_top(rect.top);
+ protoRect->set_right(rect.right);
+ protoRect->set_bottom(rect.bottom);
+}
+
+void SurfaceInterceptor::addPositionLocked(Transaction* transaction, int32_t layerId, float x,
+ float y)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ PositionChange* posChange(change->mutable_position());
+ posChange->set_x(x);
+ posChange->set_y(y);
+}
+
+void SurfaceInterceptor::addDepthLocked(Transaction* transaction, int32_t layerId, uint32_t z) {
+ Change* change(addChangeLocked(transaction, layerId));
+ LayerChange* depthChange(change->mutable_layer());
+ depthChange->set_layer(z);
+}
+
+void SurfaceInterceptor::addSizeLocked(Transaction* transaction, int32_t layerId, uint32_t w,
+ uint32_t h)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ SizeChange* sizeChange(change->mutable_size());
+ sizeChange->set_w(w);
+ sizeChange->set_h(h);
+}
+
+void SurfaceInterceptor::addAlphaLocked(Transaction* transaction, int32_t layerId, float alpha) {
+ Change* change(addChangeLocked(transaction, layerId));
+ AlphaChange* alphaChange(change->mutable_alpha());
+ alphaChange->set_alpha(alpha);
+}
+
+void SurfaceInterceptor::addMatrixLocked(Transaction* transaction, int32_t layerId,
+ const layer_state_t::matrix22_t& matrix)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ MatrixChange* matrixChange(change->mutable_matrix());
+ matrixChange->set_dsdx(matrix.dsdx);
+ matrixChange->set_dtdx(matrix.dtdx);
+ matrixChange->set_dsdy(matrix.dsdy);
+ matrixChange->set_dtdy(matrix.dtdy);
+}
+
+void SurfaceInterceptor::addTransparentRegionLocked(Transaction* transaction, int32_t layerId,
+ const Region& transRegion)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ TransparentRegionHintChange* transparentChange(change->mutable_transparent_region_hint());
+
+ for (const auto& rect : transRegion) {
+ Rectangle* protoRect(transparentChange->add_region());
+ setProtoRectLocked(protoRect, rect);
+ }
+}
+
+void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags) {
+ // There can be multiple flags changed
+ if (flags & layer_state_t::eLayerHidden) {
+ Change* change(addChangeLocked(transaction, layerId));
+ HiddenFlagChange* flagChange(change->mutable_hidden_flag());
+ flagChange->set_hidden_flag(true);
+ }
+ if (flags & layer_state_t::eLayerOpaque) {
+ Change* change(addChangeLocked(transaction, layerId));
+ OpaqueFlagChange* flagChange(change->mutable_opaque_flag());
+ flagChange->set_opaque_flag(true);
+ }
+ if (flags & layer_state_t::eLayerSecure) {
+ Change* change(addChangeLocked(transaction, layerId));
+ SecureFlagChange* flagChange(change->mutable_secure_flag());
+ flagChange->set_secure_flag(true);
+ }
+}
+
+void SurfaceInterceptor::addLayerStackLocked(Transaction* transaction, int32_t layerId,
+ uint32_t layerStack)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ LayerStackChange* layerStackChange(change->mutable_layer_stack());
+ layerStackChange->set_layer_stack(layerStack);
+}
+
+void SurfaceInterceptor::addCropLocked(Transaction* transaction, int32_t layerId,
+ const Rect& rect)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ CropChange* cropChange(change->mutable_crop());
+ Rectangle* protoRect(cropChange->mutable_rectangle());
+ setProtoRectLocked(protoRect, rect);
+}
+
+void SurfaceInterceptor::addFinalCropLocked(Transaction* transaction, int32_t layerId,
+ const Rect& rect)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ FinalCropChange* finalCropChange(change->mutable_final_crop());
+ Rectangle* protoRect(finalCropChange->mutable_rectangle());
+ setProtoRectLocked(protoRect, rect);
+}
+
+void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
+ const sp<const IBinder>& handle, uint64_t frameNumber)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ const sp<const Layer> layer(getLayer(handle));
+ if (layer == nullptr) {
+ ALOGE("An existing layer could not be retrieved with the handle"
+ " for the deferred transaction");
+ return;
+ }
+ DeferredTransactionChange* deferTransaction(change->mutable_deferred_transaction());
+ deferTransaction->set_layer_id(getLayerId(layer));
+ deferTransaction->set_frame_number(frameNumber);
+}
+
+void SurfaceInterceptor::addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
+ int32_t overrideScalingMode)
+{
+ Change* change(addChangeLocked(transaction, layerId));
+ OverrideScalingModeChange* overrideChange(change->mutable_override_scaling_mode());
+ overrideChange->set_override_scaling_mode(overrideScalingMode);
+}
+
+void SurfaceInterceptor::addChangedPropertiesLocked(Transaction* transaction,
+ const layer_state_t& state)
+{
+ const sp<const Layer> layer(getLayer(state.surface));
+ if (layer == nullptr) {
+ ALOGE("An existing layer could not be retrieved with the surface "
+ "from the layer_state_t surface in the update transaction");
+ return;
+ }
+
+ const int32_t layerId(getLayerId(layer));
+
+ if (state.what & layer_state_t::ePositionChanged) {
+ addPositionLocked(transaction, layerId, state.x, state.y);
+ }
+ if (state.what & layer_state_t::eLayerChanged) {
+ addDepthLocked(transaction, layerId, state.z);
+ }
+ if (state.what & layer_state_t::eSizeChanged) {
+ addSizeLocked(transaction, layerId, state.w, state.h);
+ }
+ if (state.what & layer_state_t::eAlphaChanged) {
+ addAlphaLocked(transaction, layerId, state.alpha);
+ }
+ if (state.what & layer_state_t::eMatrixChanged) {
+ addMatrixLocked(transaction, layerId, state.matrix);
+ }
+ if (state.what & layer_state_t::eTransparentRegionChanged) {
+ addTransparentRegionLocked(transaction, layerId, state.transparentRegion);
+ }
+ if (state.what & layer_state_t::eFlagsChanged) {
+ addFlagsLocked(transaction, layerId, state.flags);
+ }
+ if (state.what & layer_state_t::eLayerStackChanged) {
+ addLayerStackLocked(transaction, layerId, state.layerStack);
+ }
+ if (state.what & layer_state_t::eCropChanged) {
+ addCropLocked(transaction, layerId, state.crop);
+ }
+ if (state.what & layer_state_t::eDeferTransaction) {
+ addDeferTransactionLocked(transaction, layerId, state.handle, state.frameNumber);
+ }
+ if (state.what & layer_state_t::eFinalCropChanged) {
+ addFinalCropLocked(transaction, layerId, state.finalCrop);
+ }
+ if (state.what & layer_state_t::eOverrideScalingModeChanged) {
+ addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode);
+ }
+}
+
+void SurfaceInterceptor::addUpdatedLayersLocked(Increment* increment, uint32_t flags,
+ const Vector<ComposerState>& stateUpdates)
+{
+ Transaction* transaction(increment->mutable_transaction());
+ transaction->set_synchronous(flags & BnSurfaceComposer::eSynchronous);
+ transaction->set_animation(flags & BnSurfaceComposer::eAnimation);
+ for (const auto& compState: stateUpdates) {
+ addChangedPropertiesLocked(transaction, compState.state);
+ }
+}
+
+void SurfaceInterceptor::addCreatedLayerLocked(Increment* increment, const sp<const Layer>& layer) {
+ Create* create(increment->mutable_create());
+ create->set_id(getLayerId(layer));
+ create->set_name(getLayerName(layer));
+ create->set_w(layer->mCurrentState.active.w);
+ create->set_h(layer->mCurrentState.active.h);
+}
+
+void SurfaceInterceptor::addDeletedLayerLocked(Increment* increment, const sp<const Layer>& layer) {
+ Delete* deleteLayer(increment->mutable_delete_());
+ deleteLayer->set_id(getLayerId(layer));
+}
+
+void SurfaceInterceptor::addUpdatedBufferLocked(Increment* increment, const sp<const Layer>& layer,
+ uint32_t width, uint32_t height, uint64_t frameNumber)
+{
+ BufferUpdate* update(increment->mutable_buffer_update());
+ update->set_id(getLayerId(layer));
+ update->set_w(width);
+ update->set_h(height);
+ update->set_frame_number(frameNumber);
+}
+
+void SurfaceInterceptor::addUpdatedVsyncLocked(Increment* increment, nsecs_t timestamp) {
+ VSyncEvent* event(increment->mutable_vsync_event());
+ event->set_when(timestamp);
+}
+
+void SurfaceInterceptor::saveLayerUpdates(const Vector<ComposerState>& stateUpdates,
+ uint32_t flags)
+{
+ ATRACE_CALL();
+ if (!mEnabled || stateUpdates.size() <= 0) {
+ return;
+ }
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ addUpdatedLayersLocked(addTraceIncrementLocked(), flags, stateUpdates);
+}
+
+void SurfaceInterceptor::saveLayerCreate(const sp<const Layer>& layer) {
+ ATRACE_CALL();
+ if (!mEnabled || layer == nullptr) {
+ return;
+ }
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ addCreatedLayerLocked(addTraceIncrementLocked(), layer);
+}
+
+void SurfaceInterceptor::saveLayerCreateLocked(const sp<const Layer>& layer) {
+ if (!mEnabled || layer == nullptr) {
+ return;
+ }
+ addCreatedLayerLocked(addTraceIncrementLocked(), layer);
+}
+
+void SurfaceInterceptor::saveLayerDelete(const sp<const Layer>& layer) {
+ ATRACE_CALL();
+ if (!mEnabled || layer == nullptr) {
+ return;
+ }
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ addDeletedLayerLocked(addTraceIncrementLocked(), layer);
+}
+
+void SurfaceInterceptor::saveBufferUpdate(const sp<const Layer>& layer, uint32_t width,
+ uint32_t height, uint64_t frameNumber)
+{
+ ATRACE_CALL();
+ if (!mEnabled || layer == nullptr) {
+ return;
+ }
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ addUpdatedBufferLocked(addTraceIncrementLocked(), layer, width, height, frameNumber);
+}
+
+void SurfaceInterceptor::saveVSyncEvent(nsecs_t timestamp) {
+ if (!mEnabled) {
+ return;
+ }
+ std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ addUpdatedVsyncLocked(addTraceIncrementLocked(), timestamp);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
new file mode 100644
index 0000000..bc8174c
--- /dev/null
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -0,0 +1,96 @@
+/*
+ * 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_SURFACEINTERCEPTOR_H
+#define ANDROID_SURFACEINTERCEPTOR_H
+
+#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
+
+#include <mutex>
+
+namespace android {
+
+class BufferItem;
+class Layer;
+struct layer_state_t;
+
+constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+
+/*
+ * SurfaceInterceptor intercepts and stores incoming streams of window
+ * properties on SurfaceFlinger.
+ */
+class SurfaceInterceptor {
+public:
+ // The layer vector is used to capture the inital snapshot in the trace
+ void enable(const SortedVector<sp<Layer>>& layers);
+ void disable();
+ void setOutputFileName(const std::string& OutputFileName);
+
+ void saveLayerUpdates(const Vector<ComposerState>& state, uint32_t flags);
+ void saveLayerCreate(const sp<const Layer>& layer);
+ void saveLayerDelete(const sp<const Layer>& layer);
+ void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
+ uint64_t frameNumber);
+ void saveVSyncEvent(nsecs_t timestamp);
+
+private:
+ void saveExistingLayers(const SortedVector<sp<Layer>>& layers);
+ void saveInitialLayerStateLocked(const sp<const Layer>& layer);
+ void saveLayerCreateLocked(const sp<const Layer>& layer);
+ status_t writeProtoFileLocked();
+ const sp<const Layer> getLayer(const sp<const IBinder>& handle);
+ const std::string getLayerName(const sp<const Layer>& layer);
+ int32_t getLayerId(const sp<const Layer>& layer);
+ Increment* addTraceIncrementLocked();
+
+ void addUpdatedLayersLocked(Increment* increment, uint32_t flags,
+ const Vector<ComposerState>& stateUpdates);
+ void addCreatedLayerLocked(Increment* increment, const sp<const Layer>& layer);
+ void addDeletedLayerLocked(Increment* increment, const sp<const Layer>& layer);
+ void addUpdatedBufferLocked(Increment* increment, const sp<const Layer>& layer, uint32_t width,
+ uint32_t height, uint64_t frameNumber);
+ void addUpdatedVsyncLocked(Increment* increment, nsecs_t timestamp);
+
+ Change* addChangeLocked(Transaction* transaction, int32_t layerId);
+ void setProtoRectLocked(Rectangle* protoRect, const Rect& rect);
+ void addPositionLocked(Transaction* transaction, int32_t layerId, float x, float y);
+ void addDepthLocked(Transaction* transaction, int32_t layerId, uint32_t z);
+ void addSizeLocked(Transaction* transaction, int32_t layerId, uint32_t w, uint32_t h);
+ void addAlphaLocked(Transaction* transaction, int32_t layerId, float alpha);
+ void addMatrixLocked(Transaction* transaction, int32_t layerId,
+ const layer_state_t::matrix22_t& matrix);
+ void addTransparentRegionLocked(Transaction* transaction, int32_t layerId,
+ const Region& transRegion);
+ void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags);
+ void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack);
+ void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
+ void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
+ const sp<const IBinder>& handle, uint64_t frameNumber);
+ void addFinalCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
+ void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
+ int32_t overrideScalingMode);
+ void addChangedPropertiesLocked(Transaction* transaction, const layer_state_t& state);
+
+ bool mEnabled {false};
+ std::string mOutputFileName {DEFAULT_FILENAME};
+ std::mutex mTraceMutex {};
+ Trace mTrace {};
+};
+
+}
+
+#endif // ANDROID_SURFACEINTERCEPTOR_H
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index 979062e..e5dffe5 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -3,21 +3,29 @@
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS := -std=c++14
+
LOCAL_MODULE := SurfaceFlinger_test
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
Transaction_test.cpp \
+ SurfaceInterceptor_test.cpp
LOCAL_SHARED_LIBRARIES := \
- libEGL \
- libGLESv2 \
- libbinder \
- libcutils \
- libgui \
- libui \
- libutils \
+ libEGL \
+ libGLESv2 \
+ libbinder \
+ libcutils \
+ libgui \
+ libprotobuf-cpp-full \
+ libui \
+ libutils \
+
+LOCAL_STATIC_LIBRARIES := libtrace_proto
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
# to integrate with auto-test framework.
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
new file mode 100644
index 0000000..ebc4dd1
--- /dev/null
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -0,0 +1,734 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <frameworks/native/cmds/surfacecapturereplay/proto/src/trace.pb.h>
+
+#include <gtest/gtest.h>
+
+#include <android/native_window.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/LayerState.h>
+#include <ui/DisplayInfo.h>
+
+#include <fstream>
+#include <random>
+#include <thread>
+
+namespace android {
+
+constexpr int32_t SCALING_UPDATE = 1;
+constexpr uint32_t BUFFER_UPDATES = 18;
+constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
+constexpr uint32_t SIZE_UPDATE = 134;
+constexpr uint32_t STACK_UPDATE = 1;
+constexpr uint64_t DEFERRED_UPDATE = 13;
+constexpr float ALPHA_UPDATE = 0.29f;
+constexpr float POSITION_UPDATE = 121;
+const Rect CROP_UPDATE(16, 16, 32, 32);
+
+constexpr auto LAYER_NAME = "Layer Create and Delete Test";
+
+constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+
+// Fill an RGBA_8888 formatted surface with a single color.
+static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
+ ANativeWindow_Buffer outBuffer;
+ sp<Surface> s = sc->getSurface();
+ ASSERT_TRUE(s != nullptr);
+ ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
+ uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
+ for (int y = 0; y < outBuffer.height; y++) {
+ for (int x = 0; x < outBuffer.width; x++) {
+ uint8_t* pixel = img + (4 * (y*outBuffer.stride + x));
+ pixel[0] = r;
+ pixel[1] = g;
+ pixel[2] = b;
+ pixel[3] = 255;
+ }
+ }
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+}
+
+static status_t readProtoFile(Trace* trace) {
+ std::ifstream input(DEFAULT_FILENAME, std::ios::in | std::ios::binary);
+ if (input && !trace->ParseFromIstream(&input)) {
+ return PERMISSION_DENIED;
+ }
+ return NO_ERROR;
+}
+
+static void enableInterceptor() {
+ system("service call SurfaceFlinger 1020 i32 1 > /dev/null");
+}
+
+static void disableInterceptor() {
+ system("service call SurfaceFlinger 1020 i32 0 > /dev/null");
+}
+
+uint32_t getLayerId(const std::string& layerName) {
+ enableInterceptor();
+ disableInterceptor();
+ Trace capturedTrace;
+ readProtoFile(&capturedTrace);
+ uint32_t layerId = 0;
+ for (const auto& increment : *capturedTrace.mutable_increment()) {
+ if (increment.increment_case() == increment.kCreate) {
+ if (increment.create().name() == layerName) {
+ layerId = increment.create().id();
+ break;
+ }
+ }
+ }
+ return layerId;
+}
+
+class SurfaceInterceptorTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ // Allow SurfaceInterceptor write to /data
+ system("setenforce 0");
+
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+ ssize_t displayWidth = info.w;
+ ssize_t displayHeight = info.h;
+
+ // Background surface
+ mBGSurfaceControl = mComposerClient->createSurface(
+ String8("BG Interceptor Test Surface"), displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mBGSurfaceControl != NULL);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+ mBGLayerId = getLayerId("BG Interceptor Test Surface");
+
+ SurfaceComposerClient::openGlobalTransaction();
+ mComposerClient->setDisplayLayerStack(display, 0);
+ ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-3));
+ ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
+ SurfaceComposerClient::closeGlobalTransaction(true);
+ }
+
+ virtual void TearDown() {
+ mComposerClient->dispose();
+ mBGSurfaceControl.clear();
+ mComposerClient.clear();
+ }
+
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mBGSurfaceControl;
+ uint32_t mBGLayerId;
+
+public:
+ void captureTest(void (SurfaceInterceptorTest::* action)(void),
+ bool (SurfaceInterceptorTest::* verification)(Trace *));
+ void captureTest(void (SurfaceInterceptorTest::* action)(void), Change::ChangeCase changeCase);
+ void runInTransaction(void (SurfaceInterceptorTest::* action)(void), bool intercepted = false);
+
+ // Verification of changes to a surface
+ bool positionUpdateFound(const Change& change, bool foundPosition);
+ bool sizeUpdateFound(const Change& change, bool foundSize);
+ bool alphaUpdateFound(const Change& change, bool foundAlpha);
+ bool layerUpdateFound(const Change& change, bool foundLayer);
+ bool cropUpdateFound(const Change& change, bool foundCrop);
+ bool finalCropUpdateFound(const Change& change, bool foundFinalCrop);
+ bool matrixUpdateFound(const Change& change, bool foundMatrix);
+ bool scalingModeUpdateFound(const Change& change, bool foundScalingMode);
+ bool transparentRegionHintUpdateFound(const Change& change, bool foundTransparentRegion);
+ bool layerStackUpdateFound(const Change& change, bool foundLayerStack);
+ bool hiddenFlagUpdateFound(const Change& change, bool foundHiddenFlag);
+ bool opaqueFlagUpdateFound(const Change& change, bool foundOpaqueFlag);
+ bool secureFlagUpdateFound(const Change& change, bool foundSecureFlag);
+ bool deferredTransactionUpdateFound(const Change& change, bool foundDeferred);
+ bool surfaceUpdateFound(Trace* trace, Change::ChangeCase changeCase);
+ void assertAllUpdatesFound(Trace* trace);
+
+ // Verification of creation and deletion of a surface
+ bool surfaceCreateFound(Trace* trace);
+ bool surfaceDeleteFound(Trace* trace, uint32_t targetLayerId);
+
+ // Verification of buffer updates
+ bool bufferUpdatesFound(Trace* trace);
+
+ // Perform each of the possible changes to a surface
+ void positionUpdate();
+ void sizeUpdate();
+ void alphaUpdate();
+ void layerUpdate();
+ void cropUpdate();
+ void finalCropUpdate();
+ void matrixUpdate();
+ void overrideScalingModeUpdate();
+ void transparentRegionHintUpdate();
+ void layerStackUpdate();
+ void hiddenFlagUpdate();
+ void opaqueFlagUpdate();
+ void secureFlagUpdate();
+ void deferredTransactionUpdate();
+ void runAllUpdates();
+ void surfaceCreate();
+ void nBufferUpdates();
+};
+
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+ bool (SurfaceInterceptorTest::* verification)(Trace *))
+{
+ runInTransaction(action, true);
+ Trace capturedTrace;
+ ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+ ASSERT_TRUE((this->*verification)(&capturedTrace));
+}
+
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+ Change::ChangeCase changeCase)
+{
+ runInTransaction(action, true);
+ Trace capturedTrace;
+ ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+ ASSERT_TRUE(surfaceUpdateFound(&capturedTrace, changeCase));
+}
+
+void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(void),
+ bool intercepted)
+{
+ if (intercepted) {
+ enableInterceptor();
+ }
+ SurfaceComposerClient::openGlobalTransaction();
+ (this->*action)();
+ SurfaceComposerClient::closeGlobalTransaction(true);
+ if (intercepted) {
+ disableInterceptor();
+ }
+}
+
+void SurfaceInterceptorTest::positionUpdate() {
+ mBGSurfaceControl->setPosition(POSITION_UPDATE, POSITION_UPDATE);
+}
+
+void SurfaceInterceptorTest::sizeUpdate() {
+ mBGSurfaceControl->setSize(SIZE_UPDATE, SIZE_UPDATE);
+}
+
+void SurfaceInterceptorTest::alphaUpdate() {
+ mBGSurfaceControl->setAlpha(ALPHA_UPDATE);
+}
+
+void SurfaceInterceptorTest::layerUpdate() {
+ mBGSurfaceControl->setLayer(LAYER_UPDATE);
+}
+
+void SurfaceInterceptorTest::cropUpdate() {
+ mBGSurfaceControl->setCrop(CROP_UPDATE);
+}
+
+void SurfaceInterceptorTest::finalCropUpdate() {
+ mBGSurfaceControl->setFinalCrop(CROP_UPDATE);
+}
+
+void SurfaceInterceptorTest::matrixUpdate() {
+ mBGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
+}
+
+void SurfaceInterceptorTest::overrideScalingModeUpdate() {
+ mBGSurfaceControl->setOverrideScalingMode(SCALING_UPDATE);
+}
+
+void SurfaceInterceptorTest::transparentRegionHintUpdate() {
+ Region region(CROP_UPDATE);
+ mBGSurfaceControl->setTransparentRegionHint(region);
+}
+
+void SurfaceInterceptorTest::layerStackUpdate() {
+ mBGSurfaceControl->setLayerStack(STACK_UPDATE);
+}
+
+void SurfaceInterceptorTest::hiddenFlagUpdate() {
+ mBGSurfaceControl->setFlags(layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+}
+
+void SurfaceInterceptorTest::opaqueFlagUpdate() {
+ mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+}
+
+void SurfaceInterceptorTest::secureFlagUpdate() {
+ mBGSurfaceControl->setFlags(layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
+}
+
+void SurfaceInterceptorTest::deferredTransactionUpdate() {
+ mBGSurfaceControl->deferTransactionUntil(mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
+}
+
+void SurfaceInterceptorTest::runAllUpdates() {
+ runInTransaction(&SurfaceInterceptorTest::positionUpdate);
+ runInTransaction(&SurfaceInterceptorTest::sizeUpdate);
+ runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
+ runInTransaction(&SurfaceInterceptorTest::layerUpdate);
+ runInTransaction(&SurfaceInterceptorTest::cropUpdate);
+ runInTransaction(&SurfaceInterceptorTest::finalCropUpdate);
+ runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
+ runInTransaction(&SurfaceInterceptorTest::overrideScalingModeUpdate);
+ runInTransaction(&SurfaceInterceptorTest::transparentRegionHintUpdate);
+ runInTransaction(&SurfaceInterceptorTest::layerStackUpdate);
+ runInTransaction(&SurfaceInterceptorTest::hiddenFlagUpdate);
+ runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate);
+ runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate);
+ runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
+}
+
+void SurfaceInterceptorTest::surfaceCreate() {
+ mComposerClient->createSurface(String8(LAYER_NAME), SIZE_UPDATE, SIZE_UPDATE,
+ PIXEL_FORMAT_RGBA_8888, 0);
+}
+
+void SurfaceInterceptorTest::nBufferUpdates() {
+ std::random_device rd;
+ std::mt19937_64 gen(rd());
+ // This makes testing fun
+ std::uniform_int_distribution<uint8_t> dis;
+ for (uint32_t i = 0; i < BUFFER_UPDATES; ++i) {
+ fillSurfaceRGBA8(mBGSurfaceControl, dis(gen), dis(gen), dis(gen));
+ }
+}
+
+bool SurfaceInterceptorTest::positionUpdateFound(const Change& change, bool foundPosition) {
+ // There should only be one position transaction with x and y = POSITION_UPDATE
+ bool hasX(change.position().x() == POSITION_UPDATE);
+ bool hasY(change.position().y() == POSITION_UPDATE);
+ if (hasX && hasY && !foundPosition) {
+ foundPosition = true;
+ }
+ // Failed because the position update was found a second time
+ else if (hasX && hasY && foundPosition) {
+ [] () { FAIL(); }();
+ }
+ return foundPosition;
+}
+
+bool SurfaceInterceptorTest::sizeUpdateFound(const Change& change, bool foundSize) {
+ bool hasWidth(change.size().h() == SIZE_UPDATE);
+ bool hasHeight(change.size().w() == SIZE_UPDATE);
+ if (hasWidth && hasHeight && !foundSize) {
+ foundSize = true;
+ }
+ else if (hasWidth && hasHeight && foundSize) {
+ [] () { FAIL(); }();
+ }
+ return foundSize;
+}
+
+bool SurfaceInterceptorTest::alphaUpdateFound(const Change& change, bool foundAlpha) {
+ bool hasAlpha(change.alpha().alpha() == ALPHA_UPDATE);
+ if (hasAlpha && !foundAlpha) {
+ foundAlpha = true;
+ }
+ else if (hasAlpha && foundAlpha) {
+ [] () { FAIL(); }();
+ }
+ return foundAlpha;
+}
+
+bool SurfaceInterceptorTest::layerUpdateFound(const Change& change, bool foundLayer) {
+ bool hasLayer(change.layer().layer() == LAYER_UPDATE);
+ if (hasLayer && !foundLayer) {
+ foundLayer = true;
+ }
+ else if (hasLayer && foundLayer) {
+ [] () { FAIL(); }();
+ }
+ return foundLayer;
+}
+
+bool SurfaceInterceptorTest::cropUpdateFound(const Change& change, bool foundCrop) {
+ bool hasLeft(change.crop().rectangle().left() == CROP_UPDATE.left);
+ bool hasTop(change.crop().rectangle().top() == CROP_UPDATE.top);
+ bool hasRight(change.crop().rectangle().right() == CROP_UPDATE.right);
+ bool hasBottom(change.crop().rectangle().bottom() == CROP_UPDATE.bottom);
+ if (hasLeft && hasRight && hasTop && hasBottom && !foundCrop) {
+ foundCrop = true;
+ }
+ else if (hasLeft && hasRight && hasTop && hasBottom && foundCrop) {
+ [] () { FAIL(); }();
+ }
+ return foundCrop;
+}
+
+bool SurfaceInterceptorTest::finalCropUpdateFound(const Change& change, bool foundFinalCrop) {
+ bool hasLeft(change.final_crop().rectangle().left() == CROP_UPDATE.left);
+ bool hasTop(change.final_crop().rectangle().top() == CROP_UPDATE.top);
+ bool hasRight(change.final_crop().rectangle().right() == CROP_UPDATE.right);
+ bool hasBottom(change.final_crop().rectangle().bottom() == CROP_UPDATE.bottom);
+ if (hasLeft && hasRight && hasTop && hasBottom && !foundFinalCrop) {
+ foundFinalCrop = true;
+ }
+ else if (hasLeft && hasRight && hasTop && hasBottom && foundFinalCrop) {
+ [] () { FAIL(); }();
+ }
+ return foundFinalCrop;
+}
+
+bool SurfaceInterceptorTest::matrixUpdateFound(const Change& change, bool foundMatrix) {
+ bool hasSx((float)change.matrix().dsdx() == (float)M_SQRT1_2);
+ bool hasTx((float)change.matrix().dtdx() == (float)M_SQRT1_2);
+ bool hasSy((float)change.matrix().dsdy() == (float)-M_SQRT1_2);
+ bool hasTy((float)change.matrix().dtdy() == (float)M_SQRT1_2);
+ if (hasSx && hasTx && hasSy && hasTy && !foundMatrix) {
+ foundMatrix = true;
+ }
+ else if (hasSx && hasTx && hasSy && hasTy && foundMatrix) {
+ [] () { FAIL(); }();
+ }
+ return foundMatrix;
+}
+
+bool SurfaceInterceptorTest::scalingModeUpdateFound(const Change& change, bool foundScalingMode) {
+ bool hasScalingUpdate(change.override_scaling_mode().override_scaling_mode() == SCALING_UPDATE);
+ if (hasScalingUpdate && !foundScalingMode) {
+ foundScalingMode = true;
+ }
+ else if (hasScalingUpdate && foundScalingMode) {
+ [] () { FAIL(); }();
+ }
+ return foundScalingMode;
+}
+
+bool SurfaceInterceptorTest::transparentRegionHintUpdateFound(const Change& change,
+ bool foundTransparentRegion)
+{
+ auto traceRegion = change.transparent_region_hint().region(0);
+ bool hasLeft(traceRegion.left() == CROP_UPDATE.left);
+ bool hasTop(traceRegion.top() == CROP_UPDATE.top);
+ bool hasRight(traceRegion.right() == CROP_UPDATE.right);
+ bool hasBottom(traceRegion.bottom() == CROP_UPDATE.bottom);
+ if (hasLeft && hasRight && hasTop && hasBottom && !foundTransparentRegion) {
+ foundTransparentRegion = true;
+ }
+ else if (hasLeft && hasRight && hasTop && hasBottom && foundTransparentRegion) {
+ [] () { FAIL(); }();
+ }
+ return foundTransparentRegion;
+}
+
+bool SurfaceInterceptorTest::layerStackUpdateFound(const Change& change, bool foundLayerStack) {
+ bool hasLayerStackUpdate(change.layer_stack().layer_stack() == STACK_UPDATE);
+ if (hasLayerStackUpdate && !foundLayerStack) {
+ foundLayerStack = true;
+ }
+ else if (hasLayerStackUpdate && foundLayerStack) {
+ [] () { FAIL(); }();
+ }
+ return foundLayerStack;
+}
+
+bool SurfaceInterceptorTest::hiddenFlagUpdateFound(const Change& change, bool foundHiddenFlag) {
+ bool hasHiddenFlag(change.hidden_flag().hidden_flag());
+ if (hasHiddenFlag && !foundHiddenFlag) {
+ foundHiddenFlag = true;
+ }
+ else if (hasHiddenFlag && foundHiddenFlag) {
+ [] () { FAIL(); }();
+ }
+ return foundHiddenFlag;
+}
+
+bool SurfaceInterceptorTest::opaqueFlagUpdateFound(const Change& change, bool foundOpaqueFlag) {
+ bool hasOpaqueFlag(change.opaque_flag().opaque_flag());
+ if (hasOpaqueFlag && !foundOpaqueFlag) {
+ foundOpaqueFlag = true;
+ }
+ else if (hasOpaqueFlag && foundOpaqueFlag) {
+ [] () { FAIL(); }();
+ }
+ return foundOpaqueFlag;
+}
+
+bool SurfaceInterceptorTest::secureFlagUpdateFound(const Change& change, bool foundSecureFlag) {
+ bool hasSecureFlag(change.secure_flag().secure_flag());
+ if (hasSecureFlag && !foundSecureFlag) {
+ foundSecureFlag = true;
+ }
+ else if (hasSecureFlag && foundSecureFlag) {
+ [] () { FAIL(); }();
+ }
+ return foundSecureFlag;
+}
+
+bool SurfaceInterceptorTest::deferredTransactionUpdateFound(const Change& change,
+ bool foundDeferred)
+{
+ bool hasId(change.deferred_transaction().layer_id() == mBGLayerId);
+ bool hasFrameNumber(change.deferred_transaction().frame_number() ==
+ DEFERRED_UPDATE);
+ if (hasId && hasFrameNumber && !foundDeferred) {
+ foundDeferred = true;
+ }
+ else if (hasId && hasFrameNumber && foundDeferred) {
+ [] () { FAIL(); }();
+ }
+ return foundDeferred;
+}
+
+bool SurfaceInterceptorTest::surfaceUpdateFound(Trace* trace, Change::ChangeCase changeCase) {
+ bool updateFound = false;
+ for (const auto& increment : *trace->mutable_increment()) {
+ if (increment.increment_case() == increment.kTransaction) {
+ for (const auto& change : increment.transaction().change()) {
+ if (change.id() == mBGLayerId && change.Change_case() == changeCase) {
+ switch (changeCase) {
+ case Change::ChangeCase::kPosition:
+ // updateFound is sent for the tests to fail on duplicated increments
+ updateFound = positionUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kSize:
+ updateFound = sizeUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kAlpha:
+ updateFound = alphaUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kLayer:
+ updateFound = layerUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kCrop:
+ updateFound = cropUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kFinalCrop:
+ updateFound = finalCropUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kMatrix:
+ updateFound = matrixUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kOverrideScalingMode:
+ updateFound = scalingModeUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kTransparentRegionHint:
+ updateFound = transparentRegionHintUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kLayerStack:
+ updateFound = layerStackUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kHiddenFlag:
+ updateFound = hiddenFlagUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kOpaqueFlag:
+ updateFound = opaqueFlagUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kSecureFlag:
+ updateFound = secureFlagUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::kDeferredTransaction:
+ updateFound = deferredTransactionUpdateFound(change, updateFound);
+ break;
+ case Change::ChangeCase::CHANGE_NOT_SET:
+ break;
+ }
+ }
+ }
+ }
+ }
+ return updateFound;
+}
+
+void SurfaceInterceptorTest::assertAllUpdatesFound(Trace* trace) {
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kPosition));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kSize));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kAlpha));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kLayer));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kCrop));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kFinalCrop));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kMatrix));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kOverrideScalingMode));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kTransparentRegionHint));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kLayerStack));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kHiddenFlag));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kOpaqueFlag));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kSecureFlag));
+ ASSERT_TRUE(surfaceUpdateFound(trace, Change::ChangeCase::kDeferredTransaction));
+}
+
+bool SurfaceInterceptorTest::surfaceCreateFound(Trace* trace) {
+ bool foundLayer = false;
+ for (const auto& inc : *trace->mutable_increment()) {
+ if (inc.increment_case() == inc.kCreate) {
+ bool isMatch(inc.create().name() == LAYER_NAME && inc.create().w() == SIZE_UPDATE &&
+ inc.create().h() == SIZE_UPDATE);
+ if (isMatch && !foundLayer) {
+ foundLayer = true;
+ }
+ else if (isMatch && foundLayer) {
+ return false;
+ }
+ }
+ }
+ return foundLayer;
+}
+
+bool SurfaceInterceptorTest::surfaceDeleteFound(Trace* trace, uint32_t targetLayerId) {
+ bool foundLayer = false;
+ for (const auto& increment : *trace->mutable_increment()) {
+ if (increment.increment_case() == increment.kDelete) {
+ bool isMatch(increment.delete_().id() == targetLayerId);
+ if (isMatch && !foundLayer) {
+ foundLayer = true;
+ }
+ else if (isMatch && foundLayer) {
+ return false;
+ }
+ }
+ }
+ return foundLayer;
+}
+
+bool SurfaceInterceptorTest::bufferUpdatesFound(Trace* trace) {
+ uint32_t updates = 0;
+ for (const auto& inc : *trace->mutable_increment()) {
+ if (inc.increment_case() == inc.kBufferUpdate && inc.buffer_update().id() == mBGLayerId) {
+ updates++;
+ }
+ }
+ return updates == BUFFER_UPDATES;
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptPositionUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::positionUpdate, Change::ChangeCase::kPosition);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptSizeUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::sizeUpdate, Change::ChangeCase::kSize);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptAlphaUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::alphaUpdate, Change::ChangeCase::kAlpha);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptLayerUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::layerUpdate, Change::ChangeCase::kLayer);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptCropUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::cropUpdate, Change::ChangeCase::kCrop);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptFinalCropUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::finalCropUpdate, Change::ChangeCase::kFinalCrop);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::matrixUpdate, Change::ChangeCase::kMatrix);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptOverrideScalingModeUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::overrideScalingModeUpdate,
+ Change::ChangeCase::kOverrideScalingMode);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptTransparentRegionHintUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::transparentRegionHintUpdate,
+ Change::ChangeCase::kTransparentRegionHint);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptLayerStackUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::layerStackUpdate, Change::ChangeCase::kLayerStack);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptHiddenFlagUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::hiddenFlagUpdate, Change::ChangeCase::kHiddenFlag);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptOpaqueFlagUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::opaqueFlagUpdate, Change::ChangeCase::kOpaqueFlag);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptSecureFlagUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::secureFlagUpdate, Change::ChangeCase::kSecureFlag);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptDeferredTransactionUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::deferredTransactionUpdate,
+ Change::ChangeCase::kDeferredTransaction);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
+ enableInterceptor();
+ runAllUpdates();
+ disableInterceptor();
+
+ // Find all of the updates in the single trace
+ Trace capturedTrace;
+ ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+ assertAllUpdatesFound(&capturedTrace);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptLayerCreateWorks) {
+ captureTest(&SurfaceInterceptorTest::surfaceCreate, &SurfaceInterceptorTest::surfaceCreateFound);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptLayerDeleteWorks) {
+ sp<SurfaceControl> layerToDelete = mComposerClient->createSurface(String8(LAYER_NAME),
+ SIZE_UPDATE, SIZE_UPDATE, PIXEL_FORMAT_RGBA_8888, 0);
+ uint32_t targetLayerId = getLayerId(LAYER_NAME);
+ enableInterceptor();
+ mComposerClient->destroySurface(layerToDelete->getHandle());
+ disableInterceptor();
+
+ Trace capturedTrace;
+ ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+ ASSERT_TRUE(surfaceDeleteFound(&capturedTrace, targetLayerId));
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::nBufferUpdates,
+ &SurfaceInterceptorTest::bufferUpdatesFound);
+}
+
+// If the interceptor is enabled while buffer updates are being pushed, the interceptor should
+// first create a snapshot of the existing surfaces and then start capturing the buffer updates
+TEST_F(SurfaceInterceptorTest, InterceptWhileBufferUpdatesWorks) {
+ std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
+ enableInterceptor();
+ disableInterceptor();
+ bufferUpdates.join();
+
+ Trace capturedTrace;
+ ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+ const auto& firstIncrement = capturedTrace.mutable_increment(0);
+ ASSERT_EQ(firstIncrement->increment_case(), Increment::IncrementCase::kCreate);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) {
+ enableInterceptor();
+ std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
+ std::thread surfaceUpdates(&SurfaceInterceptorTest::runAllUpdates, this);
+ runInTransaction(&SurfaceInterceptorTest::surfaceCreate);
+ bufferUpdates.join();
+ surfaceUpdates.join();
+ disableInterceptor();
+
+ Trace capturedTrace;
+ ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+
+ assertAllUpdatesFound(&capturedTrace);
+ ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
+ ASSERT_TRUE(surfaceCreateFound(&capturedTrace));
+}
+
+}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index f8d4d13..79cd245 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -61,7 +61,6 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- IGraphicBufferProducer::QueueBufferOutput bufferOutput;
sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<IBinder> display(sf->getBuiltInDisplay(
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 870f8eb..37cc448 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
// API version (major.minor.patch)
define VERSION_MAJOR 1
define VERSION_MINOR 0
-define VERSION_PATCH 13
+define VERSION_PATCH 22
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -78,7 +78,7 @@
@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 5
@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer"
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2
+@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 3
@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report"
@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION 1
@@ -93,9 +93,21 @@
@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1
@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_NAME "VK_AMD_rasterization_order"
+@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1
+@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax"
+
+@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1
+@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter"
+
@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3
@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_NAME "VK_EXT_debug_marker"
+@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_SPEC_VERSION 1
+@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader"
+
+@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1
+@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation"
+
/////////////
// Types //
@@ -684,6 +696,15 @@
//@extension("VK_EXT_debug_marker")
VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
+
+ //@extension("VK_NV_dedicated_allocation")
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
+
+ //@extension("VK_NV_dedicated_allocation")
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
+
+ //@extension("VK_NV_dedicated_allocation")
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
}
enum VkSubpassContents {
@@ -721,6 +742,7 @@
VK_ERROR_INCOMPATIBLE_DRIVER = 0xFFFFFFF7, // -9
VK_ERROR_TOO_MANY_OBJECTS = 0xFFFFFFF6, // -10
VK_ERROR_FORMAT_NOT_SUPPORTED = 0xFFFFFFF5, // -11
+ VK_ERROR_FRAGMENTED_POOL = 0xFFFFFFF4, // -12
//@extension("VK_KHR_surface")
VK_ERROR_SURFACE_LOST_KHR = 0xC4653600, // -1000000000
@@ -2693,6 +2715,28 @@
f32[4] color
}
+@extension("VK_NV_dedicated_allocation")
+class VkDedicatedAllocationImageCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 dedicatedAllocation
+}
+
+@extension("VK_NV_dedicated_allocation")
+class VkDedicatedAllocationBufferCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 dedicatedAllocation
+}
+
+@extension("VK_NV_dedicated_allocation")
+class VkDedicatedAllocationMemoryAllocateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+ VkBuffer buffer
+}
+
////////////////
// Commands //
@@ -4570,7 +4614,7 @@
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
- const u32* pData) {
+ const void* pData) {
commandBufferObject := GetCommandBuffer(commandBuffer)
dstBufferObject := GetBuffer(dstBuffer)
assert(commandBufferObject.device == dstBufferObject.device)
diff --git a/vulkan/include/vulkan/vk_platform.h b/vulkan/include/vulkan/vk_platform.h
index 5d0fc76..c2232ec 100644
--- a/vulkan/include/vulkan/vk_platform.h
+++ b/vulkan/include/vulkan/vk_platform.h
@@ -51,13 +51,13 @@
#define VKAPI_ATTR
#define VKAPI_CALL __stdcall
#define VKAPI_PTR VKAPI_CALL
-#elif defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__)
- // Android does not support Vulkan in native code using the "armeabi" ABI.
- #error "Vulkan requires the 'armeabi-v7a' or 'armeabi-v7a-hard' ABI on 32-bit ARM CPUs"
-#elif defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
- // On Android/ARMv7a, Vulkan functions use the armeabi-v7a-hard calling
- // convention, even if the application's native code is compiled with the
- // armeabi-v7a calling convention.
+#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
+ #error "Vulkan isn't supported for the 'armeabi' NDK ABI"
+#elif defined(__ANDROID__) && __ARM_ARCH >= 7 && __ARM_32BIT_STATE
+ // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
+ // calling convention, i.e. float parameters are passed in registers. This
+ // is true even if the rest of the application passes floats on the stack,
+ // as it does by default when compiling for the armeabi-v7a NDK ABI.
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define VKAPI_CALL
#define VKAPI_PTR VKAPI_ATTR
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 2f18076..ddbb311 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -43,7 +43,7 @@
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
// Version of this file
-#define VK_HEADER_VERSION 13
+#define VK_HEADER_VERSION 22
#define VK_NULL_HANDLE 0
@@ -53,7 +53,7 @@
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
-#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
+#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
#else
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
@@ -135,6 +135,7 @@
VK_ERROR_INCOMPATIBLE_DRIVER = -9,
VK_ERROR_TOO_MANY_OBJECTS = -10,
VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
+ VK_ERROR_FRAGMENTED_POOL = -12,
VK_ERROR_SURFACE_LOST_KHR = -1000000000,
VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
VK_SUBOPTIMAL_KHR = 1000001003,
@@ -142,9 +143,9 @@
VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
VK_ERROR_INVALID_SHADER_NV = -1000012000,
- VK_RESULT_BEGIN_RANGE = VK_ERROR_FORMAT_NOT_SUPPORTED,
+ VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL,
VK_RESULT_END_RANGE = VK_INCOMPLETE,
- VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FORMAT_NOT_SUPPORTED + 1),
+ VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1),
VK_RESULT_MAX_ENUM = 0x7FFFFFFF
} VkResult;
@@ -214,6 +215,9 @@
VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,
VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,
VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,
VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
@@ -2347,7 +2351,7 @@
typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);
typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
-typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData);
+typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
@@ -3032,7 +3036,7 @@
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
- const uint32_t* pData);
+ const void* pData);
VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(
VkCommandBuffer commandBuffer,
@@ -3715,7 +3719,7 @@
#define VK_EXT_debug_report 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
-#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2
+#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 3
#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT
@@ -3855,6 +3859,16 @@
+#define VK_AMD_shader_trinary_minmax 1
+#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1
+#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax"
+
+
+#define VK_AMD_shader_explicit_vertex_parameter 1
+#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1
+#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter"
+
+
#define VK_EXT_debug_marker 1
#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3
#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker"
@@ -3912,6 +3926,36 @@
VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
#endif
+#define VK_AMD_gcn_shader 1
+#define VK_AMD_GCN_SHADER_SPEC_VERSION 1
+#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader"
+
+
+#define VK_NV_dedicated_allocation 1
+#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1
+#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation"
+
+typedef struct VkDedicatedAllocationImageCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 dedicatedAllocation;
+} VkDedicatedAllocationImageCreateInfoNV;
+
+typedef struct VkDedicatedAllocationBufferCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 dedicatedAllocation;
+} VkDedicatedAllocationBufferCreateInfoNV;
+
+typedef struct VkDedicatedAllocationMemoryAllocateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkImage image;
+ VkBuffer buffer;
+} VkDedicatedAllocationMemoryAllocateInfoNV;
+
+
+
#ifdef __cplusplus
}
#endif
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 0a1dda2..a57ba72 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -394,7 +394,7 @@
VKAPI_ATTR void CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);
VKAPI_ATTR void CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
VKAPI_ATTR void CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
-VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData);
+VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
VKAPI_ATTR void CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
VKAPI_ATTR void CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
VKAPI_ATTR void CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
@@ -1075,7 +1075,7 @@
GetData(commandBuffer).dispatch.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
}
-VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData) {
+VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData) {
GetData(commandBuffer).dispatch.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
}
@@ -1795,7 +1795,7 @@
}
__attribute__((visibility("default")))
-VKAPI_ATTR void vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData) {
+VKAPI_ATTR void vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData) {
vulkan::api::CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
}
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 82169ff..8f35f4d 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -68,7 +68,7 @@
class LayerLibrary {
public:
- LayerLibrary(const std::string& path)
+ explicit LayerLibrary(const std::string& path)
: path_(path), dlhandle_(nullptr), refcount_(0) {}
LayerLibrary(LayerLibrary&& other)
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 3bf3ff7..05ebcac 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -1334,7 +1334,7 @@
void CmdCopyImageToBuffer(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer destBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions) {
}
-void CmdUpdateBuffer(VkCommandBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const uint32_t* pData) {
+void CmdUpdateBuffer(VkCommandBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const void* pData) {
}
void CmdFillBuffer(VkCommandBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize fillSize, uint32_t data) {
diff --git a/vulkan/nulldrv/null_driver.tmpl b/vulkan/nulldrv/null_driver.tmpl
index 3a84971..209d61d 100644
--- a/vulkan/nulldrv/null_driver.tmpl
+++ b/vulkan/nulldrv/null_driver.tmpl
@@ -158,16 +158,7 @@
}
¶
PFN_vkVoidFunction GetInstanceProcAddr(const char* name) {«
- PFN_vkVoidFunction pfn;
- if ((pfn = Lookup(name, kInstanceProcs)))
- return pfn;
- if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID));
- if (strcmp(name, "vkAcquireImageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAcquireImageANDROID>(AcquireImageANDROID));
- if (strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueSignalReleaseImageANDROID>(QueueSignalReleaseImageANDROID));
- return nullptr;
+ return Lookup(name, kInstanceProcs);
»}
¶
} // namespace null_driver
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index 10da993..b078ad1 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -54,6 +54,7 @@
const NameProc kInstanceProcs[] = {
// clang-format off
+ {"vkAcquireImageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAcquireImageANDROID>(AcquireImageANDROID))},
{"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateCommandBuffers>(AllocateCommandBuffers))},
{"vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateDescriptorSets>(AllocateDescriptorSets))},
{"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateMemory>(AllocateMemory))},
@@ -179,10 +180,12 @@
{"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPipelineCacheData>(GetPipelineCacheData))},
{"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetQueryPoolResults>(GetQueryPoolResults))},
{"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
+ {"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
{"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
{"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkMapMemory>(MapMemory))},
{"vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkMergePipelineCaches>(MergePipelineCaches))},
{"vkQueueBindSparse", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueBindSparse>(QueueBindSparse))},
+ {"vkQueueSignalReleaseImageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueSignalReleaseImageANDROID>(QueueSignalReleaseImageANDROID))},
{"vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueSubmit>(QueueSubmit))},
{"vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueWaitIdle>(QueueWaitIdle))},
{"vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetCommandBuffer>(ResetCommandBuffer))},
@@ -206,21 +209,7 @@
}
PFN_vkVoidFunction GetInstanceProcAddr(const char* name) {
- PFN_vkVoidFunction pfn;
- if ((pfn = Lookup(name, kInstanceProcs)))
- return pfn;
- if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(
- static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(
- GetSwapchainGrallocUsageANDROID));
- if (strcmp(name, "vkAcquireImageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(
- static_cast<PFN_vkAcquireImageANDROID>(AcquireImageANDROID));
- if (strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(
- static_cast<PFN_vkQueueSignalReleaseImageANDROID>(
- QueueSignalReleaseImageANDROID));
- return nullptr;
+ return Lookup(name, kInstanceProcs);
}
} // namespace null_driver
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 98952b8..4052d26 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -145,7 +145,7 @@
VKAPI_ATTR void CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);
VKAPI_ATTR void CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
VKAPI_ATTR void CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
-VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData);
+VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
VKAPI_ATTR void CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
VKAPI_ATTR void CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
VKAPI_ATTR void CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
@@ -165,6 +165,9 @@
VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
+VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
+VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);