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);