Merge "Revert "Remove UID requirement for set sched_fifo for sensor thread"" am: c599e05ba0 am: ad8c578705
am: 1f9a85e4b4

Change-Id: I0dc233cf9ad379961301a1574bbcbceee016cace
diff --git a/Android.bp b/Android.bp
index cd05b21..de9ea86 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8,8 +8,15 @@
 
 subdirs = [
     "cmds/*",
+    "headers",
     "libs/*",
     "opengl",
     "services/*",
     "vulkan",
 ]
+
+cc_library_headers {
+    name: "libandroid_sensor_headers",
+    vendor: true,
+    export_include_dirs: ["include_sensor"],
+}
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 2d9a98c..a48dab9 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -124,6 +124,7 @@
         { OPT,      "events/sched/sched_waking/enable" },
         { OPT,      "events/sched/sched_blocked_reason/enable" },
         { OPT,      "events/sched/sched_cpu_hotplug/enable" },
+        { OPT,      "events/cgroup/enable" },
     } },
     { "irq",        "IRQ Events",   0, {
         { REQ,      "events/irq/enable" },
@@ -480,8 +481,8 @@
         newClock = "global";
     }
 
-    size_t begin = clockStr.find("[") + 1;
-    size_t end = clockStr.find("]");
+    size_t begin = clockStr.find('[') + 1;
+    size_t end = clockStr.find(']');
     if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) {
         return true;
     }
@@ -542,7 +543,7 @@
     auto listRet = sm->list([&](const auto &interfaces) {
         for (size_t i = 0; i < interfaces.size(); i++) {
             string fqInstanceName = interfaces[i];
-            string::size_type n = fqInstanceName.find("/");
+            string::size_type n = fqInstanceName.find('/');
             if (n == std::string::npos || interfaces[i].size() == n+1)
                 continue;
             hidl_string fqInterfaceName = fqInstanceName.substr(0, n);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 526fd19..3ea1d56 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -25,6 +25,8 @@
     chown root shell /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
     chown root shell /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
     chown root shell /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
+    chown root shell /sys/kernel/debug/tracing/events/cgroup/enable
+    chown root shell /sys/kernel/tracing/events/cgroup/enable
     chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
     chown root shell /sys/kernel/tracing/events/power/cpu_frequency/enable
     chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
@@ -77,6 +79,8 @@
     chmod 0664 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
     chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
     chmod 0664 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/cgroup/enable
+    chmod 0664 /sys/kernel/tracing/events/cgroup/enable
     chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
     chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency/enable
     chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
new file mode 100644
index 0000000..f908cbf
--- /dev/null
+++ b/cmds/dumpstate/Android.bp
@@ -0,0 +1,130 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "dumpstate_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+}
+
+cc_library_headers {
+    name: "dumpstate_headers",
+    vendor_available: true,
+    export_include_dirs: ["."],
+    header_libs: [
+        "libbase_headers",
+        "libutils_headers",
+    ],
+    export_header_lib_headers: [
+        "libbase_headers",
+        "libutils_headers",
+    ],
+}
+
+cc_library_shared {
+    name: "libdumpstateutil",
+    defaults: ["dumpstate_defaults"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    header_libs: ["dumpstate_headers"],
+    export_header_lib_headers: ["dumpstate_headers"],
+    srcs: [
+        "DumpstateInternal.cpp",
+        "DumpstateUtil.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+}
+
+cc_library_shared {
+    name: "libdumpstateaidl",
+    defaults: ["dumpstate_defaults"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+    aidl: {
+        local_include_dirs: ["binder"],
+        export_aidl_headers: true,
+    },
+    srcs: [
+        "binder/android/os/IDumpstate.aidl",
+        "binder/android/os/IDumpstateListener.aidl",
+        "binder/android/os/IDumpstateToken.aidl",
+    ],
+}
+
+cc_binary {
+    name: "dumpstate",
+    defaults: ["dumpstate_defaults"],
+    header_libs: ["dumpstate_headers"],
+    shared_libs: [
+        "android.hardware.dumpstate@1.0",
+        "libziparchive",
+        "libbase",
+        "libbinder",
+        "libcrypto",
+        "libcutils",
+        "libdebuggerd_client",
+        "libdumpstateaidl",
+        "libdumpstateutil",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+    srcs: [
+        "DumpstateInternal.cpp",
+        "DumpstateService.cpp",
+        "utils.cpp",
+        "dumpstate.cpp",
+    ],
+    init_rc: ["dumpstate.rc"],
+}
+
+cc_test {
+    name: "dumpstate_test",
+    defaults: ["dumpstate_defaults"],
+    header_libs: ["dumpstate_headers"],
+    shared_libs: [
+        "libziparchive",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libdebuggerd_client",
+        "libdumpstateaidl",
+        "libdumpstateutil",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+    srcs: [
+        "DumpstateInternal.cpp",
+        "DumpstateService.cpp",
+        "utils.cpp",
+        "tests/dumpstate_test.cpp",
+    ],
+    static_libs: ["libgmock"],
+}
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index a1b6a51..ea5fbf1 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -1,137 +1,5 @@
 LOCAL_PATH:= $(call my-dir)
 
-# ================#
-# Common settings #
-# ================#
-# ZipArchive support, the order matters here to get all symbols.
-COMMON_ZIP_LIBRARIES := libziparchive libz libcrypto
-
-# TODO: ideally the tests should depend on a shared dumpstate library, but currently libdumpstate
-# is used to define the device-specific HAL library. Instead, both dumpstate and dumpstate_test
-# shares a lot of common settings
-COMMON_LOCAL_CFLAGS := \
-       -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
-COMMON_SRC_FILES := \
-        DumpstateInternal.cpp \
-        utils.cpp
-COMMON_SHARED_LIBRARIES := \
-        android.hardware.dumpstate@1.0 \
-        libhidlbase \
-        libhidltransport \
-        libbase \
-        libbinder \
-        libcutils \
-        libdebuggerd_client \
-        libdumpstateaidl \
-        libdumpstateutil \
-        liblog \
-        libselinux \
-        libutils \
-        $(COMMON_ZIP_LIBRARIES)
-
-# ====================#
-# libdumpstateutil #
-# ====================#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libdumpstateutil
-
-LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_SRC_FILES := \
-        DumpstateInternal.cpp \
-        DumpstateUtil.cpp
-LOCAL_SHARED_LIBRARIES := \
-        libbase \
-        liblog \
-
-include $(BUILD_SHARED_LIBRARY)
-
-# ====================#
-# libdumpstateheaders #
-# ====================#
-# TODO: this module is necessary so the device-specific libdumpstate implementations do not
-# need to add any other dependency (like libbase). Should go away once dumpstate HAL changes.
-include $(CLEAR_VARS)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS = $(LOCAL_PATH)
-LOCAL_MODULE := libdumpstateheaders
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
-        $(COMMON_SHARED_LIBRARIES)
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \
-        $(COMMON_STATIC_LIBRARIES)
-# Soong requires that whats is on LOCAL_EXPORTED_ is also on LOCAL_
-LOCAL_SHARED_LIBRARIES := $(LOCAL_EXPORT_SHARED_LIBRARY_HEADERS)
-LOCAL_STATIC_LIBRARIES := $(LOCAL_EXPORT_STATIC_LIBRARY_HEADERS)
-
-include $(BUILD_STATIC_LIBRARY)
-
-# ================ #
-# libdumpstateaidl #
-# =================#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libdumpstateaidl
-
-LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
-
-LOCAL_SHARED_LIBRARIES := \
-        libbinder \
-        libutils
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/binder
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/binder
-LOCAL_SRC_FILES := \
-        binder/android/os/IDumpstate.aidl \
-        binder/android/os/IDumpstateListener.aidl \
-        binder/android/os/IDumpstateToken.aidl
-
-include $(BUILD_SHARED_LIBRARY)
-
-# ==========#
-# dumpstate #
-# ==========#
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \
-        DumpstateService.cpp \
-        dumpstate.cpp
-
-LOCAL_MODULE := dumpstate
-
-LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES)
-
-LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES)
-
-LOCAL_CFLAGS += $(COMMON_LOCAL_CFLAGS)
-
-LOCAL_INIT_RC := dumpstate.rc
-
-include $(BUILD_EXECUTABLE)
-
-# ===============#
-# dumpstate_test #
-# ===============#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := dumpstate_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
-
-LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \
-        DumpstateService.cpp \
-        tests/dumpstate_test.cpp
-
-LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES) \
-        libgmock
-
-LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES)
-
-include $(BUILD_NATIVE_TEST)
-
 # =======================#
 # dumpstate_test_fixture #
 # =======================#
@@ -141,38 +9,14 @@
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
+LOCAL_CFLAGS := \
+       -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_SRC_FILES := \
         tests/dumpstate_test_fixture.cpp
 
-LOCAL_MODULE_CLASS := NATIVE_TESTS
-
-dumpstate_tests_intermediates := $(local-intermediates-dir)/DATA
-dumpstate_tests_subpath_from_data := nativetest/dumpstate_test_fixture
-dumpstate_tests_root_in_device := /data/$(dumpstate_tests_subpath_from_data)
-dumpstate_tests_root_for_test_zip := $(dumpstate_tests_intermediates)/$(dumpstate_tests_subpath_from_data)
-testdata_files := $(call find-subdir-files, testdata/*)
-
-# Copy test data files to intermediates/DATA for use with LOCAL_PICKUP_FILES
-GEN := $(addprefix $(dumpstate_tests_root_for_test_zip)/, $(testdata_files))
-$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
-$(GEN): $(dumpstate_tests_root_for_test_zip)/testdata/% : $(LOCAL_PATH)/testdata/%
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-# Copy test data files again to $OUT/data so the tests can be run with adb sync
-# TODO: the build system should do this automatically
-GEN := $(addprefix $(TARGET_OUT_DATA)/$(dumpstate_tests_subpath_from_data)/, $(testdata_files))
-$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
-$(GEN): $(TARGET_OUT_DATA)/$(dumpstate_tests_subpath_from_data)/testdata/% : $(LOCAL_PATH)/testdata/%
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-LOCAL_PICKUP_FILES := $(dumpstate_tests_intermediates)
+LOCAL_TEST_DATA := $(call find-test-data-in-subdirs, $(LOCAL_PATH), *, tests/testdata)
 
 include $(BUILD_NATIVE_TEST)
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index 0343277..f0b6203 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -18,6 +18,8 @@
 
 #include "DumpstateInternal.h"
 
+#include <grp.h>
+#include <pwd.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -25,14 +27,14 @@
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <cstdint>
 #include <string>
 #include <vector>
 
 #include <android-base/file.h>
-#include <cutils/log.h>
-#include <private/android_filesystem_config.h>
+#include <log/log.h>
 
 uint64_t Nanotime() {
     timespec ts;
@@ -42,7 +44,17 @@
 
 // Switches to non-root user and group.
 bool DropRootUser() {
-    if (getgid() == AID_SHELL && getuid() == AID_SHELL) {
+    struct group* grp = getgrnam("shell");
+    gid_t shell_gid = grp != nullptr ? grp->gr_gid : 0;
+    struct passwd* pwd = getpwnam("shell");
+    uid_t shell_uid = pwd != nullptr ? pwd->pw_uid : 0;
+
+    if (!shell_gid || !shell_uid) {
+        MYLOGE("Unable to get AID_SHELL: %s\n", strerror(errno));
+        return false;
+    }
+
+    if (getgid() == shell_gid && getuid() == shell_uid) {
         MYLOGD("drop_root_user(): already running as Shell\n");
         return true;
     }
@@ -52,17 +64,28 @@
         return false;
     }
 
-    gid_t groups[] = {AID_LOG,  AID_SDCARD_R,     AID_SDCARD_RW, AID_MOUNT,
-                      AID_INET, AID_NET_BW_STATS, AID_READPROC,  AID_BLUETOOTH};
-    if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
+    static const std::vector<std::string> group_names{
+        "log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats", "readproc", "bluetooth"};
+    std::vector<gid_t> groups(group_names.size(), 0);
+    for (size_t i = 0; i < group_names.size(); ++i) {
+        grp = getgrnam(group_names[i].c_str());
+        groups[i] = grp != nullptr ? grp->gr_gid : 0;
+        if (groups[i] == 0) {
+            MYLOGE("Unable to get required gid '%s': %s\n", group_names[i].c_str(),
+                   strerror(errno));
+            return false;
+        }
+    }
+
+    if (setgroups(groups.size(), groups.data()) != 0) {
         MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
         return false;
     }
-    if (setgid(AID_SHELL) != 0) {
+    if (setgid(shell_gid) != 0) {
         MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
         return false;
     }
-    if (setuid(AID_SHELL) != 0) {
+    if (setuid(shell_uid) != 0) {
         MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
         return false;
     }
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 7488827..ea7109b 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -30,7 +30,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/log.h>
+#include <log/log.h>
 
 #include "DumpstateInternal.h"
 
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index d4d787a..79397d2 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -126,8 +126,7 @@
 static const std::string kDumpstateBoardPath = "/bugreports/";
 static const std::string kDumpstateBoardFiles[] = {
     "dumpstate_board.txt",
-    // TODO: rename to dumpstate_board.bin once vendors can handle it
-    "modem_log_all.tar"
+    "dumpstate_board.bin"
 };
 static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
 
@@ -145,10 +144,12 @@
  * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
  * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
  * is set, the vector only contains files that were written in the last 30 minutes.
+ * If |limit_by_count| is set, the vector only contains the ten latest files.
  */
 static std::vector<DumpData>* GetDumpFds(const std::string& dir_path,
                                          const std::string& file_prefix,
-                                         bool limit_by_mtime) {
+                                         bool limit_by_mtime,
+                                         bool limit_by_count = true) {
     const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
 
     std::unique_ptr<std::vector<DumpData>> dump_data(new std::vector<DumpData>());
@@ -191,6 +192,10 @@
 
     std::sort(dump_data->begin(), dump_data->end());
 
+    if (limit_by_count && dump_data->size() > 10) {
+        dump_data->erase(dump_data->begin() + 10, dump_data->end());
+    }
+
     return dump_data.release();
 }
 
@@ -692,7 +697,7 @@
     std::string valid_name = entry_name;
 
     // Rename extension if necessary.
-    size_t idx = entry_name.rfind(".");
+    size_t idx = entry_name.rfind('.');
     if (idx != std::string::npos) {
         std::string extension = entry_name.substr(idx);
         std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
@@ -930,8 +935,10 @@
                  "VM TRACES AT LAST ANR", add_to_zip);
 
         if (anr_data->size() > 1) {
+            // NOTE: Historical ANRs are always added as separate entries in the
+            // bugreport zip file.
             AddDumps(anr_data->begin() + 1, anr_data->end(),
-                     "HISTORICAL ANR", add_to_zip);
+                     "HISTORICAL ANR", true /* add_to_zip */);
         }
     } else {
         printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
@@ -1432,7 +1439,7 @@
     return true;
 }
 
-static std::string SHA256_file_hash(std::string filepath) {
+static std::string SHA256_file_hash(const std::string& filepath) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
             | O_CLOEXEC | O_NOFOLLOW)));
     if (fd == -1) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index f02303b..7757c1e 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,10 +26,11 @@
 #include <vector>
 
 #include <android-base/macros.h>
+#include <android/os/IDumpstateListener.h>
+#include <utils/StrongPointer.h>
 #include <ziparchive/zip_writer.h>
 
 #include "DumpstateUtil.h"
-#include "android/os/BnDumpstate.h"
 
 // Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
 // std::vector<std::string>
@@ -49,6 +50,8 @@
 }  // namespace os
 }  // namespace android
 
+class ZipWriter;
+
 // TODO: remove once moved to HAL
 #ifdef __cplusplus
 extern "C" {
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 52698b2..92b0c0d 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -94,7 +94,7 @@
   protected:
     const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str());
     const std::string kFixturesPath = kTestPath + "/../dumpstate_test_fixture/";
-    const std::string kTestDataPath = kFixturesPath + "/testdata/";
+    const std::string kTestDataPath = kFixturesPath + "tests/testdata/";
     const std::string kSimpleCommand = kFixturesPath + "dumpstate_test_fixture";
     const std::string kEchoCommand = "/system/bin/echo";
 
diff --git a/cmds/dumpstate/testdata/empty-file.txt b/cmds/dumpstate/tests/testdata/empty-file.txt
similarity index 100%
rename from cmds/dumpstate/testdata/empty-file.txt
rename to cmds/dumpstate/tests/testdata/empty-file.txt
diff --git a/cmds/dumpstate/testdata/multiple-lines-with-newline.txt b/cmds/dumpstate/tests/testdata/multiple-lines-with-newline.txt
similarity index 100%
rename from cmds/dumpstate/testdata/multiple-lines-with-newline.txt
rename to cmds/dumpstate/tests/testdata/multiple-lines-with-newline.txt
diff --git a/cmds/dumpstate/testdata/multiple-lines.txt b/cmds/dumpstate/tests/testdata/multiple-lines.txt
similarity index 100%
rename from cmds/dumpstate/testdata/multiple-lines.txt
rename to cmds/dumpstate/tests/testdata/multiple-lines.txt
diff --git a/cmds/dumpstate/testdata/single-line-with-newline.txt b/cmds/dumpstate/tests/testdata/single-line-with-newline.txt
similarity index 100%
rename from cmds/dumpstate/testdata/single-line-with-newline.txt
rename to cmds/dumpstate/tests/testdata/single-line-with-newline.txt
diff --git a/cmds/dumpstate/testdata/single-line.txt b/cmds/dumpstate/tests/testdata/single-line.txt
similarity index 100%
rename from cmds/dumpstate/testdata/single-line.txt
rename to cmds/dumpstate/tests/testdata/single-line.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt b/cmds/dumpstate/tests/testdata/stats-invalid-1st-NAN.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-1st-NAN.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-negative.txt b/cmds/dumpstate/tests/testdata/stats-invalid-1st-negative.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-1st-negative.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-1st-negative.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt b/cmds/dumpstate/tests/testdata/stats-invalid-1st-too-big.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-1st-too-big.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt b/cmds/dumpstate/tests/testdata/stats-invalid-2nd-NAN.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-2nd-NAN.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt b/cmds/dumpstate/tests/testdata/stats-invalid-2nd-negative.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-2nd-negative.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt b/cmds/dumpstate/tests/testdata/stats-invalid-2nd-too-big.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-2nd-too-big.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-both-NAN.txt b/cmds/dumpstate/tests/testdata/stats-invalid-both-NAN.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-invalid-both-NAN.txt
rename to cmds/dumpstate/tests/testdata/stats-invalid-both-NAN.txt
diff --git a/cmds/dumpstate/testdata/stats-one-run-no-newline.txt b/cmds/dumpstate/tests/testdata/stats-one-run-no-newline.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-one-run-no-newline.txt
rename to cmds/dumpstate/tests/testdata/stats-one-run-no-newline.txt
diff --git a/cmds/dumpstate/testdata/stats-two-runs.txt b/cmds/dumpstate/tests/testdata/stats-two-runs.txt
similarity index 100%
rename from cmds/dumpstate/testdata/stats-two-runs.txt
rename to cmds/dumpstate/tests/testdata/stats-two-runs.txt
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index f0e7200..3227749 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -16,6 +16,7 @@
 
 #include <algorithm>
 #include <chrono>
+#include <iomanip>
 #include <thread>
 
 #include <android-base/file.h>
@@ -176,7 +177,7 @@
     }
 
     for (size_t i = 0; i < N; i++) {
-        String16 service_name = std::move(services[i]);
+        const String16& service_name = std::move(services[i]);
         if (IsSkipped(skippedServices, service_name)) continue;
 
         sp<IBinder> service = sm_->checkService(service_name);
@@ -282,7 +283,14 @@
               std::chrono::duration<double> elapsed_seconds =
                   std::chrono::steady_clock::now() - start;
               aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
-                   << "was the duration of dumpsys " << service_name << endl;
+                   << "was the duration of dumpsys " << service_name;
+
+              using std::chrono::system_clock;
+              const auto finish = system_clock::to_time_t(system_clock::now());
+              std::tm finish_tm;
+              localtime_r(&finish, &finish_tm);
+              aout << ", ending at: " << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S")
+                   << endl;
             }
         } else {
             aerr << "Can't find service: " << service_name << endl;
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 66beb6d..16fefe6 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -35,6 +35,7 @@
 using ::testing::Eq;
 using ::testing::HasSubstr;
 using ::testing::MakeAction;
+using ::testing::Mock;
 using ::testing::Not;
 using ::testing::Return;
 using ::testing::StrEq;
@@ -95,7 +96,7 @@
     }
     int i = 0;
     std::ostringstream actual_stream, expected_stream;
-    for (String16 actual : arg) {
+    for (const String16& actual : arg) {
         std::string actual_str = String8(actual).c_str();
         std::string expected_str = expected[i];
         actual_stream << "'" << actual_str << "' ";
@@ -155,10 +156,11 @@
             .WillRepeatedly(DoAll(WithArg<0>(WriteOnFd(output)), Return(0)));
     }
 
-    void ExpectDumpAndHang(const char* name, int timeout_s, const std::string& output) {
+    sp<BinderMock> ExpectDumpAndHang(const char* name, int timeout_s, const std::string& output) {
         sp<BinderMock> binder_mock = ExpectCheckService(name);
         EXPECT_CALL(*binder_mock, dump(_, _))
             .WillRepeatedly(DoAll(Sleep(timeout_s), WithArg<0>(WriteOnFd(output)), Return(0)));
+        return binder_mock;
     }
 
     void CallMain(const std::vector<std::string>& args) {
@@ -245,15 +247,15 @@
 
 // Tests 'dumpsys -t 1 service_name' on a service that times out after 2s
 TEST_F(DumpsysTest, DumpRunningServiceTimeout) {
-    ExpectDumpAndHang("Valet", 2, "Here's your car");
+    sp<BinderMock> binder_mock = ExpectDumpAndHang("Valet", 2, "Here's your car");
 
     CallMain({"-t", "1", "Valet"});
 
     AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1s) EXPIRED");
     AssertNotDumped("Here's your car");
 
-    // Must wait so binder mock is deleted, otherwise test will fail with a leaked object
-    sleep(1);
+    // TODO(b/65056227): BinderMock is not destructed because thread is detached on dumpsys.cpp
+    Mock::AllowLeak(binder_mock.get());
 }
 
 // Tests 'dumpsys service_name Y U NO HAVE ARGS' on a service that is running
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index e293948..ea0cd9e 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -60,7 +60,7 @@
 
     ATRACE_BEGIN("loadStats tree");
     cacheUsed = 0;
-    for (auto path : mDataPaths) {
+    for (const auto& path : mDataPaths) {
         auto cachePath = read_path_inode(path, "cache", kXattrInodeCache);
         auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
         calculate_tree_size(cachePath, &cacheUsed);
@@ -148,6 +148,7 @@
         }
 
         // Bubble up modified time to parent
+        CHECK(p != nullptr);
         switch (p->fts_info) {
         case FTS_DP:
         case FTS_DEFAULT:
@@ -169,7 +170,7 @@
     items.clear();
 
     ATRACE_BEGIN("loadItems");
-    for (auto path : mDataPaths) {
+    for (const auto& path : mDataPaths) {
         loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache));
         loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache));
     }
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index aac4386..4a93b1f 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -311,6 +311,7 @@
         return -1;
     }
 
+#if APPLY_HARD_QUOTAS
     if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
         auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
         struct statvfs stat;
@@ -320,7 +321,8 @@
         }
 
         dq.dqb_valid = QIF_LIMITS;
-        dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
+        dq.dqb_bhardlimit =
+            (((static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
         dq.dqb_ihardlimit = (stat.f_files / 2);
         if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
                 reinterpret_cast<char*>(&dq)) != 0) {
@@ -334,6 +336,10 @@
         // Hard quota already set; assume it's reasonable
         return 0;
     }
+#else
+    // Hard quotas disabled
+    return 0;
+#endif
 }
 
 binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
@@ -1346,7 +1352,7 @@
         const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
-    for (auto packageName : packageNames) {
+    for (const auto& packageName : packageNames) {
         CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     }
     // NOTE: Locking is relaxed on this method, since it's limited to
@@ -1385,7 +1391,7 @@
     }
 
     ATRACE_BEGIN("obb");
-    for (auto packageName : packageNames) {
+    for (const auto& packageName : packageNames) {
         auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
         calculate_tree_size(obbCodePath, &extStats.codeSize);
     }
@@ -1393,7 +1399,7 @@
 
     if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
         ATRACE_BEGIN("code");
-        for (auto codePath : codePaths) {
+        for (const auto& codePath : codePaths) {
             calculate_tree_size(codePath, &stats.codeSize, -1,
                     multiuser_get_shared_gid(0, appId));
         }
@@ -1404,7 +1410,7 @@
         ATRACE_END();
     } else {
         ATRACE_BEGIN("code");
-        for (auto codePath : codePaths) {
+        for (const auto& codePath : codePaths) {
             calculate_tree_size(codePath, &stats.codeSize);
         }
         ATRACE_END();
@@ -1644,6 +1650,7 @@
     int64_t videoSize = 0;
     int64_t imageSize = 0;
     int64_t appSize = 0;
+    int64_t obbSize = 0;
 
     auto device = findQuotaDeviceForUuid(uuid);
     if (device.empty()) {
@@ -1691,6 +1698,13 @@
 #endif
             imageSize = dq.dqb_curspace;
         }
+        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
+                reinterpret_cast<char*>(&dq)) == 0) {
+#if MEASURE_DEBUG
+            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
+#endif
+            obbSize = dq.dqb_curspace;
+        }
         ATRACE_END();
 
         ATRACE_BEGIN("apps");
@@ -1747,6 +1761,11 @@
         }
         fts_close(fts);
         ATRACE_END();
+
+        ATRACE_BEGIN("obb");
+        auto obbPath = create_data_media_obb_path(uuid_, "");
+        calculate_tree_size(obbPath, &obbSize);
+        ATRACE_END();
     }
 
     std::vector<int64_t> ret;
@@ -1755,6 +1774,7 @@
     ret.push_back(videoSize);
     ret.push_back(imageSize);
     ret.push_back(appSize);
+    ret.push_back(obbSize);
 #if MEASURE_DEBUG
     LOG(DEBUG) << "Final result " << toString(ret);
 #endif
@@ -1814,8 +1834,8 @@
         const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
         int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
         const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
-        const std::unique_ptr<std::string>& sharedLibraries,
-        const std::unique_ptr<std::string>& seInfo) {
+        const std::unique_ptr<std::string>& classLoaderContext,
+        const std::unique_ptr<std::string>& seInfo, bool downgrade) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     if (packageName && *packageName != "*") {
@@ -1829,10 +1849,11 @@
     const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
     const char* compiler_filter = compilerFilter.c_str();
     const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
-    const char* shared_libraries = sharedLibraries ? sharedLibraries->c_str() : nullptr;
+    const char* class_loader_context = classLoaderContext ? classLoaderContext->c_str() : nullptr;
     const char* se_info = seInfo ? seInfo->c_str() : nullptr;
     int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
-            oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries, se_info);
+            oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
+            downgrade);
     return res ? error(res, "Failed to dexopt") : ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5756b82..c8db3df 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -83,8 +83,8 @@
             const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
             int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
             const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
-            const std::unique_ptr<std::string>& sharedLibraries,
-            const std::unique_ptr<std::string>& seInfo);
+            const std::unique_ptr<std::string>& classLoaderContext,
+            const std::unique_ptr<std::string>& seInfo, bool downgrade);
 
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index c8e76b0..452a2b1 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -51,7 +51,7 @@
             @nullable @utf8InCpp String outputPath, int dexFlags,
             @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
             @nullable @utf8InCpp String sharedLibraries,
-            @nullable @utf8InCpp String seInfo);
+            @nullable @utf8InCpp String seInfo, boolean downgrade);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 9466259..6f7ab6b 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -196,7 +196,7 @@
 static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
-        bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) {
+        bool debuggable, bool post_bootcomplete, int profile_fd, const char* class_loader_context) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -297,6 +297,12 @@
     char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
     bool have_dex2oat_image_fd = false;
     char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
+    size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
+    char class_loader_context_arg[class_loader_context_size];
+    if (class_loader_context != nullptr) {
+        snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
+            class_loader_context);
+    }
 
     sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
     sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
@@ -393,7 +399,7 @@
                      + (have_app_image_format ? 1 : 0)
                      + dex2oat_flags_count
                      + (profile_fd == -1 ? 0 : 1)
-                     + (shared_libraries != nullptr ? 4 : 0)
+                     + (class_loader_context != nullptr ? 1 : 0)
                      + (has_base_dir ? 1 : 0)
                      + (have_dex2oat_large_app_threshold ? 1 : 0)];
     int i = 0;
@@ -453,15 +459,13 @@
     if (profile_fd != -1) {
         argv[i++] = profile_arg;
     }
-    if (shared_libraries != nullptr) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = "-classpath";
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = shared_libraries;
-    }
     if (has_base_dir) {
         argv[i++] = base_dir;
     }
+    if (class_loader_context != nullptr) {
+        argv[i++] = class_loader_context_arg;
+    }
+
     // Do not add after dex2oat_flags, they should override others for debugging.
     argv[i] = NULL;
 
@@ -1372,7 +1376,7 @@
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
 // the profile has changed.
 static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& instruction_set,
-        const std::string& compiler_filter, bool profile_was_updated) {
+        const std::string& compiler_filter, bool profile_was_updated, bool downgrade) {
     const char* dexoptanalyzer_bin =
             is_debug_runtime()
                     ? "/system/bin/dexoptanalyzerd"
@@ -1389,9 +1393,13 @@
     std::string isa_arg = "--isa=" + instruction_set;
     std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
     const char* assume_profile_changed = "--assume-profile-changed";
+    const char* downgrade_flag = "--downgrade";
 
     // program name, dex file, isa, filter, the final NULL
-    const char* argv[5 + (profile_was_updated ? 1 : 0)];
+    const int argc = 5 +
+        (profile_was_updated ? 1 : 0) +
+        (downgrade ? 1 : 0);
+    const char* argv[argc];
     int i = 0;
     argv[i++] = dexoptanalyzer_bin;
     argv[i++] = dex_file_arg.c_str();
@@ -1400,6 +1408,9 @@
     if (profile_was_updated) {
         argv[i++] = assume_profile_changed;
     }
+    if (downgrade) {
+        argv[i++] = downgrade_flag;
+    }
     argv[i] = NULL;
 
     execv(dexoptanalyzer_bin, (char * const *)argv);
@@ -1480,7 +1491,7 @@
 static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
         int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
         const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
-        std::string* oat_dir_out, std::string* dex_path_out) {
+        std::string* oat_dir_out, std::string* dex_path_out, bool downgrade) {
     int storage_flag;
 
     if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
@@ -1549,7 +1560,8 @@
         // child -- drop privileges before continuing.
         drop_capabilities(uid);
         // Run dexoptanalyzer to get dexopt_needed code.
-        exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated);
+        exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated,
+                            downgrade);
         exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
     }
 
@@ -1576,7 +1588,8 @@
 
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
-        const char* volume_uuid, const char* shared_libraries, const char* se_info) {
+        const char* volume_uuid, const char* class_loader_context, const char* se_info,
+        bool downgrade) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
     if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
@@ -1584,7 +1597,12 @@
     }
 
     if (!validate_dex_path_size(dex_path)) {
-        return false;
+        return -1;
+    }
+
+    if (class_loader_context != nullptr && strlen(class_loader_context) > PKG_PATH_MAX) {
+        LOG(ERROR) << "Class loader context exceeds the allowed size: " << class_loader_context;
+        return -1;
     }
 
     bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
@@ -1599,7 +1617,8 @@
     if (is_secondary_dex) {
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                 instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                &dex_real_path)) {
+                &dex_real_path,
+                downgrade)) {
             oat_dir = oat_dir_str.c_str();
             dex_path = dex_real_path.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
@@ -1688,7 +1707,7 @@
                     debuggable,
                     boot_complete,
                     reference_profile_fd.get(),
-                    shared_libraries);
+                    class_loader_context);
         _exit(68);   /* only get here on exec failure */
     } else {
         int res = wait_child(pid);
@@ -1786,8 +1805,14 @@
     }
 
     const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+
+    // Note that we cannot validate the package path here because the file might not exist
+    // and we cannot call realpath to resolve system symlinks. Since /data/user/0 symlinks to
+    // /data/data/ a lot of validations will fail if we attempt to check the package path.
+    // It is still ok to be more relaxed because any file removal is done after forking and
+    // dropping capabilities.
     if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
-            uid, storage_flag)) {
+            uid, storage_flag, /*validate_package_path*/ false)) {
         LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
         return false;
     }
@@ -1801,37 +1826,56 @@
         return false;
     }
 
-    // The secondary dex does not exist anymore. Clear any generated files.
-    char oat_path[PKG_PATH_MAX];
-    char oat_dir[PKG_PATH_MAX];
-    char oat_isa_dir[PKG_PATH_MAX];
-    bool result = true;
-    for (size_t i = 0; i < isas.size(); i++) {
-        if (!create_secondary_dex_oat_layout(dex_path, isas[i], oat_dir, oat_isa_dir, oat_path)) {
-            LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
-            result = false;
-            continue;
-        }
+    // As a security measure we want to unlink art artifacts with the reduced capabilities
+    // of the package user id. So we fork and drop capabilities in the child.
+    pid_t pid = fork();
+    if (pid == 0) {
+        // The secondary dex does not exist anymore. Clear any generated files.
+        char oat_path[PKG_PATH_MAX];
+        char oat_dir[PKG_PATH_MAX];
+        char oat_isa_dir[PKG_PATH_MAX];
+        bool result = true;
+        /* child -- drop privileges before continuing */
+        drop_capabilities(uid);
+        for (size_t i = 0; i < isas.size(); i++) {
+            if (!create_secondary_dex_oat_layout(dex_path,
+                                                 isas[i],
+                                                 oat_dir,
+                                                 oat_isa_dir,
+                                                 oat_path)) {
+                LOG(ERROR) << "Could not create secondary odex layout: "
+                           << dex_path;
+                result = false;
+                continue;
+            }
 
-        // Delete oat/vdex/art files.
-        result = unlink_if_exists(oat_path) && result;
-        result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
-        result = unlink_if_exists(create_image_filename(oat_path)) && result;
+            // Delete oat/vdex/art files.
+            result = unlink_if_exists(oat_path) && result;
+            result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
+            result = unlink_if_exists(create_image_filename(oat_path)) && result;
 
-        // Delete profiles.
-        std::string current_profile = create_current_profile_path(
+            // Delete profiles.
+            std::string current_profile = create_current_profile_path(
                 multiuser_get_user_id(uid), dex_path, /*is_secondary*/true);
-        std::string reference_profile = create_reference_profile_path(
+            std::string reference_profile = create_reference_profile_path(
                 dex_path, /*is_secondary*/true);
-        result = unlink_if_exists(current_profile) && result;
-        result = unlink_if_exists(reference_profile) && result;
+            result = unlink_if_exists(current_profile) && result;
+            result = unlink_if_exists(reference_profile) && result;
 
-        // Try removing the directories as well, they might be empty.
-        result = rmdir_if_empty(oat_isa_dir) && result;
-        result = rmdir_if_empty(oat_dir) && result;
+            // We upgraded once the location of current profile for secondary dex files.
+            // Check for any previous left-overs and remove them as well.
+            std::string old_current_profile = dex_path + ".prof";
+            result = unlink_if_exists(old_current_profile);
+
+            // Try removing the directories as well, they might be empty.
+            result = rmdir_if_empty(oat_isa_dir) && result;
+            result = rmdir_if_empty(oat_dir) && result;
+        }
+        result ? _exit(0) : _exit(1);
     }
 
-    return result;
+    int return_code = wait_child(pid);
+    return return_code == 0;
 }
 
 // Helper for move_ab, so that we can have common failure-case cleanup.
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index d171ee5..23446da 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -63,7 +63,8 @@
 
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
-        const char* volume_uuid, const char* shared_libraries, const char* se_info);
+        const char* volume_uuid, const char* class_loader_context, const char* se_info,
+        bool downgrade);
 
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 68cb0d7..09e1a00 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -178,6 +178,7 @@
         const char* volume_uuid;
         const char* shared_libraries;
         const char* se_info;
+        bool downgrade;
     };
 
     bool ReadSystemProperties() {
@@ -281,6 +282,13 @@
         return true;
     }
 
+    bool ParseBool(const char* in) {
+        if (strcmp(in, "true") == 0) {
+            return true;
+        }
+        return false;
+    }
+
     bool ParseUInt(const char* in, uint32_t* out) {
         char* end;
         long long int result = strtoll(in, &end, 0);
@@ -349,6 +357,8 @@
         switch (version) {
             case 2:
                 return ReadArgumentsV2(argc, argv, true);
+            case 3:
+                return ReadArgumentsV3(argc, argv);
 
             default:
                 LOG(ERROR) << "Unsupported version " << version;
@@ -427,6 +437,10 @@
             }
         }
 
+        // Set downgrade to false. It is only relevant when downgrading compiler
+        // filter, which is not the case during ota.
+        package_parameters_.downgrade = false;
+
         if (param_index != 11) {
             LOG(ERROR) << "Not enough parameters";
             return false;
@@ -435,6 +449,89 @@
         return true;
     }
 
+    bool ReadArgumentsV3(int argc ATTRIBUTE_UNUSED, char** argv) {
+        size_t dexopt_index = 3;
+
+        // Check for "dexopt".
+        if (argv[dexopt_index] == nullptr) {
+            LOG(ERROR) << "Missing parameters";
+            return false;
+        }
+        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+            LOG(ERROR) << "Expected \"dexopt\"";
+            return false;
+        }
+
+        size_t param_index = 0;
+        for (;; ++param_index) {
+            const char* param = argv[dexopt_index + 1 + param_index];
+            if (param == nullptr) {
+                break;
+            }
+
+            switch (param_index) {
+                case 0:
+                    package_parameters_.apk_path = param;
+                    break;
+
+                case 1:
+                    package_parameters_.uid = atoi(param);
+                    break;
+
+                case 2:
+                    package_parameters_.pkgName = param;
+                    break;
+
+                case 3:
+                    package_parameters_.instruction_set = param;
+                    break;
+
+                case 4:
+                    package_parameters_.dexopt_needed = atoi(param);
+                    break;
+
+                case 5:
+                    package_parameters_.oat_dir = param;
+                    break;
+
+                case 6:
+                    package_parameters_.dexopt_flags = atoi(param);
+                    break;
+
+                case 7:
+                    package_parameters_.compiler_filter = param;
+                    break;
+
+                case 8:
+                    package_parameters_.volume_uuid = ParseNull(param);
+                    break;
+
+                case 9:
+                    package_parameters_.shared_libraries = ParseNull(param);
+                    break;
+
+                case 10:
+                    package_parameters_.se_info = ParseNull(param);
+                    break;
+
+                case 11:
+                    package_parameters_.downgrade = ParseBool(param);
+                    break;
+
+                default:
+                    LOG(ERROR) << "Too many arguments, got " << param;
+                    return false;
+            }
+        }
+
+        if (param_index != 12) {
+            LOG(ERROR) << "Not enough parameters";
+            return false;
+        }
+
+        return true;
+    }
+
     static int ReplaceMask(int input, int old_mask, int new_mask) {
         return (input & old_mask) != 0 ? new_mask : 0;
     }
@@ -534,6 +631,10 @@
         // receive from a v1 A side.
         package_parameters_.se_info = nullptr;
 
+        // Set downgrade to false. It is only relevant when downgrading compiler
+        // filter, which is not the case during ota.
+        package_parameters_.downgrade = false;
+
         return true;
     }
 
@@ -753,10 +854,6 @@
     }
 
     static const char* ParseNull(const char* arg) {
-        // b/38186355. Revert soon.
-        if (strcmp(arg, "!null") == 0) {
-            return nullptr;
-        }
         return (strcmp(arg, "!") == 0) ? nullptr : arg;
     }
 
@@ -823,7 +920,8 @@
                       package_parameters_.compiler_filter,
                       package_parameters_.volume_uuid,
                       package_parameters_.shared_libraries,
-                      package_parameters_.se_info);
+                      package_parameters_.se_info,
+                      package_parameters_.downgrade);
     }
 
     int RunPreopt() {
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index aed068c..2d58515 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -99,7 +99,7 @@
 static int64_t free() {
     struct statvfs buf;
     if (!statvfs("/data/local/tmp", &buf)) {
-        return buf.f_bavail * buf.f_frsize;
+        return static_cast<int64_t>(buf.f_bavail) * buf.f_frsize;
     } else {
         PLOG(ERROR) << "Failed to statvfs";
         return -1;
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index dab3236..46ed85f 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -38,16 +38,6 @@
 
 #define TEST_PROFILE_DIR "/data/misc/profiles"
 
-#define REALLY_LONG_APP_NAME "com.example." \
-        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
-        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
-        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-
-#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
-        "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
-        "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
-        "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_"
-
 namespace android {
 namespace installd {
 
@@ -88,6 +78,14 @@
     virtual void TearDown() {
         free(android_system_dirs.dirs);
     }
+
+    std::string create_too_long_path(const std::string& seed) {
+        std::string result = seed;
+        for (size_t i = seed.size(); i < PKG_PATH_MAX; i++) {
+            result += "a";
+        }
+        return result;
+    }
 };
 
 TEST_F(UtilsTest, IsValidApkPath_BadPrefix) {
@@ -388,17 +386,18 @@
             << "Primary user package directory should be created correctly";
 }
 
+
 TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
     char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0))
+    std::string really_long_app_name = create_too_long_path("com.example");
+    EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0))
             << "Should fail to create move path for primary user";
 }
 
 TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
     char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0))
+    std::string really_long_leaf_name = create_too_long_path("leaf_");
+    EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0))
             << "Should fail to create move path for primary user";
 }
 
@@ -560,7 +559,7 @@
 }
 
 TEST_F(UtilsTest, CreateSecondaryCurrentProfile) {
-    EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof",
+    EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof",
             create_current_profile_path(/*user*/0,
                     "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
 }
@@ -571,5 +570,88 @@
                     "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
 }
 
+static void pass_secondary_dex_validation(const std::string& package_name,
+        const std::string& dex_path, int uid, int storage_flag) {
+    EXPECT_TRUE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid,
+            storage_flag))
+            << dex_path << " should be allowed as a valid secondary dex path";
+}
+
+static void fail_secondary_dex_validation(const std::string& package_name,
+        const std::string& dex_path, int uid, int storage_flag) {
+    EXPECT_FALSE(validate_secondary_dex_path(package_name, dex_path, /*volume_uuid*/ nullptr, uid,
+            storage_flag))
+            << dex_path << " should not be allowed as a valid secondary dex path";
+}
+
+TEST_F(UtilsTest, ValidateSecondaryDexFilesPath) {
+    std::string package_name = "com.test.app";
+    std::string app_dir_ce_user_0 = "/data/data/" + package_name;
+    std::string app_dir_ce_user_10 = "/data/user/10/" + package_name;
+
+    std::string app_dir_de_user_0 = "/data/user_de/0/" + package_name;
+    std::string app_dir_de_user_10 = "/data/user_de/10/" + package_name;
+
+    EXPECT_EQ(app_dir_ce_user_0,
+            create_data_user_ce_package_path(nullptr, 0, package_name.c_str()));
+    EXPECT_EQ(app_dir_ce_user_10,
+            create_data_user_ce_package_path(nullptr, 10, package_name.c_str()));
+
+    EXPECT_EQ(app_dir_de_user_0,
+            create_data_user_de_package_path(nullptr, 0, package_name.c_str()));
+    EXPECT_EQ(app_dir_de_user_10,
+            create_data_user_de_package_path(nullptr, 10, package_name.c_str()));
+
+    uid_t app_uid_for_user_0 = multiuser_get_uid(/*user_id*/0, /*app_id*/ 1234);
+    uid_t app_uid_for_user_10 = multiuser_get_uid(/*user_id*/10, /*app_id*/ 1234);
+
+    // Standard path for user 0 on CE storage.
+    pass_secondary_dex_validation(
+        package_name, app_dir_ce_user_0 + "/ce0.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+    // Standard path for user 10 on CE storage.
+    pass_secondary_dex_validation(
+        package_name, app_dir_ce_user_10 + "/ce10.dex", app_uid_for_user_10, FLAG_STORAGE_CE);
+
+    // Standard path for user 0 on DE storage.
+    pass_secondary_dex_validation(
+        package_name, app_dir_de_user_0 + "/de0.dex", app_uid_for_user_0, FLAG_STORAGE_DE);
+    // Standard path for user 10 on DE storage.
+    pass_secondary_dex_validation(
+        package_name, app_dir_de_user_10 + "/de0.dex", app_uid_for_user_10, FLAG_STORAGE_DE);
+
+    // Dex path for user 0 accessed from user 10.
+    fail_secondary_dex_validation(
+        package_name, app_dir_ce_user_0 + "/path0_from10.dex",
+        app_uid_for_user_10, FLAG_STORAGE_CE);
+
+    // Dex path for CE storage accessed with DE.
+    fail_secondary_dex_validation(
+        package_name, app_dir_ce_user_0 + "/ce_from_de.dex", app_uid_for_user_0, FLAG_STORAGE_DE);
+
+    // Dex path for DE storage accessed with CE.
+    fail_secondary_dex_validation(
+        package_name, app_dir_de_user_0 + "/de_from_ce.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+
+    // Location which does not start with '/'.
+    fail_secondary_dex_validation(
+        package_name, "without_slash.dex", app_uid_for_user_10, FLAG_STORAGE_DE);
+
+    // The dex file is not in the specified package directory.
+    fail_secondary_dex_validation(
+        "another.package", app_dir_ce_user_0 + "/for_another_package.dex",
+        app_uid_for_user_0, FLAG_STORAGE_DE);
+
+    // The dex path contains indirect directories.
+    fail_secondary_dex_validation(
+        package_name, app_dir_ce_user_0 + "/1/../foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+    fail_secondary_dex_validation(
+        package_name, app_dir_ce_user_0 + "/1/./foo.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+
+    // Super long path.
+    std::string too_long = create_too_long_path("too_long_");
+    fail_secondary_dex_validation(
+        package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE);
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 8a0e137..93d5c0b 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -238,13 +238,38 @@
 
 // Keep profile paths in sync with ActivityThread and LoadedApk.
 const std::string PROFILE_EXT = ".prof";
+const std::string CURRENT_PROFILE_EXT = ".cur";
 const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;
 
+// Gets the parent directory and the file name for the given secondary dex path.
+// Returns true on success, false on failure (if the dex_path does not have the expected
+// structure).
+static bool get_secondary_dex_location(const std::string& dex_path,
+        std::string* out_dir_name, std::string* out_file_name) {
+   size_t dirIndex = dex_path.rfind('/');
+   if (dirIndex == std::string::npos) {
+        return false;
+   }
+   if (dirIndex == dex_path.size() - 1) {
+        return false;
+   }
+   *out_dir_name = dex_path.substr(0, dirIndex);
+   *out_file_name = dex_path.substr(dirIndex + 1);
+
+   return true;
+}
+
 std::string create_current_profile_path(userid_t user, const std::string& location,
         bool is_secondary_dex) {
     if (is_secondary_dex) {
-        // Secondary dex profiles are stored next to the dex files using .prof extension.
-        return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str());
+        // Secondary dex current profiles are stored next to the dex files under the oat folder.
+        std::string dex_dir;
+        std::string dex_name;
+        CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name))
+                << "Unexpected dir structure for secondary dex " << location;
+        return StringPrintf("%s/oat/%s%s%s",
+                dex_dir.c_str(), dex_name.c_str(), CURRENT_PROFILE_EXT.c_str(),
+                PROFILE_EXT.c_str());
     } else {
         // Profiles for primary apks are under /data/misc/profiles/cur.
         std::string profile_dir = create_primary_current_profile_package_dir_path(user, location);
@@ -255,12 +280,10 @@
 std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) {
     if (is_secondary_dex) {
         // Secondary dex reference profiles are stored next to the dex files under the oat folder.
-        size_t dirIndex = location.rfind('/');
-        CHECK(dirIndex != std::string::npos)
+        std::string dex_dir;
+        std::string dex_name;
+        CHECK(get_secondary_dex_location(location, &dex_dir, &dex_name))
                 << "Unexpected dir structure for secondary dex " << location;
-
-        std::string dex_dir = location.substr(0, dirIndex);
-        std::string dex_name = location.substr(dirIndex +1);
         return StringPrintf("%s/oat/%s%s",
                 dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str());
     } else {
@@ -633,7 +656,7 @@
 int64_t data_disk_free(const std::string& data_path) {
     struct statvfs sfs;
     if (statvfs(data_path.c_str(), &sfs) == 0) {
-        return sfs.f_bavail * sfs.f_frsize;
+        return static_cast<int64_t>(sfs.f_bavail) * sfs.f_frsize;
     } else {
         PLOG(ERROR) << "Couldn't statvfs " << data_path;
         return -1;
@@ -784,24 +807,36 @@
 }
 
 bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
-        const char* volume_uuid, int uid, int storage_flag) {
+        const char* volume_uuid, int uid, int storage_flag, bool validate_package_path) {
     CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);
 
-    std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
-        ? create_data_user_ce_package_path(
-                volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
-        : create_data_user_de_package_path(
-                volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
-    dir_rec_t dir;
-    if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) {
-        LOG(WARNING) << "Could not get dir rec for " << app_private_dir;
-        return false;
+    // Empty paths are not allowed.
+    if (dex_path.empty()) { return false; }
+    // First character should always be '/'. No relative paths.
+    if (dex_path[0] != '/') { return false; }
+    // The last character should not be '/'.
+    if (dex_path[dex_path.size() - 1] == '/') { return false; }
+    // There should be no '.' after the directory marker.
+    if (dex_path.find("/.") != std::string::npos) { return false; }
+    // The path should be at most PKG_PATH_MAX long.
+    if (dex_path.size() > PKG_PATH_MAX) { return false; }
+
+    if (validate_package_path) {
+        // If we are asked to validate the package path check that
+        // the dex_path is under the app data directory.
+        std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
+            ? create_data_user_ce_package_path(
+                    volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
+            : create_data_user_de_package_path(
+                    volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
+
+        if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
+            return false;
+        }
     }
-    // Usually secondary dex files have a nested directory structure.
-    // Pick at most 10 subdirectories when validating (arbitrary value).
-    // If the secondary dex file is >10 directory nested then validation will
-    // fail and the file will not be compiled.
-    return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0;
+
+    // If we got here we have a valid path.
+    return true;
 }
 
 /**
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index ac6a488..a1d8443 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,6 +36,8 @@
 #define BYPASS_QUOTA 0
 #define BYPASS_SDCARDFS 0
 
+#define APPLY_HARD_QUOTAS 1
+
 namespace android {
 namespace installd {
 
@@ -124,7 +126,7 @@
 
 int validate_system_app_path(const char* path);
 bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
-        const char* volume_uuid, int uid, int storage_flag);
+        const char* volume_uuid, int uid, int storage_flag, bool validate_package_path = true);
 
 int get_path_from_env(dir_rec_t* rec, const char* var);
 
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 35b63ec..2b5389b 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -505,7 +505,7 @@
     ALOGV("Setting Transparent Region Hint");
     Region re = Region();
 
-    for (auto r : trhc.region()) {
+    for (const auto& r : trhc.region()) {
         Rect rect = Rect(r.left(), r.top(), r.right(), r.bottom());
         re.merge(rect);
     }
diff --git a/data/etc/android.hardware.radio.xml b/data/etc/android.hardware.broadcastradio.xml
similarity index 93%
rename from data/etc/android.hardware.radio.xml
rename to data/etc/android.hardware.broadcastradio.xml
index f718c47..c669518 100644
--- a/data/etc/android.hardware.radio.xml
+++ b/data/etc/android.hardware.broadcastradio.xml
@@ -16,5 +16,5 @@
 
 <!-- This is the standard set of features for a broadcast radio. -->
 <permissions>
-    <feature name="android.hardware.radio" />
+    <feature name="android.hardware.broadcastradio" />
 </permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 835504f..561f5ba 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -41,7 +41,6 @@
     <feature name="android.software.voice_recognizers" notLowRam="true" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
-    <feature name="android.software.input_methods" />
     <feature name="android.software.print" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 0d5d206..ec7be53 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -45,7 +45,7 @@
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
-    <feature name="android.software.picture_in_picture" />
+    <feature name="android.software.picture_in_picture" notLowRam="true" />
     <feature name="android.software.activities_on_secondary_displays" />
     <feature name="android.software.print" />
     <feature name="android.software.companion_device_setup" />
diff --git a/headers/Android.bp b/headers/Android.bp
new file mode 100644
index 0000000..82bc8a1
--- /dev/null
+++ b/headers/Android.bp
@@ -0,0 +1,20 @@
+cc_library_headers {
+    name: "media_plugin_headers",
+    vendor_available: true,
+    export_include_dirs: [
+        "media_plugin",
+        "media_plugin/media/openmax",
+    ],
+    header_libs: [
+        "libstagefright_headers",
+        "libcutils_headers",
+        "libutils_headers",
+        "libstagefright_foundation_headers",
+    ],
+    export_header_lib_headers: [
+        "libstagefright_headers",
+        "libcutils_headers",
+        "libutils_headers",
+        "libstagefright_foundation_headers",
+    ],
+}
diff --git a/include/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
similarity index 100%
rename from include/media/cas/CasAPI.h
rename to headers/media_plugin/media/cas/CasAPI.h
diff --git a/include/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h
similarity index 100%
rename from include/media/cas/DescramblerAPI.h
rename to headers/media_plugin/media/cas/DescramblerAPI.h
diff --git a/include/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
similarity index 100%
rename from include/media/drm/DrmAPI.h
rename to headers/media_plugin/media/drm/DrmAPI.h
diff --git a/include/media/editor/II420ColorConverter.h b/headers/media_plugin/media/editor/II420ColorConverter.h
similarity index 100%
rename from include/media/editor/II420ColorConverter.h
rename to headers/media_plugin/media/editor/II420ColorConverter.h
diff --git a/include/media/hardware/CryptoAPI.h b/headers/media_plugin/media/hardware/CryptoAPI.h
similarity index 100%
rename from include/media/hardware/CryptoAPI.h
rename to headers/media_plugin/media/hardware/CryptoAPI.h
diff --git a/include/media/hardware/HDCPAPI.h b/headers/media_plugin/media/hardware/HDCPAPI.h
similarity index 100%
rename from include/media/hardware/HDCPAPI.h
rename to headers/media_plugin/media/hardware/HDCPAPI.h
diff --git a/include/media/hardware/HardwareAPI.h b/headers/media_plugin/media/hardware/HardwareAPI.h
similarity index 100%
rename from include/media/hardware/HardwareAPI.h
rename to headers/media_plugin/media/hardware/HardwareAPI.h
diff --git a/include/media/hardware/MetadataBufferType.h b/headers/media_plugin/media/hardware/MetadataBufferType.h
similarity index 100%
rename from include/media/hardware/MetadataBufferType.h
rename to headers/media_plugin/media/hardware/MetadataBufferType.h
diff --git a/include/media/hardware/OMXPluginBase.h b/headers/media_plugin/media/hardware/OMXPluginBase.h
similarity index 100%
rename from include/media/hardware/OMXPluginBase.h
rename to headers/media_plugin/media/hardware/OMXPluginBase.h
diff --git a/include/media/hardware/VideoAPI.h b/headers/media_plugin/media/hardware/VideoAPI.h
similarity index 100%
rename from include/media/hardware/VideoAPI.h
rename to headers/media_plugin/media/hardware/VideoAPI.h
diff --git a/include/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h
similarity index 98%
rename from include/media/openmax/OMX_AsString.h
rename to headers/media_plugin/media/openmax/OMX_AsString.h
index 56d7cc8..dc25ded 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/headers/media_plugin/media/openmax/OMX_AsString.h
@@ -930,6 +930,14 @@
 #ifndef AS_STRING_FOR_OMX_VIDEOEXT_H
 #define AS_STRING_FOR_OMX_VIDEOEXT_H
 
+inline static const char *asString(OMX_VIDEO_AVCPROFILEEXTTYPE i, const char *def = "??") {
+    switch (i) {
+        case OMX_VIDEO_AVCProfileConstrainedBaseline:   return "ConstrainedBaseline";
+        case OMX_VIDEO_AVCProfileConstrainedHigh:       return "ConstrainedHigh";
+        default:                                return asString((OMX_VIDEO_AVCPROFILETYPE)i, def);
+    }
+}
+
 inline static const char *asString(OMX_VIDEO_VP8PROFILETYPE i, const char *def = "??") {
     switch (i) {
         case OMX_VIDEO_VP8ProfileMain:    return "Main";
diff --git a/include/media/openmax/OMX_Audio.h b/headers/media_plugin/media/openmax/OMX_Audio.h
similarity index 100%
rename from include/media/openmax/OMX_Audio.h
rename to headers/media_plugin/media/openmax/OMX_Audio.h
diff --git a/include/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h
similarity index 100%
rename from include/media/openmax/OMX_AudioExt.h
rename to headers/media_plugin/media/openmax/OMX_AudioExt.h
diff --git a/include/media/openmax/OMX_Component.h b/headers/media_plugin/media/openmax/OMX_Component.h
similarity index 100%
rename from include/media/openmax/OMX_Component.h
rename to headers/media_plugin/media/openmax/OMX_Component.h
diff --git a/include/media/openmax/OMX_ContentPipe.h b/headers/media_plugin/media/openmax/OMX_ContentPipe.h
similarity index 100%
rename from include/media/openmax/OMX_ContentPipe.h
rename to headers/media_plugin/media/openmax/OMX_ContentPipe.h
diff --git a/include/media/openmax/OMX_Core.h b/headers/media_plugin/media/openmax/OMX_Core.h
similarity index 100%
rename from include/media/openmax/OMX_Core.h
rename to headers/media_plugin/media/openmax/OMX_Core.h
diff --git a/include/media/openmax/OMX_IVCommon.h b/headers/media_plugin/media/openmax/OMX_IVCommon.h
similarity index 100%
rename from include/media/openmax/OMX_IVCommon.h
rename to headers/media_plugin/media/openmax/OMX_IVCommon.h
diff --git a/include/media/openmax/OMX_Image.h b/headers/media_plugin/media/openmax/OMX_Image.h
similarity index 100%
rename from include/media/openmax/OMX_Image.h
rename to headers/media_plugin/media/openmax/OMX_Image.h
diff --git a/include/media/openmax/OMX_Index.h b/headers/media_plugin/media/openmax/OMX_Index.h
similarity index 100%
rename from include/media/openmax/OMX_Index.h
rename to headers/media_plugin/media/openmax/OMX_Index.h
diff --git a/include/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
similarity index 100%
rename from include/media/openmax/OMX_IndexExt.h
rename to headers/media_plugin/media/openmax/OMX_IndexExt.h
diff --git a/include/media/openmax/OMX_Other.h b/headers/media_plugin/media/openmax/OMX_Other.h
similarity index 100%
rename from include/media/openmax/OMX_Other.h
rename to headers/media_plugin/media/openmax/OMX_Other.h
diff --git a/include/media/openmax/OMX_Types.h b/headers/media_plugin/media/openmax/OMX_Types.h
similarity index 100%
rename from include/media/openmax/OMX_Types.h
rename to headers/media_plugin/media/openmax/OMX_Types.h
diff --git a/include/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
similarity index 100%
rename from include/media/openmax/OMX_Video.h
rename to headers/media_plugin/media/openmax/OMX_Video.h
diff --git a/include/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
similarity index 94%
rename from include/media/openmax/OMX_VideoExt.h
rename to headers/media_plugin/media/openmax/OMX_VideoExt.h
index 128dd2d..c102564 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -58,6 +58,12 @@
     OMX_NALUFORMATSTYPE eNaluFormat;
 } OMX_NALSTREAMFORMATTYPE;
 
+/** AVC additional profiles */
+typedef enum OMX_VIDEO_AVCPROFILEEXTTYPE {
+    OMX_VIDEO_AVCProfileConstrainedBaseline = 0x10000,   /**< Constrained baseline profile */
+    OMX_VIDEO_AVCProfileConstrainedHigh     = 0x80000,   /**< Constrained high profile */
+} OMX_VIDEO_AVCPROFILEEXTTYPE;
+
 /** VP8 profiles */
 typedef enum OMX_VIDEO_VP8PROFILETYPE {
     OMX_VIDEO_VP8ProfileMain = 0x01,
@@ -164,20 +170,20 @@
 
 /** 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_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;
@@ -290,6 +296,8 @@
     OMX_VIDEO_DolbyVisionProfileDvheStn = 0x20,
     OMX_VIDEO_DolbyVisionProfileDvheDth = 0x40,
     OMX_VIDEO_DolbyVisionProfileDvheDtb = 0x80,
+    OMX_VIDEO_DolbyVisionProfileDvheSt  = 0x100,
+    OMX_VIDEO_DolbyVisionProfileDvavSe  = 0x200,
     OMX_VIDEO_DolbyVisionProfileMax     = 0x7FFFFFFF
 } OMX_VIDEO_DOLBYVISIONPROFILETYPE;
 
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 2db0ee7..a88733c 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -197,7 +197,7 @@
  * A sensor event.
  */
 
-/* NOTE: changes to these structs have to be backward compatible */
+/* NOTE: Must match hardware/sensors.h */
 typedef struct ASensorVector {
     union {
         float v[3];
@@ -259,7 +259,7 @@
     };
 } AAdditionalInfoEvent;
 
-/* NOTE: changes to this struct has to be backward compatible */
+/* NOTE: Must match hardware/sensors.h */
 typedef struct ASensorEvent {
     int32_t version; /* sizeof(struct ASensorEvent) */
     int32_t sensor;
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
new file mode 100644
index 0000000..85ac78f
--- /dev/null
+++ b/include/android/sharedmem_jni.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/**
+ * @addtogroup Memory
+ * @{
+ */
+
+/**
+ * @file sharedmem_jni.h
+ */
+
+#ifndef ANDROID_SHARED_MEMORY_JNI_H
+#define ANDROID_SHARED_MEMORY_JNI_H
+
+#include <jni.h>
+#include <android/sharedmem.h>
+#include <stddef.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/**
+ * Structures and functions for a shared memory buffer that can be shared across process.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ANDROID_API__ >= __ANDROID_API_O_MR1__
+
+/**
+ * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file
+ * descriptor has all the same properties & capabilities as the FD returned from
+ * ASharedMemory_create(), however the protection flags will be the same as those of the
+ * android.os.SharedMemory object.
+ *
+ * Use close() to release the shared memory region.
+ *
+ * \param env The JNIEnv* pointer
+ * \param sharedMemory The Java android.os.SharedMemory object
+ * \return file descriptor that denotes the shared memory; -1 if the shared memory object is
+ *      already closed, if the JNIEnv or jobject is NULL, or if there are too many open file
+ *      descriptors (errno=EMFILE)
+ */
+int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory);
+
+#endif
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_SHARED_MEMORY_JNI_H
+
+/** @} */
diff --git a/include/batteryservice b/include/batteryservice
new file mode 120000
index 0000000..2178c32
--- /dev/null
+++ b/include/batteryservice
@@ -0,0 +1 @@
+../services/batteryservice/include/batteryservice/
\ No newline at end of file
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index efa1ffb..9449474 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -370,20 +370,24 @@
         int32_t idToIndex[MAX_POINTER_ID + 1];
         PointerCoords pointers[MAX_POINTERS];
 
-        void initializeFrom(const InputMessage* msg) {
-            eventTime = msg->body.motion.eventTime;
+        void initializeFrom(const InputMessage& msg) {
+            eventTime = msg.body.motion.eventTime;
             idBits.clear();
-            for (uint32_t i = 0; i < msg->body.motion.pointerCount; i++) {
-                uint32_t id = msg->body.motion.pointers[i].properties.id;
+            for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
+                uint32_t id = msg.body.motion.pointers[i].properties.id;
                 idBits.markBit(id);
                 idToIndex[id] = i;
-                pointers[i].copyFrom(msg->body.motion.pointers[i].coords);
+                pointers[i].copyFrom(msg.body.motion.pointers[i].coords);
             }
         }
 
         const PointerCoords& getPointerById(uint32_t id) const {
             return pointers[idToIndex[id]];
         }
+
+        bool hasPointerId(uint32_t id) const {
+            return idBits.hasBit(id);
+        }
     };
     struct TouchState {
         int32_t deviceId;
@@ -402,7 +406,7 @@
             lastResample.idBits.clear();
         }
 
-        void addHistory(const InputMessage* msg) {
+        void addHistory(const InputMessage& msg) {
             historyCurrent ^= 1;
             if (historySize < 2) {
                 historySize += 1;
@@ -413,6 +417,24 @@
         const History* getHistory(size_t index) const {
             return &history[(historyCurrent + index) & 1];
         }
+
+        bool recentCoordinatesAreIdentical(uint32_t id) const {
+            // Return true if the two most recently received "raw" coordinates are identical
+            if (historySize < 2) {
+                return false;
+            }
+            if (!getHistory(0)->hasPointerId(id) || !getHistory(1)->hasPointerId(id)) {
+                return false;
+            }
+            float currentX = getHistory(0)->getPointerById(id).getX();
+            float currentY = getHistory(0)->getPointerById(id).getY();
+            float previousX = getHistory(1)->getPointerById(id).getX();
+            float previousY = getHistory(1)->getPointerById(id).getY();
+            if (currentX == previousX && currentY == previousY) {
+                return true;
+            }
+            return false;
+        }
     };
     Vector<TouchState> mTouchStates;
 
@@ -432,8 +454,8 @@
             Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent,
             int32_t* displayId);
 
-    void updateTouchState(InputMessage* msg);
-    void rewriteMessage(const TouchState& state, InputMessage* msg);
+    void updateTouchState(InputMessage& msg);
+    bool rewriteMessage(const TouchState& state, InputMessage& msg);
     void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
             const InputMessage *next);
 
diff --git a/include/media b/include/media
new file mode 120000
index 0000000..3e7da1c
--- /dev/null
+++ b/include/media
@@ -0,0 +1 @@
+../headers/media_plugin/media
\ No newline at end of file
diff --git a/include_sensor/android/looper.h b/include_sensor/android/looper.h
new file mode 120000
index 0000000..0cf51b8
--- /dev/null
+++ b/include_sensor/android/looper.h
@@ -0,0 +1 @@
+../../include/android/looper.h
\ No newline at end of file
diff --git a/include_sensor/android/sensor.h b/include_sensor/android/sensor.h
new file mode 120000
index 0000000..0626f4f
--- /dev/null
+++ b/include_sensor/android/sensor.h
@@ -0,0 +1 @@
+../../include/android/sensor.h
\ No newline at end of file
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 09fd0cb..83b8021 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -69,8 +69,13 @@
         "TextOutput.cpp",
         "IpPrefix.cpp",
         "Value.cpp",
+        "aidl/android/content/pm/IPackageManagerNative.aidl",
     ],
 
+    aidl: {
+        export_aidl_headers: true,
+    },
+
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
new file mode 100644
index 0000000..3264666
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -0,0 +1,57 @@
+/*
+**
+** Copyright 2017, 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.
+*/
+
+package android.content.pm;
+
+/**
+ * Parallel implementation of certain {@link PackageManager} APIs that need to
+ * be exposed to native code.
+ * <p>These APIs are a parallel definition to the APIs in PackageManager, so,
+ * they can technically diverge. However, it's good practice to keep these
+ * APIs in sync with each other.
+ * <p>Because these APIs are exposed to native code, it's possible they will
+ * be exposed to privileged components [such as UID 0]. Care should be taken
+ * to avoid exposing potential security holes for methods where permission
+ * checks are bypassed based upon UID alone.
+ *
+ * @hide
+ */
+interface IPackageManagerNative {
+    /**
+     * Returns a set of names for the given UIDs.
+     * IMPORTANT: Unlike the Java version of this API, unknown UIDs are
+     * not represented by 'null's. Instead, they are represented by empty
+     * strings.
+     */
+    @utf8InCpp String[] getNamesForUids(in int[] uids);
+
+    /**
+     * Returns the name of the installer (a package) which installed the named
+     * package. Preloaded packages return the string "preload". Sideloaded packages
+     * return an empty string. Unknown or unknowable are returned as empty strings.
+     */
+
+    @utf8InCpp String getInstallerForPackage(in String packageName);
+
+    /**
+     * Returns the version code of the named package.
+     * Unknown or unknowable versions are returned as 0.
+     */
+
+    int getVersionCodeForPackage(in String packageName);
+
+}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 3996305..21debc1 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -96,6 +96,7 @@
         "IProducerListener.cpp",
         "ISurfaceComposer.cpp",
         "ISurfaceComposerClient.cpp",
+        "LayerDebugInfo.cpp",
         "LayerState.cpp",
         "OccupancyTracker.cpp",
         "StreamSplitter.cpp",
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index d9d50db..da42956 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -19,6 +19,8 @@
 //#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #include <utils/Log.h>
 
+#include <inttypes.h>
+
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
 
@@ -31,13 +33,13 @@
 namespace android {
 
 BufferItemConsumer::BufferItemConsumer(
-        const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage,
+        const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
         int bufferCount, bool controlledByApp) :
     ConsumerBase(consumer, controlledByApp)
 {
     status_t err = mConsumer->setConsumerUsageBits(consumerUsage);
     LOG_ALWAYS_FATAL_IF(err != OK,
-            "Failed to set consumer usage bits to %#x", consumerUsage);
+            "Failed to set consumer usage bits to %#" PRIx64, consumerUsage);
     if (bufferCount != DEFAULT_MAX_BUFFERS) {
         err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
         LOG_ALWAYS_FATAL_IF(err != OK,
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 3d94a02..c5cab2d 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -347,10 +347,10 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
-        sp<android::Fence> *outFence, uint32_t width, uint32_t height,
-        PixelFormat format, uint64_t usage,
-        FrameEventHistoryDelta* outTimestamps) {
+status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
+                                            uint32_t width, uint32_t height, PixelFormat format,
+                                            uint64_t usage, uint64_t* outBufferAge,
+                                            FrameEventHistoryDelta* outTimestamps) {
     ATRACE_CALL();
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
@@ -558,6 +558,9 @@
             mSlots[*outSlot].mFrameNumber,
             mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
 
+    if (outBufferAge) {
+        *outBufferAge = mCore->mBufferAge;
+    }
     addAndGetFrameTimestamps(nullptr, outTimestamps);
 
     return returnFlags;
@@ -761,7 +764,7 @@
     input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
             &crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
             &getFrameTimestamps);
-    Region surfaceDamage = input.getSurfaceDamage();
+    const Region& surfaceDamage = input.getSurfaceDamage();
 
     if (acquireFence == NULL) {
         BQ_LOGE("queueBuffer: fence is NULL");
@@ -1099,6 +1102,7 @@
             value = (mCore->mQueue.size() > 1);
             break;
         case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+            // deprecated; higher 32 bits are truncated
             value = static_cast<int32_t>(mCore->mConsumerUsageBits);
             break;
         case NATIVE_WINDOW_DEFAULT_DATASPACE:
@@ -1544,4 +1548,12 @@
     return NO_ERROR;
 }
 
+status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const {
+    BQ_LOGV("getConsumerUsage");
+
+    Mutex::Autolock lock(mCore->mMutex);
+    *outUsage = mCore->mConsumerUsageBits;
+    return NO_ERROR;
+}
+
 } // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 3d36376..7aa7872 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -335,16 +335,25 @@
         return OK;
     }
 
-    auto status = mSlots[slot].mFence->getStatus();
-
-    if (status == Fence::Status::Invalid) {
-        CB_LOGE("fence has invalid state");
+    // Check status of fences first because merging is expensive.
+    // Merging an invalid fence with any other fence results in an
+    // invalid fence.
+    auto currentStatus = mSlots[slot].mFence->getStatus();
+    if (currentStatus == Fence::Status::Invalid) {
+        CB_LOGE("Existing fence has invalid state");
         return BAD_VALUE;
     }
 
-    if (status == Fence::Status::Signaled) {
+    auto incomingStatus = fence->getStatus();
+    if (incomingStatus == Fence::Status::Invalid) {
+        CB_LOGE("New fence has invalid state");
         mSlots[slot].mFence = fence;
-    } else {  // status == Fence::Status::Unsignaled
+        return BAD_VALUE;
+    }
+
+    // If both fences are signaled or both are unsignaled, we need to merge
+    // them to get an accurate timestamp.
+    if (currentStatus == incomingStatus) {
         char fenceName[32] = {};
         snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot);
         sp<Fence> mergedFence = Fence::merge(
@@ -357,7 +366,17 @@
             return BAD_VALUE;
         }
         mSlots[slot].mFence = mergedFence;
+    } else if (incomingStatus == Fence::Status::Unsignaled) {
+        // If one fence has signaled and the other hasn't, the unsignaled
+        // fence will approximately correspond with the correct timestamp.
+        // There's a small race if both fences signal at about the same time
+        // and their statuses are retrieved with unfortunate timing. However,
+        // by this point, they will have both signaled and only the timestamp
+        // will be slightly off; any dependencies after this point will
+        // already have been met.
+        mSlots[slot].mFence = fence;
     }
+    // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
 
     return OK;
 }
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 679c70a..14d9937 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -1115,7 +1115,7 @@
     return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
 }
 
-status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
+status_t GLConsumer::setConsumerUsageBits(uint64_t usage) {
     Mutex::Autolock lock(mMutex);
     if (mAbandoned) {
         GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!");
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 1b0fe06..71e22ce 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -62,7 +62,8 @@
     SET_DEQUEUE_TIMEOUT,
     GET_LAST_QUEUED_BUFFER,
     GET_FRAME_TIMESTAMPS,
-    GET_UNIQUE_ID
+    GET_UNIQUE_ID,
+    GET_CONSUMER_USAGE,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -124,9 +125,9 @@
         return result;
     }
 
-    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,
-            uint32_t height, PixelFormat format, uint64_t usage,
-            FrameEventHistoryDelta* outTimestamps) {
+    virtual status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height,
+                                   PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+                                   FrameEventHistoryDelta* outTimestamps) {
         Parcel data, reply;
         bool getFrameTimestamps = (outTimestamps != nullptr);
 
@@ -149,6 +150,17 @@
             fence->clear();
             return result;
         }
+        if (outBufferAge) {
+            result = reply.readUint64(outBufferAge);
+        } else {
+            // Read the value even if outBufferAge is nullptr:
+            uint64_t bufferAge;
+            result = reply.readUint64(&bufferAge);
+        }
+        if (result != NO_ERROR) {
+            ALOGE("IGBP::dequeueBuffer failed to read buffer age: %d", result);
+            return result;
+        }
         if (getFrameTimestamps) {
             result = reply.read(*outTimestamps);
             if (result != NO_ERROR) {
@@ -493,6 +505,25 @@
         }
         return actualResult;
     }
+
+    virtual status_t getConsumerUsage(uint64_t* outUsage) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        status_t result = remote()->transact(GET_CONSUMER_USAGE, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getConsumerUsage failed to transact: %d", result);
+        }
+        status_t actualResult = NO_ERROR;
+        result = reply.readInt32(&actualResult);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readUint64(outUsage);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return actualResult;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -516,11 +547,10 @@
         return mBase->setAsyncMode(async);
     }
 
-    status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
-            PixelFormat format, uint64_t usage,
-            FrameEventHistoryDelta* outTimestamps) override {
-        return mBase->dequeueBuffer(
-                slot, fence, w, h, format, usage, outTimestamps);
+    status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format,
+                           uint64_t usage, uint64_t* outBufferAge,
+                           FrameEventHistoryDelta* outTimestamps) override {
+        return mBase->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps);
     }
 
     status_t detachBuffer(int slot) override {
@@ -612,6 +642,10 @@
     status_t getUniqueId(uint64_t* outId) const override {
         return mBase->getUniqueId(outId);
     }
+
+    status_t getConsumerUsage(uint64_t* outUsage) const override {
+        return mBase->getConsumerUsage(outUsage);
+    }
 };
 
 IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
@@ -655,16 +689,18 @@
             uint32_t height = data.readUint32();
             PixelFormat format = static_cast<PixelFormat>(data.readInt32());
             uint64_t usage = data.readUint64();
+            uint64_t bufferAge = 0;
             bool getTimestamps = data.readBool();
 
             int buf = 0;
             sp<Fence> fence = Fence::NO_FENCE;
             FrameEventHistoryDelta frameTimestamps;
-            int result = dequeueBuffer(&buf, &fence, width, height, format,
-                    usage, getTimestamps ? &frameTimestamps : nullptr);
+            int result = dequeueBuffer(&buf, &fence, width, height, format, usage, &bufferAge,
+                                       getTimestamps ? &frameTimestamps : nullptr);
 
             reply->writeInt32(buf);
             reply->write(*fence);
+            reply->writeUint64(bufferAge);
             if (getTimestamps) {
                 reply->write(frameTimestamps);
             }
@@ -877,6 +913,20 @@
             }
             return NO_ERROR;
         }
+        case GET_CONSUMER_USAGE: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            uint64_t outUsage = 0;
+            status_t actualResult = getConsumerUsage(&outUsage);
+            status_t result = reply->writeInt32(actualResult);
+            if (result != NO_ERROR) {
+                return result;
+            }
+            result = reply->writeUint64(outUsage);
+            if (result != NO_ERROR) {
+                return result;
+            }
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 0a0d112..8e7f814 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -28,6 +28,7 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerDebugInfo.h>
 
 #include <private/gui/LayerState.h>
 
@@ -469,6 +470,36 @@
         return result;
     }
 
+    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
+    {
+        if (!outLayers) {
+            return UNEXPECTED_NULL;
+        }
+
+        Parcel data, reply;
+
+        status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        int32_t result = 0;
+        err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        outLayers->clear();
+        return reply.readParcelableVector(outLayers);
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -763,6 +794,17 @@
             }
             return injectVSync(when);
         }
+        case GET_LAYER_DEBUG_INFO: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            std::vector<LayerDebugInfo> outLayers;
+            status_t result = getLayerDebugInfo(&outLayers);
+            reply->writeInt32(result);
+            if (result == NO_ERROR)
+            {
+                result = reply->writeParcelableVector(outLayers);
+            }
+            return result;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
new file mode 100644
index 0000000..57ddde0
--- /dev/null
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 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 <gui/LayerDebugInfo.h>
+
+#include <ui/DebugUtils.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/String8.h>
+
+using namespace android;
+
+#define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false)
+
+namespace android {
+
+status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const {
+    RETURN_ON_ERROR(parcel->writeCString(mName.c_str()));
+    RETURN_ON_ERROR(parcel->writeCString(mParentName.c_str()));
+    RETURN_ON_ERROR(parcel->writeCString(mType.c_str()));
+    RETURN_ON_ERROR(parcel->write(mTransparentRegion));
+    RETURN_ON_ERROR(parcel->write(mVisibleRegion));
+    RETURN_ON_ERROR(parcel->write(mSurfaceDamageRegion));
+    RETURN_ON_ERROR(parcel->writeUint32(mLayerStack));
+    RETURN_ON_ERROR(parcel->writeFloat(mX));
+    RETURN_ON_ERROR(parcel->writeFloat(mY));
+    RETURN_ON_ERROR(parcel->writeUint32(mZ));
+    RETURN_ON_ERROR(parcel->writeInt32(mWidth));
+    RETURN_ON_ERROR(parcel->writeInt32(mHeight));
+    RETURN_ON_ERROR(parcel->write(mCrop));
+    RETURN_ON_ERROR(parcel->write(mFinalCrop));
+    RETURN_ON_ERROR(parcel->writeFloat(mAlpha));
+    RETURN_ON_ERROR(parcel->writeUint32(mFlags));
+    RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat));
+    RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace)));
+    for (size_t index = 0; index < 4; index++) {
+        RETURN_ON_ERROR(parcel->writeFloat(mMatrix[index / 2][index % 2]));
+    }
+    RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferWidth));
+    RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferHeight));
+    RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferStride));
+    RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferFormat));
+    RETURN_ON_ERROR(parcel->writeInt32(mNumQueuedFrames));
+    RETURN_ON_ERROR(parcel->writeBool(mRefreshPending));
+    RETURN_ON_ERROR(parcel->writeBool(mIsOpaque));
+    RETURN_ON_ERROR(parcel->writeBool(mContentDirty));
+    return NO_ERROR;
+}
+
+status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) {
+    mName = parcel->readCString();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mParentName = parcel->readCString();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mType = parcel->readCString();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    RETURN_ON_ERROR(parcel->read(mTransparentRegion));
+    RETURN_ON_ERROR(parcel->read(mVisibleRegion));
+    RETURN_ON_ERROR(parcel->read(mSurfaceDamageRegion));
+    RETURN_ON_ERROR(parcel->readUint32(&mLayerStack));
+    RETURN_ON_ERROR(parcel->readFloat(&mX));
+    RETURN_ON_ERROR(parcel->readFloat(&mY));
+    RETURN_ON_ERROR(parcel->readUint32(&mZ));
+    RETURN_ON_ERROR(parcel->readInt32(&mWidth));
+    RETURN_ON_ERROR(parcel->readInt32(&mHeight));
+    RETURN_ON_ERROR(parcel->read(mCrop));
+    RETURN_ON_ERROR(parcel->read(mFinalCrop));
+    RETURN_ON_ERROR(parcel->readFloat(&mAlpha));
+    RETURN_ON_ERROR(parcel->readUint32(&mFlags));
+    RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat));
+    // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways?
+    mDataSpace = static_cast<android_dataspace>(parcel->readUint32());
+    RETURN_ON_ERROR(parcel->errorCheck());
+    for (size_t index = 0; index < 4; index++) {
+        RETURN_ON_ERROR(parcel->readFloat(&mMatrix[index / 2][index % 2]));
+    }
+    RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferWidth));
+    RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferHeight));
+    RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferStride));
+    RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferFormat));
+    RETURN_ON_ERROR(parcel->readInt32(&mNumQueuedFrames));
+    RETURN_ON_ERROR(parcel->readBool(&mRefreshPending));
+    RETURN_ON_ERROR(parcel->readBool(&mIsOpaque));
+    RETURN_ON_ERROR(parcel->readBool(&mContentDirty));
+    return NO_ERROR;
+}
+
+std::string to_string(const LayerDebugInfo& info) {
+    String8 result;
+
+    result.appendFormat("+ %s (%s)\n", info.mType.c_str(), info.mName.c_str());
+    info.mTransparentRegion.dump(result, "TransparentRegion");
+    info.mVisibleRegion.dump(result, "VisibleRegion");
+    info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion");
+
+    result.appendFormat("      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
+            info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY),
+            info.mWidth, info.mHeight);
+
+    result.appendFormat("crop=%s, finalCrop=%s, ",
+            to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str());
+    result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
+    result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
+    result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
+    result.appendFormat("alpha=%.3f, flags=0x%08x, ",
+            static_cast<double>(info.mAlpha), info.mFlags);
+    result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]",
+            static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]),
+            static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1]));
+    result.append("\n");
+    result.appendFormat("      parent=%s\n", info.mParentName.c_str());
+    result.appendFormat("      activeBuffer=[%4ux%4u:%4u,%s],",
+            info.mActiveBufferWidth, info.mActiveBufferHeight,
+            info.mActiveBufferStride,
+            decodePixelFormat(info.mActiveBufferFormat).c_str());
+    result.appendFormat(" queued-frames=%d, mRefreshPending=%d",
+            info.mNumQueuedFrames, info.mRefreshPending);
+    result.append("\n");
+    return std::string(result.c_str());
+}
+
+} // android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 409a3cb..5b1c599 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -44,21 +44,19 @@
 
 namespace android {
 
-Surface::Surface(
-        const sp<IGraphicBufferProducer>& bufferProducer,
-        bool controlledByApp)
-    : mGraphicBufferProducer(bufferProducer),
-      mCrop(Rect::EMPTY_RECT),
-      mGenerationNumber(0),
-      mSharedBufferMode(false),
-      mAutoRefresh(false),
-      mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
-      mSharedBufferHasBeenQueued(false),
-      mQueriedSupportedTimestamps(false),
-      mFrameTimestampsSupportsPresent(false),
-      mEnableFrameTimestamps(false),
-      mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
-{
+Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
+      : mGraphicBufferProducer(bufferProducer),
+        mCrop(Rect::EMPTY_RECT),
+        mBufferAge(0),
+        mGenerationNumber(0),
+        mSharedBufferMode(false),
+        mAutoRefresh(false),
+        mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
+        mSharedBufferHasBeenQueued(false),
+        mQueriedSupportedTimestamps(false),
+        mFrameTimestampsSupportsPresent(false),
+        mEnableFrameTimestamps(false),
+        mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) {
     // Initialize the ANativeWindow function pointers.
     ANativeWindow::setSwapInterval  = hook_setSwapInterval;
     ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
@@ -506,9 +504,10 @@
     nsecs_t startTime = systemTime();
 
     FrameEventHistoryDelta frameTimestamps;
-    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
-            reqWidth, reqHeight, reqFormat, reqUsage,
-            enableFrameTimestamps ? &frameTimestamps : nullptr);
+    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
+                                                            reqFormat, reqUsage, &mBufferAge,
+                                                            enableFrameTimestamps ? &frameTimestamps
+                                                                                  : nullptr);
     mLastDequeueDuration = systemTime() - startTime;
 
     if (result < 0) {
@@ -845,6 +844,14 @@
                 }
                 return err;
             }
+            case NATIVE_WINDOW_BUFFER_AGE: {
+                if (mBufferAge > INT32_MAX) {
+                    *value = 0;
+                } else {
+                    *value = static_cast<int32_t>(mBufferAge);
+                }
+                return NO_ERROR;
+            }
             case NATIVE_WINDOW_LAST_DEQUEUE_DURATION: {
                 int64_t durationUs = mLastDequeueDuration / 1000;
                 *value = durationUs > std::numeric_limits<int>::max() ?
@@ -967,6 +974,9 @@
     case NATIVE_WINDOW_SET_USAGE64:
         res = dispatchSetUsage64(args);
         break;
+    case NATIVE_WINDOW_GET_CONSUMER_USAGE64:
+        res = dispatchGetConsumerUsage64(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -1145,6 +1155,11 @@
     return getHdrSupport(outSupport);
 }
 
+int Surface::dispatchGetConsumerUsage64(va_list args) {
+    uint64_t* usage = va_arg(args, uint64_t*);
+    return getConsumerUsage(usage);
+}
+
 int Surface::connect(int api) {
     static sp<IProducerListener> listener = new DummyProducerListener();
     return connect(api, listener);
@@ -1714,6 +1729,11 @@
     return mGraphicBufferProducer->getUniqueId(outId);
 }
 
+int Surface::getConsumerUsage(uint64_t* outUsage) const {
+    Mutex::Autolock lock(mMutex);
+    return mGraphicBufferProducer->getConsumerUsage(outUsage);
+}
+
 nsecs_t Surface::getLastDequeueStartTime() const {
     Mutex::Autolock lock(mMutex);
     return mLastDequeueStartTime;
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index 7c0552e..3b89291 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -21,6 +21,8 @@
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <gui/bufferqueue/1.0/B2HProducerListener.h>
 
+#include <system/window.h>
+
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -989,10 +991,10 @@
 }
 
 // FIXME: usage bits truncated -- needs a 64-bits usage version
-status_t H2BGraphicBufferProducer::dequeueBuffer(
-        int* slot, sp<Fence>* fence,
-        uint32_t w, uint32_t h, ::android::PixelFormat format,
-        uint64_t usage, FrameEventHistoryDelta* outTimestamps) {
+status_t H2BGraphicBufferProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
+                                                 uint32_t h, ::android::PixelFormat format,
+                                                 uint64_t usage, uint64_t* outBufferAge,
+                                                 FrameEventHistoryDelta* outTimestamps) {
     *fence = new Fence();
     status_t fnStatus;
     status_t transStatus = toStatusT(mBase->dequeueBuffer(
@@ -1016,6 +1018,10 @@
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
+    if (outBufferAge) {
+        // Since the HAL version doesn't return the buffer age, set it to 0:
+        *outBufferAge = 0;
+    }
     return transStatus == NO_ERROR ? fnStatus : transStatus;
 }
 
@@ -1228,6 +1234,18 @@
     return transStatus == NO_ERROR ? fnStatus : transStatus;
 }
 
+status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t* outUsage) const {
+    ALOGW("getConsumerUsage is not fully supported");
+    int result;
+    status_t transStatus = toStatusT(mBase->query(
+            NATIVE_WINDOW_CONSUMER_USAGE_BITS,
+            [&result, outUsage] (int32_t tResult, int32_t tValue) {
+                result = static_cast<int>(tResult);
+                *outUsage = static_cast<uint64_t>(tValue);
+            }));
+    return transStatus == NO_ERROR ? result : static_cast<int>(transStatus);
+}
+
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace bufferqueue
diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
index 217fe6a..d9c5775 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -52,7 +52,7 @@
     // controlledByApp tells whether this consumer is controlled by the
     // application.
     BufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer,
-            uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
+            uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
             bool controlledByApp = false);
 
     ~BufferItemConsumer() override;
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 0f8917a..5c7ffb4 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -80,9 +80,10 @@
     //
     // In both cases, the producer will need to call requestBuffer to get a
     // GraphicBuffer handle for the returned slot.
-    virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
-            uint32_t width, uint32_t height, PixelFormat format,
-            uint64_t usage, FrameEventHistoryDelta* outTimestamps) override;
+    virtual status_t dequeueBuffer(int* outSlot, sp<Fence>* outFence, uint32_t width,
+                                   uint32_t height, PixelFormat format, uint64_t usage,
+                                   uint64_t* outBufferAge,
+                                   FrameEventHistoryDelta* outTimestamps) override;
 
     // See IGraphicBufferProducer::detachBuffer
     virtual status_t detachBuffer(int slot);
@@ -182,6 +183,9 @@
     // See IGraphicBufferProducer::getUniqueId
     virtual status_t getUniqueId(uint64_t* outId) const override;
 
+    // See IGraphicBufferProducer::getConsumerUsage
+    virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 2cf6162..75f2cca 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -210,7 +210,7 @@
     // so the refactoring can proceed smoothly
     status_t setDefaultBufferFormat(PixelFormat defaultFormat);
     status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
-    status_t setConsumerUsageBits(uint32_t usage);
+    status_t setConsumerUsageBits(uint64_t usage);
     status_t setTransformHint(uint32_t hint);
     status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
 
@@ -386,7 +386,7 @@
     // BufferQueue instance; these will be OR:d with any additional flags passed
     // from the GLConsumer user. In particular, GLConsumer will always
     // consume buffers as hardware textures.
-    static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
+    static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
 
     // mCurrentTextureImage is the EglImage/buffer of the current texture. It's
     // possible that this buffer is not associated with any buffer slot, so we
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 6d16e74..039dc0d 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -194,9 +194,9 @@
     //
     // All other negative values are an unknown error returned downstream
     // from the graphics allocator (typically errno).
-    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, PixelFormat format, uint64_t usage,
-            FrameEventHistoryDelta* outTimestamps) = 0;
+    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+                                   PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+                                   FrameEventHistoryDelta* outTimestamps) = 0;
 
     // detachBuffer attempts to remove all ownership of the buffer in the given
     // slot from the buffer queue. If this call succeeds, the slot will be
@@ -593,6 +593,12 @@
 
     // Returns a unique id for this BufferQueue
     virtual status_t getUniqueId(uint64_t* outId) const = 0;
+
+    // Returns the consumer usage flags for this BufferQueue. This returns the
+    // full 64-bit usage flags, rather than the truncated 32-bit usage flags
+    // returned by querying the now deprecated
+    // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute.
+    virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index f80ba00..b226742 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -39,6 +39,7 @@
 struct DisplayState;
 struct DisplayInfo;
 struct DisplayStatInfo;
+class LayerDebugInfo;
 class HdrCapabilities;
 class IDisplayEventConnection;
 class IGraphicBufferProducer;
@@ -195,6 +196,12 @@
     virtual status_t enableVSyncInjections(bool enable) = 0;
 
     virtual status_t injectVSync(nsecs_t when) = 0;
+
+    /* Gets the list of active layers in Z order for debugging purposes
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -229,6 +236,7 @@
         SET_ACTIVE_COLOR_MODE,
         ENABLE_VSYNC_INJECTIONS,
         INJECT_VSYNC,
+        GET_LAYER_DEBUG_INFO,
         CREATE_SCOPED_CONNECTION
     };
 
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
new file mode 100644
index 0000000..8453e04
--- /dev/null
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcelable.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <string>
+
+namespace android {
+
+/* Class for transporting debug info from SurfaceFlinger to authorized
+ * recipients.  The class is intended to be a data container. There are
+ * no getters or setters.
+ */
+class LayerDebugInfo : public Parcelable {
+public:
+    LayerDebugInfo() = default;
+    LayerDebugInfo(const LayerDebugInfo&) = default;
+    virtual ~LayerDebugInfo() = default;
+
+    virtual status_t writeToParcel(Parcel* parcel) const;
+    virtual status_t readFromParcel(const Parcel* parcel);
+
+    std::string mName = std::string("NOT FILLED");
+    std::string mParentName = std::string("NOT FILLED");
+    std::string mType = std::string("NOT FILLED");
+    Region mTransparentRegion = Region::INVALID_REGION;
+    Region mVisibleRegion = Region::INVALID_REGION;
+    Region mSurfaceDamageRegion = Region::INVALID_REGION;
+    uint32_t mLayerStack = 0;
+    float mX = 0.f;
+    float mY = 0.f;
+    uint32_t mZ = 0 ;
+    int32_t mWidth = -1;
+    int32_t mHeight = -1;
+    Rect mCrop = Rect::INVALID_RECT;
+    Rect mFinalCrop = Rect::INVALID_RECT;
+    float mAlpha = 0.f;
+    uint32_t mFlags = 0;
+    PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
+    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+    // Row-major transform matrix (SurfaceControl::setMatrix())
+    float mMatrix[2][2] = {{0.f, 0.f}, {0.f, 0.f}};
+    int32_t mActiveBufferWidth = -1;
+    int32_t mActiveBufferHeight = -1;
+    int32_t mActiveBufferStride = 0;
+    PixelFormat mActiveBufferFormat = PIXEL_FORMAT_NONE;
+    int32_t mNumQueuedFrames = -1;
+    bool mRefreshPending = false;
+    bool mIsOpaque = false;
+    bool mContentDirty = false;
+};
+
+std::string to_string(const LayerDebugInfo& info);
+
+} // namespace android
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 0f7e12a..55dd6bf 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -159,6 +159,7 @@
     status_t getHdrSupport(bool* supported);
 
     status_t getUniqueId(uint64_t* outId) const;
+    status_t getConsumerUsage(uint64_t* outUsage) const;
 
     // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call
     nsecs_t getLastDequeueStartTime() const;
@@ -223,6 +224,7 @@
     int dispatchGetFrameTimestamps(va_list args);
     int dispatchGetWideColorSupport(va_list args);
     int dispatchGetHdrSupport(va_list args);
+    int dispatchGetConsumerUsage64(va_list args);
 
 protected:
     virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@@ -403,6 +405,10 @@
     // (the change since the previous frame) passed in by the producer.
     Region mDirtyRegion;
 
+    // mBufferAge tracks the age of the contents of the most recently dequeued
+    // buffer as the number of frames that have elapsed since it was last queued
+    uint64_t mBufferAge;
+
     // Stores the current generation number. See setGenerationNumber and
     // IGraphicBufferProducer::setGenerationNumber for more information.
     uint32_t mGenerationNumber;
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 8bb705c..c15209d 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -90,6 +90,16 @@
     status_t    setFlags(uint32_t flags, uint32_t mask);
     status_t    setTransparentRegionHint(const Region& transparent);
     status_t    setAlpha(float alpha=1.0f);
+
+    // Experimentarily it appears that the matrix transforms the
+    // on-screen rectangle and it's contents before the position is
+    // applied.
+    //
+    // TODO: Test with other combinations to find approximate transformation rules.
+    //
+    // For example:
+    // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives
+    // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y))
     status_t    setMatrix(float dsdx, float dtdx, float dtdy, float dsdy);
     status_t    setCrop(const Rect& crop);
     status_t    setFinalCrop(const Rect& crop);
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index c3a9d44..74850b4 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -64,9 +64,9 @@
     status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
     status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
     status_t setAsyncMode(bool async) override;
-    status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, ::android::PixelFormat format, uint64_t usage,
-            FrameEventHistoryDelta* outTimestamps) override;
+    status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+                           ::android::PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+                           FrameEventHistoryDelta* outTimestamps) override;
     status_t detachBuffer(int slot) override;
     status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence)
             override;
@@ -94,6 +94,7 @@
           sp<Fence>* outFence, float outTransformMatrix[16]) override;
     void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
     status_t getUniqueId(uint64_t* outId) const override;
+    status_t getConsumerUsage(uint64_t* outUsage) const override;
 };
 
 }  // namespace utils
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
index d64e530..b87cbbd 100644
--- a/libs/gui/tests/BufferItemConsumer_test.cpp
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -76,8 +76,8 @@
 
         int slot;
         sp<Fence> outFence;
-        status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth,
-                                                kHeight, 0, 0, nullptr);
+        status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth, kHeight, 0, 0,
+                                                nullptr, nullptr);
         ASSERT_GE(ret, 0);
 
         ALOGV("dequeueBuffer: slot=%d", slot);
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 4220aaf..9a20859 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -144,8 +144,8 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                       nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataIn;
@@ -188,16 +188,16 @@
 
     for (int i = 0; i < 2; i++) {
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-                mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-                    GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+                  mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+                                           nullptr, nullptr));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
     }
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-                GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+                                       nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
 
@@ -239,8 +239,8 @@
     EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3));
     for (int i = 0; i < 3; i++) {
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-                mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-                    GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+                  mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+                                           nullptr, nullptr));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -275,8 +275,8 @@
     BufferItem item;
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-            GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+                                       nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -285,8 +285,8 @@
 
     for (int i = 0; i < 2; i++) {
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-                mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-                GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
+                  mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN,
+                                           nullptr, nullptr));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -335,8 +335,8 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                       nullptr, nullptr));
     ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
     ASSERT_EQ(OK, mProducer->detachBuffer(slot));
@@ -384,8 +384,8 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                       nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
     IGraphicBufferProducer::QueueBufferInput input(0, false,
             HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
@@ -420,8 +420,8 @@
             EGL_NO_SYNC_KHR, Fence::NO_FENCE));
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                       nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataOut;
@@ -443,8 +443,8 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                       nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataIn;
@@ -492,22 +492,24 @@
     sp<GraphicBuffer> buffer;
     // This should return an error since it would require an allocation
     ASSERT_EQ(OK, mProducer->allowAllocation(false));
-    ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, 0, 0,
-            0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+    ASSERT_EQ(WOULD_BLOCK,
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                       nullptr, nullptr));
 
     // This should succeed, now that we've lifted the prohibition
     ASSERT_EQ(OK, mProducer->allowAllocation(true));
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-            GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                       nullptr, nullptr));
 
     // Release the previous buffer back to the BufferQueue
     mProducer->cancelBuffer(slot, fence);
 
     // This should fail since we're requesting a different size
     ASSERT_EQ(OK, mProducer->allowAllocation(false));
-    ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence,
-            WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+    ASSERT_EQ(WOULD_BLOCK,
+              mProducer->dequeueBuffer(&slot, &fence, WIDTH * 2, HEIGHT * 2, 0,
+                                       GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr));
 }
 
 TEST_F(BufferQueueTest, TestGenerationNumbers) {
@@ -524,7 +526,7 @@
     int slot;
     sp<Fence> fence;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
 
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
@@ -567,7 +569,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
+              mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
 
     // Queue the buffer
@@ -581,8 +583,7 @@
     // always the same one and because async mode gets enabled.
     int slot;
     for (int i = 0; i < 5; i++) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(
-                &slot, &fence, 0, 0, 0, 0, nullptr));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
         ASSERT_EQ(sharedSlot, slot);
         ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
     }
@@ -619,7 +620,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
+              mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
 
     // Queue the buffer
@@ -646,8 +647,7 @@
     // always return the same one.
     int slot;
     for (int i = 0; i < 5; i++) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(
-                &slot, &fence, 0, 0, 0, 0, nullptr));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
         ASSERT_EQ(sharedSlot, slot);
         ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
     }
@@ -686,7 +686,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
+              mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
 
     // Enable shared buffer mode
@@ -703,8 +703,7 @@
     // always the same one and because async mode gets enabled.
     int slot;
     for (int i = 0; i < 5; i++) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(
-                &slot, &fence, 0, 0, 0, 0, nullptr));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
         ASSERT_EQ(sharedSlot, slot);
         ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
     }
@@ -739,8 +738,7 @@
     for (int i = 0; i < 5; ++i) {
         int slot = BufferQueue::INVALID_BUFFER_SLOT;
         sp<Fence> fence = Fence::NO_FENCE;
-        auto result = mProducer->dequeueBuffer(
-                &slot, &fence, 0, 0, 0, 0, nullptr);
+        auto result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr);
         if (i < 2) {
             ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
                     result);
@@ -767,8 +765,7 @@
     for (int i = 0; i < 2; ++i) {
         int slot = BufferQueue::INVALID_BUFFER_SLOT;
         sp<Fence> fence = Fence::NO_FENCE;
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(
-                &slot, &fence, 0, 0, 0, 0, nullptr));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
         IGraphicBufferProducer::QueueBufferInput input(0ull, true,
                 HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
@@ -779,8 +776,7 @@
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> fence = Fence::NO_FENCE;
     auto startTime = systemTime();
-    ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(
-            &slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_GE(systemTime() - startTime, TIMEOUT);
 
     // We're technically attaching the same buffer multiple times (since we
@@ -801,7 +797,7 @@
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> sourceFence;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0, nullptr));
+              mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0, nullptr, nullptr));
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
     ASSERT_EQ(OK, mProducer->detachBuffer(slot));
@@ -824,7 +820,7 @@
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> fence;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     sp<GraphicBuffer> firstBuffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &firstBuffer));
 
@@ -836,7 +832,7 @@
     // Dequeue a second buffer
     slot = BufferQueue::INVALID_BUFFER_SLOT;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+              mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     sp<GraphicBuffer> secondBuffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &secondBuffer));
 
@@ -887,8 +883,8 @@
     int slots[3] = {};
     mProducer->setMaxDequeuedBufferCount(3);
     for (size_t i = 0; i < 3; ++i) {
-        status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
-                0, 0, 0, 0, nullptr);
+        status_t result =
+                mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr);
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
         ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
     }
@@ -901,8 +897,7 @@
     // The first segment is a two-buffer segment, so we only put one buffer into
     // the queue at a time
     for (size_t i = 0; i < 5; ++i) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(
-                &slot, &fence, 0, 0, 0, 0, nullptr));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
         ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -917,17 +912,16 @@
     // two-buffer segment, but then at the end, we put two buffers in the queue
     // at the same time before draining it.
     for (size_t i = 0; i < 5; ++i) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(
-                &slot, &fence, 0, 0, 0, 0, nullptr));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
         ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
                 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
         std::this_thread::sleep_for(16ms);
     }
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
     ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -942,11 +936,10 @@
 
     // The third segment is a triple-buffer segment, so the queue is switching
     // between one buffer and two buffers deep.
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
     for (size_t i = 0; i < 5; ++i) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(
-                &slot, &fence, 0, 0, 0, 0, nullptr));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
         ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -1026,8 +1019,8 @@
     int slots[4] = {};
     mProducer->setMaxDequeuedBufferCount(4);
     for (size_t i = 0; i < 4; ++i) {
-        status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
-                0, 0, 0, 0, nullptr);
+        status_t result =
+                mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr);
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
         ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
     }
@@ -1038,14 +1031,14 @@
     // Get buffers in all states: dequeued, filled, acquired, free
 
     // Fill 3 buffers
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
     // Dequeue 1 buffer
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
 
     // Acquire and free 1 buffer
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -1104,8 +1097,8 @@
     int slots[2] = {};
     ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(2));
     for (size_t i = 0; i < 2; ++i) {
-        status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
-                0, 0, 0, 0, nullptr);
+        status_t result =
+                mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0, nullptr, nullptr);
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
         ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
     }
@@ -1115,10 +1108,10 @@
 
     // Fill 2 buffers without consumer consuming them. Verify that all
     // queued buffer returns proper bufferReplaced flag
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
     ASSERT_EQ(false, output.bufferReplaced);
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
     ASSERT_EQ(true, output.bufferReplaced);
 }
@@ -1140,8 +1133,7 @@
             NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
 
     // Dequeue, request, and queue one buffer
-    status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0,
-            nullptr);
+    status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr);
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
@@ -1156,7 +1148,7 @@
             EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
 
     // Dequeue and queue the buffer again
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
 
     // Acquire and release the buffer again. Upon acquiring, the buffer handle
@@ -1168,7 +1160,7 @@
             EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
 
     // Dequeue and queue the buffer again
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
 
     // Disconnect the producer end. This should clear all of the slots and mark
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index bcfc91c..dd23bd4 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -194,7 +194,8 @@
     };
 
     status_t dequeueBuffer(uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) {
-        return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage, nullptr);
+        return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage,
+                                        nullptr, nullptr);
     }
 
     void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence,
@@ -206,9 +207,12 @@
 
         ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
-        ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-                (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH,
-                DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr)));
+
+        ASSERT_EQ(OK,
+                  ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                          (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                                                    DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS,
+                                                    nullptr, nullptr)));
 
         EXPECT_LE(0, *slot);
         EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, *slot);
@@ -343,11 +347,11 @@
     int dequeuedSlot = -1;
     sp<Fence> dequeuedFence;
 
-
-    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-            (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                     DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS, nullptr)));
+    ASSERT_EQ(OK,
+              ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                      (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+                                                DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                                TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)));
 
     EXPECT_LE(0, dequeuedSlot);
     EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
@@ -403,10 +407,11 @@
     int dequeuedSlot = -1;
     sp<Fence> dequeuedFence;
 
-    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-            (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                     DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS, nullptr)));
+    ASSERT_EQ(OK,
+              ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                      (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+                                                DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                                TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)));
 
     // Slot was enqueued without requesting a buffer
     {
@@ -472,10 +477,11 @@
     int dequeuedSlot = -1;
     sp<Fence> dequeuedFence;
 
-    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-            (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                     DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS, nullptr)));
+    ASSERT_EQ(OK,
+              ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                      (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+                                                DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                                TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)));
 
     // No return code, but at least test that it doesn't blow up...
     // TODO: add a return code
@@ -519,12 +525,11 @@
     int dequeuedSlot = -1;
     sp<Fence> dequeuedFence;
     for (int i = 0; i < maxBuffers; ++i) {
-
-        EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-                (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                         DEFAULT_WIDTH, DEFAULT_HEIGHT,
-                                         DEFAULT_FORMAT,
-                                         TEST_PRODUCER_USAGE_BITS, nullptr)))
+        EXPECT_EQ(OK,
+                  ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                          (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+                                                    DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                                    TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)))
                 << "iteration: " << i << ", slot: " << dequeuedSlot;
     }
 
@@ -557,11 +562,11 @@
     int dequeuedSlot = -1;
     sp<Fence> dequeuedFence;
     for (int i = 0; i < 2; i++) {
-        ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-                (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                         DEFAULT_WIDTH, DEFAULT_HEIGHT,
-                                         DEFAULT_FORMAT,
-                                         TEST_PRODUCER_USAGE_BITS, nullptr)))
+        ASSERT_EQ(OK,
+                  ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                          (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+                                                    DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                                    TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)))
                 << "slot: " << dequeuedSlot;
     }
 
@@ -593,10 +598,11 @@
     // Should now be able to queue/dequeue as many buffers as we want without
     // blocking
     for (int i = 0; i < 5; ++i) {
-        ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-                (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                TEST_PRODUCER_USAGE_BITS, nullptr)))
+        ASSERT_EQ(OK,
+                  ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                          (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+                                                    DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                                    TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)))
                 << "slot : " << dequeuedSlot;
         ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer));
         ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output));
@@ -610,10 +616,11 @@
         int dequeuedSlot = -1;
         sp<Fence> dequeuedFence;
 
-        ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-                (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                TEST_PRODUCER_USAGE_BITS, nullptr)))
+        ASSERT_EQ(OK,
+                  ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                          (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH,
+                                                    DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                                    TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)))
                 << "slot: " << dequeuedSlot;
     }
 
@@ -630,8 +637,9 @@
     int slot = -1;
     sp<Fence> fence;
 
-    ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH,
-            DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr));
+    ASSERT_EQ(NO_INIT,
+              mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                       TEST_PRODUCER_USAGE_BITS, nullptr, nullptr));
 }
 
 TEST_F(IGraphicBufferProducerTest,
@@ -649,10 +657,11 @@
     int slot = -1;
     sp<Fence> fence;
 
-    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-            (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH,
-            DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS,
-            nullptr)));
+    ASSERT_EQ(OK,
+              ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                      (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                                                DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS,
+                                                nullptr, nullptr)));
 
     EXPECT_LE(0, slot);
     EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, slot);
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
index 6bc3ccf..bb6b8a5 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -38,8 +38,10 @@
     }
     status_t setAsyncMode(bool async) override { return mProducer->setAsyncMode(async); }
     status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format,
-                           uint64_t usage, FrameEventHistoryDelta* outTimestamps) override {
-        return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outTimestamps);
+                           uint64_t usage, uint64_t* outBufferAge,
+                           FrameEventHistoryDelta* outTimestamps) override {
+        return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge,
+                                        outTimestamps);
     }
     status_t detachBuffer(int slot) override { return mProducer->detachBuffer(slot); }
     status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override {
@@ -90,6 +92,9 @@
     }
     void getFrameTimestamps(FrameEventHistoryDelta*) override {}
     status_t getUniqueId(uint64_t* outId) const override { return mProducer->getUniqueId(outId); }
+    status_t getConsumerUsage(uint64_t* outUsage) const override {
+        return mProducer->getConsumerUsage(outUsage);
+    }
 
 protected:
     sp<IGraphicBufferProducer> mProducer;
@@ -105,10 +110,10 @@
 
     // Override dequeueBuffer, optionally corrupting the returned slot number
     status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height,
-                           PixelFormat format, uint64_t usage,
+                           PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
                            FrameEventHistoryDelta* outTimestamps) override {
         EXPECT_EQ(BUFFER_NEEDS_REALLOCATION,
-                  mProducer->dequeueBuffer(buf, fence, width, height, format, usage,
+                  mProducer->dequeueBuffer(buf, fence, width, height, format, usage, outBufferAge,
                                            outTimestamps));
         EXPECT_EQ(mExpectedSlot, *buf);
         if (mMaliciousValue != 0) {
diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp
index e2f4948..ad6e051 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -82,8 +82,8 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                           nullptr, nullptr));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataIn;
@@ -116,8 +116,8 @@
     // This should succeed even with allocation disabled since it will have
     // received the buffer back from the output BufferQueue
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                           nullptr, nullptr));
 }
 
 TEST_F(StreamSplitterTest, OneInputMultipleOutputs) {
@@ -154,8 +154,8 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                           nullptr, nullptr));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataIn;
@@ -191,8 +191,8 @@
     // This should succeed even with allocation disabled since it will have
     // received the buffer back from the output BufferQueues
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                           nullptr, nullptr));
 }
 
 TEST_F(StreamSplitterTest, OutputAbandonment) {
@@ -218,8 +218,8 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+              inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                           nullptr, nullptr));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
     // Abandon the output
@@ -231,8 +231,9 @@
     ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput));
 
     // Input should be abandoned
-    ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-            GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
+    ASSERT_EQ(NO_INIT,
+              inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                           nullptr, nullptr));
 }
 
 } // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index e18af17..45e95a5 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -539,6 +539,9 @@
         return NO_ERROR;
     }
     status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; }
+    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
+        return NO_ERROR;
+    }
 
 protected:
     IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 8c6ef69..77f06bb 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -426,7 +426,13 @@
 
     std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
 
-    mCallbacks[descriptor] = {callbackData, pointer};
+    if (pointer != nullptr) {
+        mCallbacks[descriptor] = {callbackData, pointer};
+    } else {
+        ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
+        mCallbacks.erase(descriptor);
+        return Error::None;
+    }
 
     bool hasPendingInvalidate = false;
     std::vector<hwc2_display_t> displayIds;
@@ -2005,10 +2011,21 @@
     return Error::None;
 }
 
+static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+    return rect1.left == rect2.left &&
+            rect1.right == rect2.right &&
+            rect1.top == rect2.top &&
+            rect1.bottom == rect2.bottom;
+}
+
 Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
-    mVisibleRegion.resize(visible.numRects);
-    std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
-    mDisplay.markGeometryChanged();
+    if ((getNumVisibleRegions() != visible.numRects) ||
+        !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
+                    compareRects)) {
+        mVisibleRegion.resize(visible.numRects);
+        std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+        mDisplay.markGeometryChanged();
+    }
     return Error::None;
 }
 
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 9294419..2f39976 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -34,6 +34,7 @@
     clang: true,
 
     shared_libs: [
+        "libbase",
         "liblog",
         "libcutils",
     ],
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 63e98bb..9abd04c 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -496,7 +496,7 @@
             MotionEvent* motionEvent = factory->createMotionEvent();
             if (! motionEvent) return NO_MEMORY;
 
-            updateTouchState(&mMsg);
+            updateTouchState(mMsg);
             initializeMotionEvent(motionEvent, &mMsg);
             *outSeq = mMsg.body.motion.seq;
             *outEvent = motionEvent;
@@ -564,7 +564,7 @@
     uint32_t chain = 0;
     for (size_t i = 0; i < count; i++) {
         InputMessage& msg = batch.samples.editItemAt(i);
-        updateTouchState(&msg);
+        updateTouchState(msg);
         if (i) {
             SeqChain seqChain;
             seqChain.seq = msg.body.motion.seq;
@@ -584,20 +584,19 @@
     return OK;
 }
 
-void InputConsumer::updateTouchState(InputMessage* msg) {
+void InputConsumer::updateTouchState(InputMessage& msg) {
     if (!mResampleTouch ||
-            !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
+            !(msg.body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
         return;
     }
 
-    int32_t deviceId = msg->body.motion.deviceId;
-    int32_t source = msg->body.motion.source;
-    nsecs_t eventTime = msg->body.motion.eventTime;
+    int32_t deviceId = msg.body.motion.deviceId;
+    int32_t source = msg.body.motion.source;
 
     // Update the touch state history to incorporate the new input message.
     // If the message is in the past relative to the most recently produced resampled
     // touch, then use the resampled time and coordinates instead.
-    switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) {
+    switch (msg.body.motion.action & AMOTION_EVENT_ACTION_MASK) {
     case AMOTION_EVENT_ACTION_DOWN: {
         ssize_t index = findTouchState(deviceId, source);
         if (index < 0) {
@@ -615,9 +614,8 @@
         if (index >= 0) {
             TouchState& touchState = mTouchStates.editItemAt(index);
             touchState.addHistory(msg);
-            if (eventTime < touchState.lastResample.eventTime) {
-                rewriteMessage(touchState, msg);
-            } else {
+            bool messageRewritten = rewriteMessage(touchState, msg);
+            if (!messageRewritten) {
                 touchState.lastResample.idBits.clear();
             }
         }
@@ -628,7 +626,7 @@
         ssize_t index = findTouchState(deviceId, source);
         if (index >= 0) {
             TouchState& touchState = mTouchStates.editItemAt(index);
-            touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
+            touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
             rewriteMessage(touchState, msg);
         }
         break;
@@ -639,7 +637,7 @@
         if (index >= 0) {
             TouchState& touchState = mTouchStates.editItemAt(index);
             rewriteMessage(touchState, msg);
-            touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
+            touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
         }
         break;
     }
@@ -666,23 +664,28 @@
     }
 }
 
-void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) {
-    for (uint32_t i = 0; i < msg->body.motion.pointerCount; i++) {
-        uint32_t id = msg->body.motion.pointers[i].properties.id;
+bool InputConsumer::rewriteMessage(const TouchState& state, InputMessage& msg) {
+    bool messageRewritten = false;
+    nsecs_t eventTime = msg.body.motion.eventTime;
+    for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
+        uint32_t id = msg.body.motion.pointers[i].properties.id;
         if (state.lastResample.idBits.hasBit(id)) {
-            PointerCoords& msgCoords = msg->body.motion.pointers[i].coords;
+            PointerCoords& msgCoords = msg.body.motion.pointers[i].coords;
             const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
+            if (eventTime < state.lastResample.eventTime ||
+                    state.recentCoordinatesAreIdentical(id)) {
+                msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
+                msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
 #if DEBUG_RESAMPLING
-            ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
-                    resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
-                    resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y),
-                    msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
-                    msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
+                ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
+                        resampleCoords.getX(), resampleCoords.getY(),
+                        msgCoords.getX(), msgCoords.getY());
 #endif
-            msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
-            msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
+                messageRewritten = true;
+            }
         }
     }
+    return messageRewritten;
 }
 
 void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
@@ -710,6 +713,7 @@
     }
 
     // Ensure that the current sample has all of the pointers that need to be reported.
+    // Also ensure that the past two "real" touch events do not contain duplicate coordinates
     const History* current = touchState.getHistory(0);
     size_t pointerCount = event->getPointerCount();
     for (size_t i = 0; i < pointerCount; i++) {
@@ -720,6 +724,12 @@
 #endif
             return;
         }
+        if (touchState.recentCoordinatesAreIdentical(id)) {
+#if DEBUG_RESAMPLING
+            ALOGD("Not resampled, past two historical events have duplicate coordinates");
+#endif
+            return;
+        }
     }
 
     // Find the data to use for resampling.
@@ -729,12 +739,12 @@
     if (next) {
         // Interpolate between current sample and future sample.
         // So current->eventTime <= sampleTime <= future.eventTime.
-        future.initializeFrom(next);
+        future.initializeFrom(*next);
         other = &future;
         nsecs_t delta = future.eventTime - current->eventTime;
         if (delta < RESAMPLE_MIN_DELTA) {
 #if DEBUG_RESAMPLING
-            ALOGD("Not resampled, delta time is too small: %lld ns.", delta);
+            ALOGD("Not resampled, delta time is too small: %" PRId64 " ns.", delta);
 #endif
             return;
         }
@@ -746,12 +756,12 @@
         nsecs_t delta = current->eventTime - other->eventTime;
         if (delta < RESAMPLE_MIN_DELTA) {
 #if DEBUG_RESAMPLING
-            ALOGD("Not resampled, delta time is too small: %lld ns.", delta);
+            ALOGD("Not resampled, delta time is too small: %" PRId64 " ns.", delta);
 #endif
             return;
         } else if (delta > RESAMPLE_MAX_DELTA) {
 #if DEBUG_RESAMPLING
-            ALOGD("Not resampled, delta time is too large: %lld ns.", delta);
+            ALOGD("Not resampled, delta time is too large: %" PRId64 " ns.", delta);
 #endif
             return;
         }
@@ -759,7 +769,7 @@
         if (sampleTime > maxPredict) {
 #if DEBUG_RESAMPLING
             ALOGD("Sample time is too far in the future, adjusting prediction "
-                    "from %lld to %lld ns.",
+                    "from %" PRId64 " to %" PRId64 " ns.",
                     sampleTime - current->eventTime, maxPredict - current->eventTime);
 #endif
             sampleTime = maxPredict;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 7f6b157..62acea3 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -23,13 +23,14 @@
 // Log debug messages about the progress of the algorithm itself.
 #define DEBUG_STRATEGY 0
 
-#include <math.h>
+#include <inttypes.h>
 #include <limits.h>
+#include <math.h>
 
+#include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <input/VelocityTracker.h>
 #include <utils/BitSet.h>
-#include <utils/String8.h>
 #include <utils/Timers.h>
 
 namespace android {
@@ -46,8 +47,7 @@
 
 static float vectorDot(const float* a, const float* b, uint32_t m) {
     float r = 0;
-    while (m) {
-        m--;
+    for (size_t i = 0; i < m; i++) {
         r += *(a++) * *(b++);
     }
     return r;
@@ -55,8 +55,7 @@
 
 static float vectorNorm(const float* a, uint32_t m) {
     float r = 0;
-    while (m) {
-        m--;
+    for (size_t i = 0; i < m; i++) {
         float t = *(a++);
         r += t * t;
     }
@@ -64,36 +63,36 @@
 }
 
 #if DEBUG_STRATEGY || DEBUG_VELOCITY
-static String8 vectorToString(const float* a, uint32_t m) {
-    String8 str;
-    str.append("[");
-    while (m--) {
-        str.appendFormat(" %f", *(a++));
-        if (m) {
-            str.append(",");
+static std::string vectorToString(const float* a, uint32_t m) {
+    std::string str;
+    str += "[";
+    for (size_t i = 0; i < m; i++) {
+        if (i) {
+            str += ",";
         }
+        str += android::base::StringPrintf(" %f", *(a++));
     }
-    str.append(" ]");
+    str += " ]";
     return str;
 }
 
-static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
-    String8 str;
-    str.append("[");
+static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
+    std::string str;
+    str = "[";
     for (size_t i = 0; i < m; i++) {
         if (i) {
-            str.append(",");
+            str += ",";
         }
-        str.append(" [");
+        str += " [";
         for (size_t j = 0; j < n; j++) {
             if (j) {
-                str.append(",");
+                str += ",";
             }
-            str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]);
+            str += android::base::StringPrintf(" %f", a[rowMajor ? i * n + j : j * m + i]);
         }
-        str.append(" ]");
+        str += " ]";
     }
-    str.append(" ]");
+    str += " ]";
     return str;
 }
 #endif
@@ -244,7 +243,7 @@
     mStrategy->addMovement(eventTime, idBits, positions);
 
 #if DEBUG_VELOCITY
-    ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
+    ALOGD("VelocityTracker: addMovement eventTime=%" PRId64 ", idBits=0x%08x, activePointerId=%d",
             eventTime, idBits.value, mActivePointerId);
     for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
         uint32_t id = iterBits.firstMarkedBit();
@@ -256,8 +255,8 @@
                 "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
                 id, positions[index].x, positions[index].y,
                 int(estimator.degree),
-                vectorToString(estimator.xCoeff, estimator.degree + 1).string(),
-                vectorToString(estimator.yCoeff, estimator.degree + 1).string(),
+                vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(),
+                vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(),
                 estimator.confidence);
     }
 #endif
@@ -443,8 +442,8 @@
         const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) {
 #if DEBUG_STRATEGY
     ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
-            vectorToString(x, m).string(), vectorToString(y, m).string(),
-            vectorToString(w, m).string());
+            vectorToString(x, m).c_str(), vectorToString(y, m).c_str(),
+            vectorToString(w, m).c_str());
 #endif
 
     // Expand the X vector to a matrix A, pre-multiplied by the weights.
@@ -456,7 +455,7 @@
         }
     }
 #if DEBUG_STRATEGY
-    ALOGD("  - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
+    ALOGD("  - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
 #endif
 
     // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
@@ -491,8 +490,8 @@
         }
     }
 #if DEBUG_STRATEGY
-    ALOGD("  - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
-    ALOGD("  - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
+    ALOGD("  - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str());
+    ALOGD("  - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str());
 
     // calculate QR, if we factored A correctly then QR should equal A
     float qr[n][m];
@@ -504,7 +503,7 @@
             }
         }
     }
-    ALOGD("  - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
+    ALOGD("  - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str());
 #endif
 
     // Solve R B = Qt W Y to find B.  This is easy because R is upper triangular.
@@ -522,7 +521,7 @@
         outB[i] /= r[i][i];
     }
 #if DEBUG_STRATEGY
-    ALOGD("  - b=%s", vectorToString(outB, n).string());
+    ALOGD("  - b=%s", vectorToString(outB, n).c_str());
 #endif
 
     // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
@@ -557,6 +556,46 @@
     return true;
 }
 
+/*
+ * Optimized unweighted second-order least squares fit. About 2x speed improvement compared to
+ * the default implementation
+ */
+static float solveUnweightedLeastSquaresDeg2(const float* x, const float* y, size_t count) {
+    float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
+
+    for (size_t i = 0; i < count; i++) {
+        float xi = x[i];
+        float yi = y[i];
+        float xi2 = xi*xi;
+        float xi3 = xi2*xi;
+        float xi4 = xi3*xi;
+        float xi2yi = xi2*yi;
+        float xiyi = xi*yi;
+
+        sxi += xi;
+        sxi2 += xi2;
+        sxiyi += xiyi;
+        sxi2yi += xi2yi;
+        syi += yi;
+        sxi3 += xi3;
+        sxi4 += xi4;
+    }
+
+    float Sxx = sxi2 - sxi*sxi / count;
+    float Sxy = sxiyi - sxi*syi / count;
+    float Sxx2 = sxi3 - sxi*sxi2 / count;
+    float Sx2y = sxi2yi - sxi2*syi / count;
+    float Sx2x2 = sxi4 - sxi2*sxi2 / count;
+
+    float numerator = Sxy*Sx2x2 - Sx2y*Sxx2;
+    float denominator = Sxx*Sx2x2 - Sxx2*Sxx2;
+    if (denominator == 0) {
+        ALOGW("division by 0 when computing velocity, Sxx=%f, Sx2x2=%f, Sxx2=%f", Sxx, Sx2x2, Sxx2);
+        return 0;
+    }
+    return numerator/denominator;
+}
+
 bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
         VelocityTracker::Estimator* outEstimator) const {
     outEstimator->clear();
@@ -598,6 +637,19 @@
         degree = m - 1;
     }
     if (degree >= 1) {
+        if (degree == 2 && mWeighting == WEIGHTING_NONE) { // optimize unweighted, degree=2 fit
+            outEstimator->time = newestMovement.eventTime;
+            outEstimator->degree = 2;
+            outEstimator->confidence = 1;
+            outEstimator->xCoeff[0] = 0; // only slope is calculated, set rest of coefficients = 0
+            outEstimator->yCoeff[0] = 0;
+            outEstimator->xCoeff[1] = solveUnweightedLeastSquaresDeg2(time, x, m);
+            outEstimator->yCoeff[1] = solveUnweightedLeastSquaresDeg2(time, y, m);
+            outEstimator->xCoeff[2] = 0;
+            outEstimator->yCoeff[2] = 0;
+            return true;
+        }
+
         float xdet, ydet;
         uint32_t n = degree + 1;
         if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
@@ -608,8 +660,8 @@
 #if DEBUG_STRATEGY
             ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
                     int(outEstimator->degree),
-                    vectorToString(outEstimator->xCoeff, n).string(),
-                    vectorToString(outEstimator->yCoeff, n).string(),
+                    vectorToString(outEstimator->xCoeff, n).c_str(),
+                    vectorToString(outEstimator->yCoeff, n).c_str(),
                     outEstimator->confidence);
 #endif
             return true;
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 3df97a1..6490804 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -115,7 +115,7 @@
      * The consumer gralloc usage bits currently set by the consumer.
      * The values are defined in hardware/libhardware/include/gralloc.h.
      */
-    NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
+    NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, /* deprecated */
 
     /**
      * Transformation that will by applied to buffers by the hwcomposer.
@@ -224,6 +224,7 @@
     NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT        = 28,
     NATIVE_WINDOW_GET_HDR_SUPPORT               = 29,
     NATIVE_WINDOW_SET_USAGE64                   = 30,
+    NATIVE_WINDOW_GET_CONSUMER_USAGE64          = 31,
 // clang-format on
 };
 
@@ -900,13 +901,18 @@
 
 static inline int native_window_get_wide_color_support(
     struct ANativeWindow* window, bool* outSupport) {
-  return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
-                         outSupport);
+    return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
+            outSupport);
 }
 
 static inline int native_window_get_hdr_support(struct ANativeWindow* window,
                                                 bool* outSupport) {
-  return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+    return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+}
+
+static inline int native_window_get_consumer_usage(struct ANativeWindow* window,
+                                                   uint64_t* outUsage) {
+    return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage);
 }
 
 __END_DECLS
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
deleted file mode 100644
index 6a38a1f..0000000
--- a/libs/sensor/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-ashutoshj@google.com
-pengxu@google.com
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index cabe94e..59173cb 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -108,4 +108,10 @@
     ],
 }
 
+cc_library_headers {
+    name: "libui_headers",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+}
+
 subdirs = ["tests"]
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index d5676cc..2d72944 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -16,10 +16,13 @@
 
 #include <ui/DebugUtils.h>
 #include <ui/PixelFormat.h>
+#include <ui/Rect.h>
 
 #include <android-base/stringprintf.h>
 #include <string>
 
+using android::base::StringPrintf;
+
 std::string decodeStandard(android_dataspace dataspace) {
     const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
     switch (dataspaceSelect) {
@@ -187,7 +190,7 @@
 
 std::string dataspaceDetails(android_dataspace dataspace) {
     if (dataspace == 0) {
-        return "Default (0)";
+        return "Default";
     }
     return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(),
                                        decodeTransfer(dataspace).c_str(),
@@ -262,3 +265,7 @@
             return android::base::StringPrintf("Unknown %#08x", format);
     }
 }
+
+std::string to_string(const android::Rect& rect) {
+    return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom);
+}
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index 39adc5e..755e60c 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -76,7 +76,7 @@
     mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]);
     mMinLuminance        = reinterpret_cast<float const&>(buf[2]);
     if (itemCount) {
-        mSupportedHdrTypes.reserve(itemCount);
+        mSupportedHdrTypes.resize(itemCount);
         for (size_t i = 0; i < itemCount; ++i) {
             mSupportedHdrTypes[i] = buf[4 + i];
         }
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index 30f4a59..dad9446 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -21,9 +21,14 @@
 
 #include <string>
 
+namespace android {
+class Rect;
+}
+
 std::string decodeStandard(android_dataspace dataspace);
 std::string decodeTransfer(android_dataspace dataspace);
 std::string decodeRange(android_dataspace dataspace);
 std::string dataspaceDetails(android_dataspace dataspace);
 std::string decodeColorMode(android_color_mode colormode);
 std::string decodePixelFormat(android::PixelFormat format);
+std::string to_string(const android::Rect& rect);
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index bfb9a55..f9f87ff 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -417,6 +417,28 @@
   on_buffer_removed_ = callback;
 }
 
+pdx::Status<void> BufferHubQueue::FreeAllBuffers() {
+  // Clear all available buffers.
+  available_buffers_.Clear();
+
+  pdx::Status<void> last_error;  // No error.
+  // Clear all buffers this producer queue is tracking.
+  for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
+    if (buffers_[slot] != nullptr) {
+      auto status = RemoveBuffer(slot);
+      if (!status) {
+        ALOGE(
+            "ProducerQueue::FreeAllBuffers: Failed to remove buffer at "
+            "slot=%d.",
+            slot);
+        last_error = status.error_status();
+      }
+    }
+  }
+
+  return last_error;
+}
+
 ProducerQueue::ProducerQueue(LocalChannelHandle handle)
     : BASE(std::move(handle)) {
   auto status = ImportQueue();
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 0f75a5c..53eed89 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -131,9 +131,9 @@
 
 status_t BufferHubQueueProducer::dequeueBuffer(
     int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
-    PixelFormat format, uint64_t usage,
+    PixelFormat format, uint64_t usage, uint64_t* /*outBufferAge*/,
     FrameEventHistoryDelta* /* out_timestamps */) {
-  ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%llu", width,
+  ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width,
            height, format, usage);
 
   status_t ret;
@@ -206,11 +206,11 @@
   // It's either in free state (if the buffer has never been used before) or
   // in queued state (if the buffer has been dequeued and queued back to
   // BufferHubQueue).
-  // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's
-  // model.
-  LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() &&
-                       !buffers_[slot].mBufferState.isQueued()),
-                      "dequeueBuffer: slot %zu is not free or queued.", slot);
+  LOG_ALWAYS_FATAL_IF(
+      (!buffers_[slot].mBufferState.isFree() &&
+       !buffers_[slot].mBufferState.isQueued()),
+      "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+      buffers_[slot].mBufferState.string());
 
   buffers_[slot].mBufferState.freeQueued();
   buffers_[slot].mBufferState.dequeue();
@@ -514,6 +514,7 @@
     return BAD_VALUE;
   }
 
+  FreeAllBuffers();
   connected_api_ = kNoConnectedApi;
   return NO_ERROR;
 }
@@ -608,6 +609,14 @@
   return NO_ERROR;
 }
 
+status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const {
+  ALOGD_IF(TRACE, __FUNCTION__);
+
+  // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
+  *out_usage = 0;
+  return NO_ERROR;
+}
+
 status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height,
                                                 uint32_t layer_count,
                                                 PixelFormat format,
@@ -647,5 +656,31 @@
   return NO_ERROR;
 }
 
+status_t BufferHubQueueProducer::FreeAllBuffers() {
+  for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
+    // Reset in memory objects related the the buffer.
+    buffers_[slot].mGraphicBuffer = nullptr;
+    buffers_[slot].mBufferState.reset();
+    buffers_[slot].mRequestBufferCalled = false;
+    buffers_[slot].mBufferProducer = nullptr;
+    buffers_[slot].mFence = Fence::NO_FENCE;
+  }
+
+  auto status = queue_->FreeAllBuffers();
+  if (!status) {
+    ALOGE(
+        "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on "
+        "the queue: %s",
+        status.GetErrorMessage().c_str());
+  }
+
+  if (queue_->capacity() != 0 || queue_->count() != 0) {
+    LOG_ALWAYS_FATAL(
+        "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed.");
+  }
+
+  return NO_ERROR;
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index d57c7af..0699fef 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -66,6 +66,11 @@
 
   explicit operator bool() const { return epoll_fd_.IsValid(); }
 
+  int GetBufferId(size_t slot) const {
+    return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
+                                                      : -1;
+  }
+
   std::shared_ptr<BufferHubBuffer> GetBuffer(size_t slot) const {
     return buffers_[slot];
   }
@@ -122,6 +127,10 @@
   // to deregister a buffer for epoll and internal bookkeeping.
   virtual pdx::Status<void> RemoveBuffer(size_t slot);
 
+  // Free all buffers that belongs to this queue. Can only be called from
+  // producer side.
+  virtual pdx::Status<void> FreeAllBuffers();
+
   // Dequeue a buffer from the free queue, blocking until one is available. The
   // timeout argument specifies the number of milliseconds that |Dequeue()| will
   // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely,
@@ -214,7 +223,7 @@
   // Tracks the buffers belonging to this queue. Buffers are stored according to
   // "slot" in this vector. Each slot is a logical id of the buffer within this
   // queue regardless of its queue position or presence in the ring buffer.
-  std::vector<std::shared_ptr<BufferHubBuffer>> buffers_{kMaxQueueCapacity};
+  std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_;
 
   // Buffers and related data that are available for dequeue.
   RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
@@ -297,6 +306,11 @@
   // Remove producer buffer from the queue.
   pdx::Status<void> RemoveBuffer(size_t slot) override;
 
+  // Free all buffers on this producer queue.
+  pdx::Status<void> FreeAllBuffers() override {
+    return BufferHubQueue::FreeAllBuffers();
+  }
+
   // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
   // and caller should call Post() once it's done writing to release the buffer
   // to the consumer side.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
index 638a56c..7ed55fb 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
@@ -43,6 +43,7 @@
   // See |IGraphicBufferProducer::dequeueBuffer|
   status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
                          uint32_t height, PixelFormat format, uint64_t usage,
+                         uint64_t* outBufferAge,
                          FrameEventHistoryDelta* outTimestamps) override;
 
   // See |IGraphicBufferProducer::detachBuffer|
@@ -111,6 +112,9 @@
   // See |IGraphicBufferProducer::getUniqueId|
   status_t getUniqueId(uint64_t* out_id) const override;
 
+  // See |IGraphicBufferProducer::getConsumerUsage|
+  status_t getConsumerUsage(uint64_t* out_usage) const override;
+
  private:
   using LocalHandle = pdx::LocalHandle;
 
@@ -131,6 +135,10 @@
   // Remove a buffer via BufferHubRPC.
   status_t RemoveBuffer(size_t slot);
 
+  // Free all buffers which are owned by the prodcuer. Note that if graphic
+  // buffers are acquired by the consumer, we can't .
+  status_t FreeAllBuffers();
+
   // Concreate implementation backed by BufferHubBuffer.
   std::shared_ptr<ProducerQueue> queue_;
 
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index e0a4052..7581a06 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -570,6 +570,103 @@
   EXPECT_EQ(consumer_queue_->is_async(), kIsAsync);
 }
 
+TEST_F(BufferHubQueueTest, TestFreeAllBuffers) {
+  constexpr size_t kBufferCount = 2;
+
+#define CHECK_NO_BUFFER_THEN_ALLOCATE(num_buffers)  \
+  EXPECT_EQ(consumer_queue_->count(), 0U);          \
+  EXPECT_EQ(consumer_queue_->capacity(), 0U);       \
+  EXPECT_EQ(producer_queue_->count(), 0U);          \
+  EXPECT_EQ(producer_queue_->capacity(), 0U);       \
+  for (size_t i = 0; i < num_buffers; i++) {        \
+    AllocateBuffer();                               \
+  }                                                 \
+  EXPECT_EQ(producer_queue_->count(), num_buffers); \
+  EXPECT_EQ(producer_queue_->capacity(), num_buffers);
+
+  size_t slot;
+  uint64_t seq;
+  LocalHandle fence;
+  pdx::Status<void> status;
+  pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status;
+  pdx::Status<std::shared_ptr<BufferProducer>> producer_status;
+  std::shared_ptr<BufferConsumer> consumer_buffer;
+  std::shared_ptr<BufferProducer> producer_buffer;
+
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
+                           UsagePolicy{}));
+
+  // Free all buffers when buffers are avaible for dequeue.
+  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+  status = producer_queue_->FreeAllBuffers();
+  EXPECT_TRUE(status.ok());
+
+  // Free all buffers when one buffer is dequeued.
+  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+  producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+  ASSERT_TRUE(producer_status.ok());
+  status = producer_queue_->FreeAllBuffers();
+  EXPECT_TRUE(status.ok());
+
+  // Free all buffers when all buffers are dequeued.
+  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+  for (size_t i = 0; i < kBufferCount; i++) {
+    producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+    ASSERT_TRUE(producer_status.ok());
+  }
+  status = producer_queue_->FreeAllBuffers();
+  EXPECT_TRUE(status.ok());
+
+  // Free all buffers when one buffer is posted.
+  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+  producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+  ASSERT_TRUE(producer_status.ok());
+  producer_buffer = producer_status.take();
+  ASSERT_NE(nullptr, producer_buffer);
+  ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+  status = producer_queue_->FreeAllBuffers();
+  EXPECT_TRUE(status.ok());
+
+  // Free all buffers when all buffers are posted.
+  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+  for (size_t i = 0; i < kBufferCount; i++) {
+    producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+    ASSERT_TRUE(producer_status.ok());
+    producer_buffer = producer_status.take();
+    ASSERT_NE(nullptr, producer_buffer);
+    ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+  }
+  status = producer_queue_->FreeAllBuffers();
+  EXPECT_TRUE(status.ok());
+
+  // Free all buffers when all buffers are acquired.
+  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+  for (size_t i = 0; i < kBufferCount; i++) {
+    producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+    ASSERT_TRUE(producer_status.ok());
+    producer_buffer = producer_status.take();
+    ASSERT_NE(nullptr, producer_buffer);
+    ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+    consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
+    ASSERT_TRUE(consumer_status.ok());
+  }
+
+  status = producer_queue_->FreeAllBuffers();
+  EXPECT_TRUE(status.ok());
+
+  // In addition to FreeAllBuffers() from the queue, it is also required to
+  // delete all references to the ProducerBuffer (i.e. the PDX client).
+  producer_buffer = nullptr;
+
+  // Crank consumer queue events to pickup EPOLLHUP events on the queue.
+  consumer_queue_->HandleQueueEvents();
+
+  // One last check.
+  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+
+#undef CHECK_NO_BUFFER_THEN_ALLOCATE
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index c7692d0..28cd63a 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -117,9 +117,9 @@
     ASSERT_NE(nullptr, outSlot);
     ASSERT_NE(nullptr, outFence);
 
-    int ret = mProducer->dequeueBuffer(outSlot, outFence, kDefaultWidth,
-                                       kDefaultHeight, kDefaultFormat,
-                                       kTestProducerUsageBits, nullptr);
+    int ret = mProducer->dequeueBuffer(
+        outSlot, outFence, kDefaultWidth, kDefaultHeight, kDefaultFormat,
+        kTestProducerUsageBits, nullptr, nullptr);
     // BUFFER_NEEDS_REALLOCATION can be either on or off.
     ASSERT_EQ(0, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & ret);
 
@@ -440,9 +440,10 @@
   sp<Fence> fence;
   for (int i = 0; i < 2; i++) {
     ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-                      (mProducer->dequeueBuffer(
-                          &slot, &fence, kDefaultWidth, kDefaultHeight,
-                          kDefaultFormat, kTestProducerUsageBits, nullptr)))
+                      (mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
+                                                kDefaultHeight, kDefaultFormat,
+                                                kTestProducerUsageBits,
+                                                nullptr, nullptr)))
         << "slot: " << slot;
   }
 
@@ -458,7 +459,8 @@
 
   ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
                                               kDefaultHeight, kDefaultFormat,
-                                              kTestProducerUsageBits, nullptr));
+                                              kTestProducerUsageBits,
+                                              nullptr, nullptr));
 }
 
 TEST_F(BufferHubQueueProducerTest,
@@ -506,6 +508,44 @@
   ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE));
 }
 
+TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) {
+  int slot = -1;
+  sp<GraphicBuffer> buffer;
+  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+
+  constexpr int maxDequeuedBuffers = 1;
+  int minUndequeuedBuffers;
+  EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                                       &minUndequeuedBuffers));
+  EXPECT_EQ(NO_ERROR, mProducer->setAsyncMode(false));
+  EXPECT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers));
+
+  int maxCapacity = maxDequeuedBuffers + minUndequeuedBuffers;
+
+  // Dequeue, request, and queue all buffers.
+  for (int i = 0; i < maxCapacity; i++) {
+    EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+    EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+    EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output));
+  }
+
+  // Disconnect then reconnect.
+  EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+
+  // Dequeue, request, and queue all buffers.
+  for (int i = 0; i < maxCapacity; i++) {
+    EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+    EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+    EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output));
+  }
+
+  EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 7fe9825..9fe161d 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -32,6 +32,7 @@
     "dvr_display_manager.cpp",
     "dvr_hardware_composer_client.cpp",
     "dvr_performance.cpp",
+    "dvr_pose.cpp",
     "dvr_surface.cpp",
     "dvr_vsync.cpp",
 ]
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 4d9b215..1a99234 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -44,7 +44,13 @@
 }
 
 void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) {
-  delete write_buffer;
+  if (write_buffer != nullptr) {
+    ALOGW_IF(
+        write_buffer->slot != -1,
+        "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
+        "buffer queue slot. This may indicate possible leaks.");
+    delete write_buffer;
+  }
 }
 
 int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer) {
@@ -107,7 +113,15 @@
     *read_buffer = new DvrReadBuffer;
 }
 
-void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) { delete read_buffer; }
+void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) {
+  if (read_buffer != nullptr) {
+    ALOGW_IF(
+        read_buffer->slot != -1,
+        "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
+        "buffer queue slot. This may indicate possible leaks.");
+    delete read_buffer;
+  }
+}
 
 int dvrReadBufferIsValid(DvrReadBuffer* read_buffer) {
   return read_buffer && read_buffer->read_buffer;
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 018abbb..035252d 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -14,6 +14,8 @@
 using android::dvr::BufferProducer;
 using android::dvr::ConsumerQueue;
 using android::dvr::ProducerQueue;
+using android::dvr::ProducerQueueConfigBuilder;
+using android::dvr::UsagePolicy;
 
 extern "C" {
 
@@ -61,7 +63,7 @@
 }
 
 int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
-                                 int* out_fence_fd) {
+                                 int* out_fence_fd, size_t* out_slot) {
   size_t slot;
   pdx::LocalHandle fence;
   std::shared_ptr<BufferProducer> buffer_producer;
@@ -139,6 +141,86 @@
 
   write_buffer->write_buffer = std::move(buffer_producer);
   *out_fence_fd = fence.Release();
+  if (out_slot) {
+    // TODO(b/65469368): Remove this null check once dvrWriteBufferQueueDequeue
+    // is deprecated.
+    *out_slot = slot;
+  }
+  return 0;
+}
+
+int DvrWriteBufferQueue::GainBuffer(int timeout,
+                                    DvrWriteBuffer** out_write_buffer,
+                                    DvrNativeBufferMetadata* out_meta,
+                                    int* out_fence_fd) {
+  DvrWriteBuffer write_buffer;
+  int fence_fd;
+  size_t slot;
+  const int ret = Dequeue(timeout, &write_buffer, &fence_fd, &slot);
+  if (ret < 0) {
+    ALOGE_IF(
+        ret != -ETIMEDOUT,
+        "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer, ret=%d",
+        ret);
+    return ret;
+  }
+
+  if (write_buffers_[slot] == nullptr) {
+    // Lazy initialization of a write_buffers_ slot. Note that a slot will only
+    // be dynamically allocated once during the entire cycle life of a queue.
+    write_buffers_[slot] = std::make_unique<DvrWriteBuffer>();
+    write_buffers_[slot]->slot = slot;
+  }
+
+  LOG_ALWAYS_FATAL_IF(
+      write_buffers_[slot]->write_buffer,
+      "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot);
+  write_buffers_[slot]->write_buffer = std::move(write_buffer.write_buffer);
+
+  *out_write_buffer = write_buffers_[slot].release();
+  *out_fence_fd = fence_fd;
+
+  return 0;
+}
+
+int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
+                                    const DvrNativeBufferMetadata* meta,
+                                    int ready_fence_fd) {
+  LOG_FATAL_IF(
+      (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
+      "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
+
+  // Some basic sanity checks before we put the buffer back into a slot.
+  size_t slot = static_cast<size_t>(write_buffer->slot);
+  if (write_buffers_[slot] != nullptr) {
+    ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
+    return -EINVAL;
+  }
+  if (write_buffer->write_buffer == nullptr) {
+    ALOGE("DvrWriteBufferQueue::PostBuffer: Invalid write buffer.");
+    return -EINVAL;
+  }
+  if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) {
+    ALOGE(
+        "DvrWriteBufferQueue::PostBuffer: Buffer to be released does not "
+        "belong to this buffer queue.");
+    return -EINVAL;
+  }
+
+  pdx::LocalHandle fence(ready_fence_fd);
+  // TODO(b/65455724): All BufferHub operations should be async.
+  const int ret = write_buffer->write_buffer->Post(fence, meta, sizeof(*meta));
+  if (ret < 0) {
+    ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d",
+          ret);
+    return ret;
+  }
+
+  // Put the DvrWriteBuffer pointer back into its slot for reuse.
+  write_buffers_[slot].reset(write_buffer);
+  // It's import to reset the write buffer client now. It should stay invalid
+  // until next GainBuffer on the same slot.
+  write_buffers_[slot]->write_buffer = nullptr;
   return 0;
 }
 
@@ -156,6 +238,36 @@
   return 0;
 }
 
+int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
+                              uint32_t layer_count, uint64_t usage,
+                              size_t capacity, size_t metadata_size,
+                              DvrWriteBufferQueue** out_write_queue) {
+  if (!out_write_queue)
+    return -EINVAL;
+
+  auto config_builder = ProducerQueueConfigBuilder()
+                            .SetDefaultWidth(width)
+                            .SetDefaultHeight(height)
+                            .SetDefaultFormat(format)
+                            .SetMetadataSize(metadata_size);
+  std::unique_ptr<ProducerQueue> producer_queue =
+      ProducerQueue::Create(config_builder.Build(), UsagePolicy{});
+  if (!producer_queue) {
+    ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue.");
+    return -ENOMEM;
+  }
+
+  auto status = producer_queue->AllocateBuffers(width, height, layer_count,
+                                                format, usage, capacity);
+  if (!status.ok()) {
+    ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers.");
+    return -ENOMEM;
+  }
+
+  *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue));
+  return 0;
+}
+
 void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
   delete write_queue;
 }
@@ -176,6 +288,14 @@
 
 int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
                                           ANativeWindow** out_window) {
+  ALOGW(
+      "dvrWriteBufferQueueGetExternalSurface: This API has been deprecated and "
+      "renamed to dvrWriteBufferQueueGetANativeWindow.");
+  return dvrWriteBufferQueueGetANativeWindow(write_queue, out_window);
+}
+
+int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
+                                        ANativeWindow** out_window) {
   if (!write_queue || !out_window)
     return -EINVAL;
 
@@ -196,7 +316,29 @@
   if (!write_queue || !write_buffer || !out_fence_fd)
     return -EINVAL;
 
-  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
+  // TODO(b/65469368): Deprecate this API once new GainBuffer API is in use.
+  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd, nullptr);
+}
+
+int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
+                                  DvrWriteBuffer** out_write_buffer,
+                                  DvrNativeBufferMetadata* out_meta,
+                                  int* out_fence_fd) {
+  if (!write_queue || !out_write_buffer || !out_meta || !out_fence_fd)
+    return -EINVAL;
+
+  return write_queue->GainBuffer(timeout, out_write_buffer, out_meta,
+                                 out_fence_fd);
+}
+
+int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
+                                  DvrWriteBuffer* write_buffer,
+                                  const DvrNativeBufferMetadata* meta,
+                                  int ready_fence_fd) {
+  if (!write_queue || !write_buffer || !write_buffer->write_buffer || !meta)
+    return -EINVAL;
+
+  return write_queue->PostBuffer(write_buffer, meta, ready_fence_fd);
 }
 
 int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
@@ -228,8 +370,8 @@
 }
 
 int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
-                                int* out_fence_fd, void* out_meta,
-                                size_t meta_size_bytes) {
+                                int* out_fence_fd, size_t* out_slot,
+                                void* out_meta, size_t meta_size_bytes) {
   if (meta_size_bytes != consumer_queue_->metadata_size()) {
     ALOGE(
         "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
@@ -251,6 +393,95 @@
 
   read_buffer->read_buffer = buffer_status.take();
   *out_fence_fd = acquire_fence.Release();
+
+  if (out_slot) {
+    // TODO(b/65469368): Remove this null check once dvrReadBufferQueueDequeue
+    // is deprecated.
+    *out_slot = slot;
+  }
+  return 0;
+}
+
+int DvrReadBufferQueue::AcquireBuffer(int timeout,
+                                      DvrReadBuffer** out_read_buffer,
+                                      DvrNativeBufferMetadata* out_meta,
+                                      int* out_fence_fd) {
+  DvrReadBuffer read_buffer;
+  int fence_fd;
+  size_t slot;
+  const int ret = Dequeue(timeout, &read_buffer, &fence_fd, &slot, out_meta,
+                          sizeof(*out_meta));
+  if (ret < 0) {
+    ALOGE_IF(
+        ret != -ETIMEDOUT,
+        "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer, error=%d",
+        ret);
+    return ret;
+  }
+
+  if (read_buffers_[slot] == nullptr) {
+    // Lazy initialization of a read_buffers_ slot. Note that a slot will only
+    // be dynamically allocated once during the entire cycle life of a queue.
+    read_buffers_[slot] = std::make_unique<DvrReadBuffer>();
+    read_buffers_[slot]->slot = slot;
+  }
+
+  LOG_FATAL_IF(
+      read_buffers_[slot]->read_buffer,
+      "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot);
+  read_buffers_[slot]->read_buffer = std::move(read_buffer.read_buffer);
+
+  *out_read_buffer = read_buffers_[slot].release();
+  *out_fence_fd = fence_fd;
+
+  return 0;
+}
+
+int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
+                                      const DvrNativeBufferMetadata* meta,
+                                      int release_fence_fd) {
+  LOG_FATAL_IF(
+      (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
+      "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
+
+  // Some basic sanity checks before we put the buffer back into a slot.
+  size_t slot = static_cast<size_t>(read_buffer->slot);
+  if (read_buffers_[slot] != nullptr) {
+    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
+    return -EINVAL;
+  }
+  if (read_buffer->read_buffer == nullptr) {
+    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Invalid read buffer.");
+    return -EINVAL;
+  }
+  if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
+    ALOGE(
+        "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not "
+        "belong to this buffer queue.");
+    return -EINVAL;
+  }
+
+  pdx::LocalHandle fence(release_fence_fd);
+  int ret = 0;
+  if (fence) {
+    ret = read_buffer->read_buffer->Release(fence);
+  } else {
+    // TODO(b/65458354): Send metadata back to producer once shared memory based
+    // metadata is implemented.
+    // TODO(b/65455724): All BufferHub operations should be async.
+    ret = read_buffer->read_buffer->ReleaseAsync();
+  }
+  if (ret < 0) {
+    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d",
+          ret);
+    return ret;
+  }
+
+  // Put the DvrReadBuffer pointer back into its slot for reuse.
+  read_buffers_[slot].reset(read_buffer);
+  // It's import to reset the read buffer client now. It should stay invalid
+  // until next AcquireBuffer on the same slot.
+  read_buffers_[slot]->read_buffer = nullptr;
   return 0;
 }
 
@@ -271,9 +502,11 @@
   } else {
     consumer_queue_->SetBufferRemovedCallback(
         [callback, context](const std::shared_ptr<BufferHubBuffer>& buffer) {
-          DvrReadBuffer read_buffer{
-              std::static_pointer_cast<BufferConsumer>(buffer)};
-          callback(&read_buffer, context);
+          // When buffer is removed from the queue, the slot is already invalid.
+          auto read_buffer = std::make_unique<DvrReadBuffer>();
+          read_buffer->read_buffer =
+              std::static_pointer_cast<BufferConsumer>(buffer);
+          callback(read_buffer.release(), context);
         });
   }
 }
@@ -326,8 +559,30 @@
   if (meta_size_bytes != 0 && !out_meta)
     return -EINVAL;
 
-  return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
-                             meta_size_bytes);
+  // TODO(b/65469368): Deprecate this API once new AcquireBuffer API is in use.
+  return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, nullptr,
+                             out_meta, meta_size_bytes);
+}
+
+int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
+                                    DvrReadBuffer** out_read_buffer,
+                                    DvrNativeBufferMetadata* out_meta,
+                                    int* out_fence_fd) {
+  if (!read_queue || !out_read_buffer || !out_meta || !out_fence_fd)
+    return -EINVAL;
+
+  return read_queue->AcquireBuffer(timeout, out_read_buffer, out_meta,
+                                   out_fence_fd);
+}
+
+int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
+                                    DvrReadBuffer* read_buffer,
+                                    const DvrNativeBufferMetadata* meta,
+                                    int release_fence_fd) {
+  if (!read_queue || !read_buffer || !read_buffer->read_buffer || !meta)
+    return -EINVAL;
+
+  return read_queue->ReleaseBuffer(read_buffer, meta, release_fence_fd);
 }
 
 int dvrReadBufferQueueSetBufferAvailableCallback(
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h
index ffbe7a5..f9c0bfd 100644
--- a/libs/vr/libdvr/dvr_buffer_queue_internal.h
+++ b/libs/vr/libdvr/dvr_buffer_queue_internal.h
@@ -5,11 +5,23 @@
 #include <private/dvr/buffer_hub_queue_client.h>
 #include <sys/cdefs.h>
 
+#include <array>
 #include <memory>
 
+#include "dvr_internal.h"
+
 struct ANativeWindow;
 
+typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+typedef struct DvrWriteBuffer DvrWriteBuffer;
+typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
+typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
+                                                        void* context);
+
 struct DvrWriteBufferQueue {
+  using BufferHubQueue = android::dvr::BufferHubQueue;
   using ProducerQueue = android::dvr::ProducerQueue;
 
   // Create a concrete object for DvrWriteBufferQueue.
@@ -30,19 +42,28 @@
 
   int GetNativeWindow(ANativeWindow** out_window);
   int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
-  int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
+  int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd,
+              size_t* out_slot);
+  int GainBuffer(int timeout, DvrWriteBuffer** out_write_buffer,
+                 DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
+  int PostBuffer(DvrWriteBuffer* write_buffer,
+                 const DvrNativeBufferMetadata* meta, int ready_fence_fd);
   int ResizeBuffer(uint32_t width, uint32_t height);
 
  private:
   std::shared_ptr<ProducerQueue> producer_queue_;
+  std::array<std::unique_ptr<DvrWriteBuffer>, BufferHubQueue::kMaxQueueCapacity>
+      write_buffers_;
 
   uint32_t width_;
   uint32_t height_;
   uint32_t format_;
+
   android::sp<android::Surface> native_window_;
 };
 
 struct DvrReadBufferQueue {
+  using BufferHubQueue = android::dvr::BufferHubQueue;
   using ConsumerQueue = android::dvr::ConsumerQueue;
 
   explicit DvrReadBufferQueue(
@@ -54,7 +75,11 @@
 
   int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
   int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd,
-              void* out_meta, size_t meta_size_bytes);
+              size_t* out_slot, void* out_meta, size_t meta_size_bytes);
+  int AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer,
+                    DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
+  int ReleaseBuffer(DvrReadBuffer* read_buffer,
+                    const DvrNativeBufferMetadata* meta, int release_fence_fd);
   void SetBufferAvailableCallback(
       DvrReadBufferQueueBufferAvailableCallback callback, void* context);
   void SetBufferRemovedCallback(
@@ -63,6 +88,8 @@
 
  private:
   std::shared_ptr<ConsumerQueue> consumer_queue_;
+  std::array<std::unique_ptr<DvrReadBuffer>, BufferHubQueue::kMaxQueueCapacity>
+      read_buffers_;
 };
 
 #endif  // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
index 28b6c28..de8bb96 100644
--- a/libs/vr/libdvr/dvr_internal.h
+++ b/libs/vr/libdvr/dvr_internal.h
@@ -34,10 +34,20 @@
 extern "C" {
 
 struct DvrWriteBuffer {
+  // The slot nubmer of the buffer, a valid slot number must be in the range of
+  // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
+  // DvrWriteBuffer acquired from a DvrWriteBufferQueue.
+  int32_t slot = -1;
+
   std::shared_ptr<android::dvr::BufferProducer> write_buffer;
 };
 
 struct DvrReadBuffer {
+  // The slot nubmer of the buffer, a valid slot number must be in the range of
+  // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
+  // DvrReadBuffer acquired from a DvrReadBufferQueue.
+  int32_t slot = -1;
+
   std::shared_ptr<android::dvr::BufferConsumer> read_buffer;
 };
 
diff --git a/libs/vr/libdvr/dvr_pose.cpp b/libs/vr/libdvr/dvr_pose.cpp
new file mode 100644
index 0000000..c379ef5
--- /dev/null
+++ b/libs/vr/libdvr/dvr_pose.cpp
@@ -0,0 +1,29 @@
+#include "include/dvr/dvr_pose.h"
+
+#include <memory>
+
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/pose_client_internal.h>
+
+#include "dvr_buffer_queue_internal.h"
+
+using android::dvr::ConsumerQueue;
+
+int dvrPoseClientGetDataReader(DvrPoseClient* client, uint64_t data_type,
+                               DvrReadBufferQueue** queue_out) {
+  if (!client || !queue_out)
+    return -EINVAL;
+
+  ConsumerQueue* consumer_queue;
+  int status = android::dvr::dvrPoseClientGetDataReaderHandle(client,
+                                                              data_type,
+                                                              &consumer_queue);
+  if (status != 0) {
+    ALOGE("dvrPoseClientGetDataReader: Failed to get queue: %d", status);
+    return status;
+  }
+
+  std::shared_ptr<ConsumerQueue> consumer_queue_ptr{consumer_queue};
+  *queue_out = new DvrReadBufferQueue(consumer_queue_ptr);
+  return 0;
+}
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index d0dbd8d..8f45ce7 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -23,6 +23,7 @@
 typedef struct DvrDisplayManager DvrDisplayManager;
 typedef struct DvrSurfaceState DvrSurfaceState;
 typedef struct DvrPoseClient DvrPoseClient;
+typedef struct DvrPoseDataCaptureRequest DvrPoseDataCaptureRequest;
 typedef struct DvrVSyncClient DvrVSyncClient;
 typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
 
@@ -33,6 +34,7 @@
 
 typedef struct DvrReadBufferQueue DvrReadBufferQueue;
 typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
 
 typedef struct DvrSurface DvrSurface;
 typedef uint64_t DvrSurfaceAttributeType;
@@ -159,18 +161,33 @@
     DvrBuffer* buffer);
 
 // dvr_buffer_queue.h
+typedef int (*DvrWriteBufferQueueCreatePtr)(uint32_t width, uint32_t height,
+                                            uint32_t format,
+                                            uint32_t layer_count,
+                                            uint64_t usage, size_t capacity,
+                                            size_t metadata_size,
+                                            DvrWriteBufferQueue** queue_out);
 typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue);
 typedef ssize_t (*DvrWriteBufferQueueGetCapacityPtr)(
     DvrWriteBufferQueue* write_queue);
 typedef int (*DvrWriteBufferQueueGetIdPtr)(DvrWriteBufferQueue* write_queue);
 typedef int (*DvrWriteBufferQueueGetExternalSurfacePtr)(
     DvrWriteBufferQueue* write_queue, ANativeWindow** out_window);
+typedef int (*DvrWriteBufferQueueGetANativeWindowPtr)(
+    DvrWriteBufferQueue* write_queue, ANativeWindow** out_window);
 typedef int (*DvrWriteBufferQueueCreateReadQueuePtr)(
     DvrWriteBufferQueue* write_queue, DvrReadBufferQueue** out_read_queue);
 typedef int (*DvrWriteBufferQueueDequeuePtr)(DvrWriteBufferQueue* write_queue,
                                              int timeout,
                                              DvrWriteBuffer* out_buffer,
                                              int* out_fence_fd);
+typedef int (*DvrWriteBufferQueueGainBufferPtr)(
+    DvrWriteBufferQueue* write_queue, int timeout,
+    DvrWriteBuffer** out_write_buffer, DvrNativeBufferMetadata* out_meta,
+    int* out_fence_fd);
+typedef int (*DvrWriteBufferQueuePostBufferPtr)(
+    DvrWriteBufferQueue* write_queue, DvrWriteBuffer* write_buffer,
+    const DvrNativeBufferMetadata* meta, int ready_fence_fd);
 typedef int (*DvrWriteBufferQueueResizeBufferPtr)(
     DvrWriteBufferQueue* write_queue, uint32_t width, uint32_t height);
 typedef void (*DvrReadBufferQueueDestroyPtr)(DvrReadBufferQueue* read_queue);
@@ -185,6 +202,13 @@
                                             DvrReadBuffer* out_buffer,
                                             int* out_fence_fd, void* out_meta,
                                             size_t meta_size_bytes);
+typedef int (*DvrReadBufferQueueAcquireBufferPtr)(
+    DvrReadBufferQueue* read_queue, int timeout,
+    DvrReadBuffer** out_read_buffer, DvrNativeBufferMetadata* out_meta,
+    int* out_fence_fd);
+typedef int (*DvrReadBufferQueueReleaseBufferPtr)(
+    DvrReadBufferQueue* read_queue, DvrReadBuffer* read_buffer,
+    const DvrNativeBufferMetadata* meta, int release_fence_fd);
 typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
 typedef int (*DvrReadBufferQueueSetBufferAvailableCallbackPtr)(
     DvrReadBufferQueue* read_queue,
@@ -238,6 +262,15 @@
                                              DvrPoseAsync* out_pose);
 typedef int (*DvrPoseClientSensorsEnablePtr)(DvrPoseClient* client,
                                              bool enabled);
+typedef int (*DvrPoseClientDataCapturePtr)(DvrPoseClient* client,
+    const DvrPoseDataCaptureRequest* request);
+typedef int (*DvrPoseClientDataReaderDestroyPtr)(DvrPoseClient* client,
+                                                 uint64_t data_type);
+
+// dvr_pose.h
+typedef int (*DvrPoseClientGetDataReaderPtr)(DvrPoseClient* client,
+                                             uint64_t data_type,
+                                             DvrReadBufferQueue** read_queue);
 
 // services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
 
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 72e0f67..cce8c7e 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -65,7 +65,7 @@
 DVR_V1_API_ENTRY(WriteBufferQueueDestroy);
 DVR_V1_API_ENTRY(WriteBufferQueueGetCapacity);
 DVR_V1_API_ENTRY(WriteBufferQueueGetId);
-DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface);
+DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface);  // deprecated
 DVR_V1_API_ENTRY(WriteBufferQueueCreateReadQueue);
 DVR_V1_API_ENTRY(WriteBufferQueueDequeue);
 DVR_V1_API_ENTRY(WriteBufferQueueResizeBuffer);
@@ -160,3 +160,20 @@
 
 // Read buffer queue
 DVR_V1_API_ENTRY(ReadBufferQueueGetEventFd);
+
+// Create write buffer queue locally
+DVR_V1_API_ENTRY(WriteBufferQueueCreate);
+
+// Gets an ANativeWindow from DvrWriteBufferQueue.
+DVR_V1_API_ENTRY(WriteBufferQueueGetANativeWindow);
+
+// Dvr{Read,Write}BufferQueue API for asynchronous IPC.
+DVR_V1_API_ENTRY(WriteBufferQueueGainBuffer);
+DVR_V1_API_ENTRY(WriteBufferQueuePostBuffer);
+DVR_V1_API_ENTRY(ReadBufferQueueAcquireBuffer);
+DVR_V1_API_ENTRY(ReadBufferQueueReleaseBuffer);
+
+// Pose client
+DVR_V1_API_ENTRY(PoseClientGetDataReader);
+DVR_V1_API_ENTRY(PoseClientDataCapture);
+DVR_V1_API_ENTRY(PoseClientDataReaderDestroy);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index e2127f8..bf695c7 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -12,6 +12,36 @@
 typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
 typedef struct DvrReadBufferQueue DvrReadBufferQueue;
 
+// Creates a write buffer queue to be used locally.
+//
+// Note that this API is mostly for testing purpose. For now there is no
+// mechanism to send a DvrWriteBufferQueue cross process. Use
+// dvrSurfaceCreateWriteBufferQueue if cross-process buffer transport is
+// intended.
+//
+// @param width The width of the buffers that this queue will produce.
+// @param height The height of buffers that this queue will produce.
+// @param format The format of the buffers that this queue will produce. This
+//     must be one of the AHARDWAREBUFFER_FORMAT_XXX enums.
+// @param layer_count The number of layers of the buffers that this queue will
+//     produce.
+// @param usage The usage of the buffers that this queue will produce. This
+//     must a combination of the AHARDWAREBUFFER_USAGE_XXX flags.
+// @param capacity The number of buffer that this queue will allocate. Note that
+//     all buffers will be allocated on create. Currently, the number of buffers
+//     is the queue cannot be changed after creation though DVR API. However,
+//     ANativeWindow can choose to reallocate, attach, or detach buffers from
+//     a DvrWriteBufferQueue through Android platform logic.
+// @param metadata_size The size of metadata in bytes.
+// @param out_write_queue The pointer of a DvrWriteBufferQueue will be filled
+//      here if the method call succeeds. The metadata size must match
+//      the metadata size in dvrWriteBufferPost/dvrReadBufferAcquire.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
+                              uint32_t layer_count, uint64_t usage,
+                              size_t capacity, size_t metadata_size,
+                              DvrWriteBufferQueue** out_write_queue);
+
 // Destroy a write buffer queue.
 //
 // @param write_queue The DvrWriteBufferQueue of interest.
@@ -43,6 +73,10 @@
 //     the method call succeeds.
 // @return Zero on success; or -EINVAL if this DvrWriteBufferQueue does not
 //     support being used as an android Surface.
+int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
+                                        ANativeWindow** out_window);
+
+// @deprecated Please use dvrWriteBufferQueueGetANativeWindow instead.
 int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
                                           ANativeWindow** out_window);
 
@@ -55,21 +89,44 @@
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
                                        DvrReadBufferQueue** out_read_queue);
 
-// Dequeue a buffer to write into.
+// @deprecated Please use dvrWriteBufferQueueGainBuffer instead.
+int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
+                               DvrWriteBuffer* out_buffer, int* out_fence_fd);
+
+// Gains a buffer to write into.
 //
-// @param write_queue The DvrWriteBufferQueue of interest.
+// @param write_queue The DvrWriteBufferQueue to gain buffer from.
 // @param timeout Specifies the number of milliseconds that the method will
 //     block. Specifying a timeout of -1 causes it to block indefinitely,
 //     while specifying a timeout equal to zero cause it to return immediately,
 //     even if no buffers are available.
 // @param out_buffer A targeting DvrWriteBuffer object to hold the output of the
-//     dequeue operation. Must be created by |dvrWriteBufferCreateEmpty|.
+//     dequeue operation.
+// @param out_meta A DvrNativeBufferMetadata object populated by the
+//     corresponding dvrReadBufferQueueReleaseBuffer API.
 // @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
 //     signals the release of underlying buffer. The producer should wait until
 //     this fence clears before writing data into it.
 // @return Zero on success, or negative error code.
-int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
-                               DvrWriteBuffer* out_buffer, int* out_fence_fd);
+int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
+                                  DvrWriteBuffer** out_write_buffer,
+                                  DvrNativeBufferMetadata* out_meta,
+                                  int* out_fence_fd);
+
+// Posts a buffer and signals its readiness to be read from.
+//
+// @param write_queue The DvrWriteBufferQueue to post buffer into.
+// @param write_buffer The buffer to be posted.
+// @param meta The buffer metadata describing the buffer.
+// @param ready_fence_fd  A sync fence fd defined in NDK's sync.h API, which
+//     signals the readdiness of underlying buffer. When a valid fence gets
+//     passed in, the consumer will wait the fence to be ready before it starts
+//     to ready from the buffer.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
+                                  DvrWriteBuffer* write_buffer,
+                                  const DvrNativeBufferMetadata* meta,
+                                  int ready_fence_fd);
 
 // Overrides buffer dimension with new width and height.
 //
@@ -119,28 +176,45 @@
 int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
                                       DvrReadBufferQueue** out_read_queue);
 
-// Dequeue a buffer to read from.
+// @deprecated Please use dvrReadBufferQueueAcquireBuffer instead.
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+                              DvrReadBuffer* out_buffer, int* out_fence_fd,
+                              void* out_meta, size_t meta_size_bytes);
+
+// Dequeues a buffer to read from.
 //
-// @param read_queue The DvrReadBufferQueue of interest.
+// @param read_queue The DvrReadBufferQueue to acquire buffer from.
 // @param timeout Specifies the number of milliseconds that the method will
 //     block. Specifying a timeout of -1 causes it to block indefinitely,
 //     while specifying a timeout equal to zero cause it to return immediately,
 //     even if no buffers are available.
 // @param out_buffer A targeting DvrReadBuffer object to hold the output of the
 //     dequeue operation. Must be created by |dvrReadBufferCreateEmpty|.
+// @param out_meta A DvrNativeBufferMetadata object populated by the
+//     corresponding dvrWriteBufferQueuePostBuffer API.
 // @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
 //     signals the release of underlying buffer. The consumer should wait until
 //     this fence clears before reading data from it.
-// @param out_meta The memory area where a metadata object will be filled.
-//     Can be nullptr iff |meta_size_bytes| is zero (i.e., there is no
-//     metadata).
-// @param meta_size_bytes Size of the metadata object caller expects. If it
-//     doesn't match the size of actually metadata transported by the buffer
-//     queue, the method returns -EINVAL.
 // @return Zero on success, or negative error code.
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
-                              DvrReadBuffer* out_buffer, int* out_fence_fd,
-                              void* out_meta, size_t meta_size_bytes);
+int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
+                                    DvrReadBuffer** out_read_buffer,
+                                    DvrNativeBufferMetadata* out_meta,
+                                    int* out_fence_fd);
+
+// Releases a buffer and signals its readiness to be written into.
+//
+// @param read_queue The DvrReadBufferQueue to release buffer into.
+// @param read_buffer The buffer to be released.
+// @param meta The buffer metadata describing the buffer.
+// @param release_fence_fd A sync fence fd defined in NDK's sync.h API, which
+//     signals the readdiness of underlying buffer. When a valid fence gets
+//     passed in, the producer will wait the fence to be ready before it starts
+//     to write into the buffer again.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
+                                    DvrReadBuffer* read_buffer,
+                                    const DvrNativeBufferMetadata* meta,
+                                    int release_fence_fd);
 
 // Callback function which will be called when a buffer is avaiable.
 //
diff --git a/libs/vr/libdvr/include/dvr/dvr_pose.h b/libs/vr/libdvr/include/dvr/dvr_pose.h
index b3df028..8752751 100644
--- a/libs/vr/libdvr/include/dvr/dvr_pose.h
+++ b/libs/vr/libdvr/include/dvr/dvr_pose.h
@@ -15,6 +15,9 @@
 #endif
 #endif
 
+typedef struct DvrPoseClient DvrPoseClient;
+typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+
 // Represents an estimated pose, accessed asynchronously through a shared ring
 // buffer. No assumptions should be made about the data in padding space.
 // The size of this struct is 128 bytes.
@@ -95,6 +98,57 @@
   uint8_t padding[12];
 } DvrPose;
 
+// Represents a data type that can be streamed from pose service.
+enum {
+  DVR_POSE_RAW_DATA_STEREO_IMAGE = (1ULL << 0),
+  DVR_POSE_RAW_DATA_POINT_CLOUD = (1ULL << 1),
+  DVR_POSE_RAW_DATA_FEATURES = (1ULL << 2),
+
+  // Always last.
+  DVR_POSE_RAW_DATA_COUNT = (1ULL << 3),
+};
+
+// A request to retrieve data from the pose service. Expects that a buffer
+// queue has been initialized through dvrPoseClientGetDataReader().
+typedef struct DvrPoseDataCaptureRequest {
+  // The type of data to capture. Refer to enum DVR_POSE_RAW_DATA_* for types.
+  uint64_t data_type;
+  // The sample interval. This can be used to skip samples. For example, a
+  // value of 5 will capture every fifth frame and discard the 4 frames in
+  // between. Set to 1 to capture all frames.
+  uint32_t sample_interval;
+  // The length of time to capture samples in milliseconds. Set to 0 to capture
+  // indefinitely.
+  uint32_t capture_time_ms;
+  // Reserved fields.
+  uint32_t reserved0;
+  uint32_t reserved1;
+  uint32_t reserved2;
+  uint32_t reserved3;
+  uint32_t reserved4;
+} DvrPoseDataCaptureRequest;
+
+// Gets a read buffer queue for the data type |data_type|. Each call returns a
+// different read buffer queue connected to the same write buffer queue. A
+// separate write buffer queue exists for each |data_type|.
+//
+// PoseService supports a single consumer per write buffer queue. The consumer
+// is expected to hold a single DvrReadBufferQueue at a time. Callers should
+// cache these instead of requesting new ones when possible. If the consumer
+// disconnects from the queue, it can regain a read buffer queue for the same
+// producer by calling this function.
+//
+// For data_type DVR_POSE_RAW_DATA_STEREO_IMAGE, each buffer consists of two
+// images formatted as a AHARDWAREBUFFER_FORMAT_BLOB, where height is 1 and
+// width is the total size of both images. The size of an individual image can
+// be found in the metadata struct DvrNativeBufferMetadata, where width is
+// |crop_right| and height is |crop_bottom|/2. Each image is contiguous in
+// memory with stride equal to width.
+int dvrPoseClientGetDataReader(DvrPoseClient* client, uint64_t data_type,
+                               DvrReadBufferQueue** queue_out);
+
+// TODO(b/65067592): Move pose api's from pose_client.h to here.
+
 __END_DECLS
 
 #endif  // ANDROID_DVR_PUBLIC_POSE_H_
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index ab2ee75..a9302a7 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -47,6 +47,7 @@
     cflags: [
         "-DLOG_TAG=\"dvr_api-test\"",
         "-DTRACE=0",
+        "-Wno-missing-field-initializers",
         "-O0",
         "-g",
     ],
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 16da1d9..f1c5e48 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -1,28 +1,32 @@
+#include <android/log.h>
+#include <android/native_window.h>
+#include <android-base/unique_fd.h>
 #include <dvr/dvr_api.h>
 #include <dvr/dvr_buffer_queue.h>
-#include <gui/Surface.h>
-#include <private/dvr/buffer_hub_queue_client.h>
 
-#include <base/logging.h>
 #include <gtest/gtest.h>
 
-#include "../dvr_internal.h"
-#include "../dvr_buffer_queue_internal.h"
+#include <array>
+#include <unordered_map>
 
-namespace android {
-namespace dvr {
+#ifndef ALOGD
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+  ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0)
+#endif
 
 namespace {
 
 static constexpr uint32_t kBufferWidth = 100;
 static constexpr uint32_t kBufferHeight = 1;
 static constexpr uint32_t kLayerCount = 1;
-static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB;
+static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
 static constexpr size_t kQueueCapacity = 3;
 
-typedef uint64_t TestMeta;
-
 class DvrBufferQueueTest : public ::testing::Test {
  public:
   static void BufferAvailableCallback(void* context) {
@@ -36,14 +40,6 @@
   }
 
  protected:
-  void SetUp() override {
-    config_builder_ = ProducerQueueConfigBuilder()
-                          .SetDefaultWidth(kBufferWidth)
-                          .SetDefaultHeight(kBufferHeight)
-                          .SetDefaultFormat(kBufferFormat)
-                          .SetMetadata<TestMeta>();
-  }
-
   void TearDown() override {
     if (write_queue_ != nullptr) {
       dvrWriteBufferQueueDestroy(write_queue_);
@@ -51,19 +47,6 @@
     }
   }
 
-  void CreateWriteBufferQueue() {
-    write_queue_ = new DvrWriteBufferQueue(
-        ProducerQueue::Create(config_builder_.Build(), UsagePolicy{}));
-    ASSERT_NE(nullptr, write_queue_);
-  }
-
-  void AllocateBuffers(size_t buffer_count) {
-    auto status = write_queue_->producer_queue()->AllocateBuffers(
-        kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
-        buffer_count);
-    ASSERT_TRUE(status.ok());
-  }
-
   void HandleBufferAvailable() {
     buffer_available_count_ += 1;
     ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_);
@@ -75,22 +58,26 @@
              buffer_removed_count_);
   }
 
-  ProducerQueueConfigBuilder config_builder_;
   DvrWriteBufferQueue* write_queue_{nullptr};
   int buffer_available_count_{0};
   int buffer_removed_count_{0};
 };
 
-TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(0, ret);
 
   dvrWriteBufferQueueDestroy(write_queue_);
   write_queue_ = nullptr;
 }
 
-TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
-  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(0, ret);
 
   size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
 
@@ -98,11 +85,14 @@
   ASSERT_EQ(kQueueCapacity, capacity);
 }
 
-TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue = nullptr;
-  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
@@ -110,12 +100,15 @@
   dvrReadBufferQueueDestroy(read_queue);
 }
 
-TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue1 = nullptr;
   DvrReadBufferQueue* read_queue2 = nullptr;
-  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue1);
@@ -129,98 +122,86 @@
   dvrReadBufferQueueDestroy(read_queue2);
 }
 
-TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
-  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3));
+TEST_F(DvrBufferQueueTest, GainBuffer) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(ret, 0);
 
-  DvrReadBuffer* read_buffer = nullptr;
-  DvrWriteBuffer* write_buffer = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  EXPECT_FALSE(dvrWriteBufferIsValid(wb));
 
-  EXPECT_FALSE(dvrReadBufferIsValid(read_buffer));
-  EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
-
-  dvrReadBufferCreateEmpty(&read_buffer);
-  ASSERT_NE(nullptr, read_buffer);
-
-  dvrWriteBufferCreateEmpty(&write_buffer);
-  ASSERT_NE(nullptr, write_buffer);
-
-  EXPECT_FALSE(dvrReadBufferIsValid(read_buffer));
-  EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
-
-  DvrReadBufferQueue* read_queue = nullptr;
-
-  ASSERT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
-  const int kTimeoutMs = 0;
+  DvrNativeBufferMetadata meta = {0};
   int fence_fd = -1;
-  ASSERT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, kTimeoutMs,
-                                          write_buffer, &fence_fd));
-  EXPECT_EQ(-1, fence_fd);
-  EXPECT_TRUE(dvrWriteBufferIsValid(write_buffer));
-
-  ASSERT_EQ(0, dvrWriteBufferClear(write_buffer));
-  EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
+  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
+                                      &fence_fd);
+  ASSERT_EQ(ret, 0);
+  EXPECT_EQ(fence_fd, -1);
+  EXPECT_NE(wb, nullptr);
+  EXPECT_TRUE(dvrWriteBufferIsValid(wb));
 }
 
-TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
-  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(ret, 0);
 
-  static constexpr int kTimeout = 0;
   DvrReadBufferQueue* read_queue = nullptr;
   DvrReadBuffer* rb = nullptr;
   DvrWriteBuffer* wb = nullptr;
+  DvrNativeBufferMetadata meta1 = {0};
+  DvrNativeBufferMetadata meta2 = {0};
   int fence_fd = -1;
 
-  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
-  ASSERT_EQ(0, ret);
-  ASSERT_NE(nullptr, read_queue);
+  ASSERT_EQ(ret, 0);
+  ASSERT_NE(read_queue, nullptr);
 
   dvrReadBufferQueueSetBufferAvailableCallback(read_queue,
                                                &BufferAvailableCallback, this);
 
-  dvrWriteBufferCreateEmpty(&wb);
-  ASSERT_NE(nullptr, wb);
-
-  dvrReadBufferCreateEmpty(&rb);
-  ASSERT_NE(nullptr, rb);
-
   // Gain buffer for writing.
-  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb, &fence_fd);
-  ASSERT_EQ(0, ret);
+  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta1,
+                                      &fence_fd);
+  ASSERT_EQ(ret, 0);
+  ASSERT_NE(wb, nullptr);
   ASSERT_TRUE(dvrWriteBufferIsValid(wb));
   ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
            wb, fence_fd);
-  pdx::LocalHandle release_fence(fence_fd);
+  android::base::unique_fd release_fence(fence_fd);
 
   // Post buffer to the read_queue.
-  TestMeta seq = 42U;
-  ret = dvrWriteBufferPost(wb, /* fence */ -1, &seq, sizeof(seq));
-  ASSERT_EQ(0, ret);
-  dvrWriteBufferDestroy(wb);
+  meta1.timestamp = 42;
+  ret = dvrWriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+  ASSERT_EQ(ret, 0);
+  ASSERT_FALSE(dvrWriteBufferIsValid(wb));
   wb = nullptr;
 
   // Acquire buffer for reading.
-  TestMeta acquired_seq = 0U;
-  ret = dvrReadBufferQueueDequeue(read_queue, kTimeout, rb, &fence_fd,
-                                  &acquired_seq, sizeof(acquired_seq));
-  ASSERT_EQ(0, ret);
+  ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/0, &rb, &meta2,
+                                        &fence_fd);
+  ASSERT_EQ(ret, 0);
+  ASSERT_NE(rb, nullptr);
 
   // Dequeue is successfully, BufferAvailableCallback should be fired once.
-  ASSERT_EQ(1, buffer_available_count_);
+  ASSERT_EQ(buffer_available_count_, 1);
   ASSERT_TRUE(dvrReadBufferIsValid(rb));
-  ASSERT_EQ(seq, acquired_seq);
+
+  // Metadata should be passed along from producer to consumer properly.
+  ASSERT_EQ(meta1.timestamp, meta2.timestamp);
+
   ALOGD_IF(TRACE,
            "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
            fence_fd);
-  pdx::LocalHandle acquire_fence(fence_fd);
+  android::base::unique_fd acquire_fence(fence_fd);
 
   // Release buffer to the write_queue.
-  ret = dvrReadBufferRelease(rb, -1);
-  ASSERT_EQ(0, ret);
-  dvrReadBufferDestroy(rb);
+  ret = dvrReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+                                        /*release_fence_fd=*/-1);
+  ASSERT_EQ(ret, 0);
+  ASSERT_FALSE(dvrReadBufferIsValid(rb));
   rb = nullptr;
 
   // TODO(b/34387835) Currently buffer allocation has to happen after all queues
@@ -233,45 +214,38 @@
   dvrReadBufferQueueDestroy(read_queue);
 }
 
-TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+TEST_F(DvrBufferQueueTest, GetANativeWindow) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, write_queue_);
 
   ANativeWindow* window = nullptr;
-
-  // The |write_queue_| doesn't have proper metadata (must be
-  // DvrNativeBufferMetadata) configured during creation.
-  int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
-  ASSERT_EQ(-EINVAL, ret);
-  ASSERT_EQ(nullptr, window);
-
-  // A write queue with DvrNativeBufferMetadata should work fine.
-  auto config = ProducerQueueConfigBuilder()
-                    .SetMetadata<DvrNativeBufferMetadata>()
-                    .Build();
-  std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
-      write_queue(
-          new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})),
-          dvrWriteBufferQueueDestroy);
-  ASSERT_NE(nullptr, write_queue.get());
-
-  ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
+  ret = dvrWriteBufferQueueGetANativeWindow(write_queue_, &window);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, window);
 
-  sp<Surface> surface = static_cast<Surface*>(window);
-  ASSERT_TRUE(Surface::isValid(surface));
+  uint32_t width = ANativeWindow_getWidth(window);
+  uint32_t height = ANativeWindow_getHeight(window);
+  uint32_t format = ANativeWindow_getFormat(window);
+  ASSERT_EQ(kBufferWidth, width);
+  ASSERT_EQ(kBufferHeight, height);
+  ASSERT_EQ(kBufferFormat, format);
 }
 
 // Create buffer queue of three buffers and dequeue three buffers out of it.
 // Before each dequeue operation, we resize the buffer queue and expect the
 // queue always return buffer with desired dimension.
-TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
-  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+TEST_F(DvrBufferQueueTest, ResizeBuffer) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(0, ret);
 
-  static constexpr int kTimeout = 0;
   int fence_fd = -1;
 
+  DvrNativeBufferMetadata meta = {0};
   DvrReadBufferQueue* read_queue = nullptr;
   DvrWriteBuffer* wb1 = nullptr;
   DvrWriteBuffer* wb2 = nullptr;
@@ -281,7 +255,7 @@
   AHardwareBuffer* ahb3 = nullptr;
   AHardwareBuffer_Desc buffer_desc;
 
-  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
@@ -289,13 +263,6 @@
   dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback,
                                              this);
 
-  dvrWriteBufferCreateEmpty(&wb1);
-  ASSERT_NE(nullptr, wb1);
-  dvrWriteBufferCreateEmpty(&wb2);
-  ASSERT_NE(nullptr, wb2);
-  dvrWriteBufferCreateEmpty(&wb3);
-  ASSERT_NE(nullptr, wb3);
-
   // Handle all pending events on the read queue.
   ret = dvrReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
@@ -310,11 +277,12 @@
   ASSERT_EQ(0, ret);
 
   // Gain first buffer for writing. All buffers will be resized.
-  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb1, &fence_fd);
+  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, &meta,
+                                      &fence_fd);
   ASSERT_EQ(0, ret);
   ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
-  pdx::LocalHandle release_fence1(fence_fd);
+  android::base::unique_fd release_fence1(fence_fd);
 
   // Check the buffer dimension.
   ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
@@ -336,12 +304,13 @@
   ASSERT_EQ(0, ret);
 
   // The next buffer we dequeued should have new width.
-  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb2, &fence_fd);
+  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, &meta,
+                                      &fence_fd);
   ASSERT_EQ(0, ret);
   ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
            fence_fd);
-  pdx::LocalHandle release_fence2(fence_fd);
+  android::base::unique_fd release_fence2(fence_fd);
 
   // Check the buffer dimension, should be new width
   ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
@@ -362,12 +331,13 @@
   ASSERT_EQ(0, ret);
 
   // The next buffer we dequeued should have new width.
-  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb3, &fence_fd);
+  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, &meta,
+                                      &fence_fd);
   ASSERT_EQ(0, ret);
   ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
            fence_fd);
-  pdx::LocalHandle release_fence3(fence_fd);
+  android::base::unique_fd release_fence3(fence_fd);
 
   // Check the buffer dimension, should be new width
   ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
@@ -385,77 +355,14 @@
   dvrReadBufferQueueDestroy(read_queue);
 }
 
-TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) {
-  // Overrides default queue parameters: Empty metadata.
-  config_builder_.SetMetadata<void>();
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
-  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
-
-  DvrReadBuffer* rb = nullptr;
-  DvrWriteBuffer* wb = nullptr;
-  dvrReadBufferCreateEmpty(&rb);
-  dvrWriteBufferCreateEmpty(&wb);
+TEST_F(DvrBufferQueueTest, ReadQueueEventFd) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue = nullptr;
-  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
-  const int kTimeoutMs = 0;
-  int fence_fd = -1;
-  EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
-
-  EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, nullptr, 0));
-  EXPECT_EQ(0, dvrWriteBufferClear(wb));
-  dvrWriteBufferDestroy(wb);
-  wb = nullptr;
-
-  // When acquire buffer, it's legit to pass nullptr as out_meta iff metadata
-  // size is Zero.
-  EXPECT_EQ(0, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
-                                         nullptr, 0));
-  EXPECT_TRUE(dvrReadBufferIsValid(rb));
-}
-
-TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
-  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
-
-  DvrReadBuffer* rb = nullptr;
-  DvrWriteBuffer* wb = nullptr;
-  dvrReadBufferCreateEmpty(&rb);
-  dvrWriteBufferCreateEmpty(&wb);
-
-  DvrReadBufferQueue* read_queue = nullptr;
-  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
-  const int kTimeoutMs = 0;
-  int fence_fd = -1;
-  EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
-
-  TestMeta seq = 42U;
-  EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, &seq, sizeof(seq)));
-  EXPECT_EQ(0, dvrWriteBufferClear(wb));
-  dvrWriteBufferDestroy(wb);
-  wb = nullptr;
-
-  // Dequeue with wrong metadata will cause EINVAL.
-  int8_t wrong_metadata;
-  EXPECT_EQ(-EINVAL,
-            dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
-                                      &wrong_metadata, sizeof(wrong_metadata)));
-  EXPECT_FALSE(dvrReadBufferIsValid(rb));
-
-  // Dequeue with empty metadata will cause EINVAL.
-  EXPECT_EQ(-EINVAL, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb,
-                                               &fence_fd, nullptr, 0));
-  EXPECT_FALSE(dvrReadBufferIsValid(rb));
-}
-
-TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) {
-  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
-  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
-
-  DvrReadBufferQueue* read_queue = nullptr;
-  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
@@ -464,7 +371,154 @@
   ASSERT_GT(event_fd, 0);
 }
 
-}  // namespace
+// Verifies a Dvr{Read,Write}BufferQueue contains the same set of
+// Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
+// the corresponding AHardwareBuffer handle stays the same.
+TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) {
+  int ret = dvrWriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(0, ret);
 
-}  // namespace dvr
-}  // namespace android
+  int fence_fd = -1;
+  DvrReadBufferQueue* read_queue = nullptr;
+  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+  // Read buffers.
+  std::array<DvrReadBuffer*, kQueueCapacity> rbs;
+  // Write buffers.
+  std::array<DvrWriteBuffer*, kQueueCapacity> wbs;
+  // Buffer metadata.
+  std::array<DvrNativeBufferMetadata, kQueueCapacity> metas;
+  // Hardware buffers for Read buffers.
+  std::unordered_map<int, AHardwareBuffer*> rhbs;
+  // Hardware buffers for Write buffers.
+  std::unordered_map<int, AHardwareBuffer*> whbs;
+
+  constexpr int kNumTests = 100;
+
+  // This test runs the following operations many many times. Thus we prefer to
+  // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output.
+  std::function<void(size_t i)> Gain = [&](size_t i) {
+    int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0,
+                                            &wbs[i], &metas[i], &fence_fd);
+    ASSERT_EQ(ret, 0);
+    ASSERT_LT(fence_fd, 0);  // expect invalid fence.
+    ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
+    int buffer_id = dvrWriteBufferGetId(wbs[i]);
+    ASSERT_GT(buffer_id, 0);
+
+    AHardwareBuffer* hb = nullptr;
+    ASSERT_EQ(0, dvrWriteBufferGetAHardwareBuffer(wbs[i], &hb));
+
+    auto whb_it = whbs.find(buffer_id);
+    if (whb_it == whbs.end()) {
+      // If this is a new buffer id, check that total number of unique
+      // hardware buffers won't exceed queue capacity.
+      ASSERT_LT(whbs.size(), kQueueCapacity);
+      whbs.emplace(buffer_id, hb);
+    } else {
+      // If this is a buffer id we have seen before, check that the
+      // buffer_id maps to the same AHardwareBuffer handle.
+      ASSERT_EQ(hb, whb_it->second);
+    }
+  };
+
+  std::function<void(size_t i)> Post = [&](size_t i) {
+    ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
+
+    metas[i].timestamp++;
+    int ret = dvrWriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
+                                            /*fence=*/-1);
+    ASSERT_EQ(ret, 0);
+  };
+
+  std::function<void(size_t i)> Acquire = [&](size_t i) {
+    int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/0,
+                                              &rbs[i], &metas[i], &fence_fd);
+    ASSERT_EQ(ret, 0);
+    ASSERT_LT(fence_fd, 0);  // expect invalid fence.
+    ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+
+    int buffer_id = dvrReadBufferGetId(rbs[i]);
+    ASSERT_GT(buffer_id, 0);
+
+    AHardwareBuffer* hb = nullptr;
+    ASSERT_EQ(0, dvrReadBufferGetAHardwareBuffer(rbs[i], &hb));
+
+    auto rhb_it = rhbs.find(buffer_id);
+    if (rhb_it == rhbs.end()) {
+      // If this is a new buffer id, check that total number of unique hardware
+      // buffers won't exceed queue capacity.
+      ASSERT_LT(rhbs.size(), kQueueCapacity);
+      rhbs.emplace(buffer_id, hb);
+    } else {
+      // If this is a buffer id we have seen before, check that the buffer_id
+      // maps to the same AHardwareBuffer handle.
+      ASSERT_EQ(hb, rhb_it->second);
+    }
+  };
+
+  std::function<void(size_t i)> Release = [&](size_t i) {
+    ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+
+    int ret = dvrReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
+                                              /*release_fence_fd=*/-1);
+    ASSERT_EQ(ret, 0);
+  };
+
+  // Scenario one:
+  for (int i = 0; i < kNumTests; i++) {
+    // Gain all write buffers.
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Gain(i));
+    }
+    // Post all write buffers.
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Post(i));
+    }
+    // Acquire all read buffers.
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Acquire(i));
+    }
+    // Release all read buffers.
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Release(i));
+    }
+  }
+
+  // Scenario two:
+  for (int i = 0; i < kNumTests; i++) {
+    // Gain and post all write buffers.
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Gain(i));
+      ASSERT_NO_FATAL_FAILURE(Post(i));
+    }
+    // Acquire and release all read buffers.
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Acquire(i));
+      ASSERT_NO_FATAL_FAILURE(Release(i));
+    }
+  }
+
+  // Scenario three:
+  for (int i = 0; i < kNumTests; i++) {
+    // Gain all write buffers then post them in reversed order.
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Gain(i));
+    }
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Post(kQueueCapacity - 1 - i));
+    }
+
+    // Acquire all write buffers then release them in reversed order.
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Acquire(i));
+    }
+    for (size_t i = 0; i < kQueueCapacity; i++) {
+      ASSERT_NO_FATAL_FAILURE(Release(kQueueCapacity - 1 - i));
+    }
+  }
+}
+
+}  // namespace
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index f55e994..8fce140 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -5,12 +5,15 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-DLOG_TAG=\"libpdx\"",
+        "-DTRACE=0",
     ],
     export_include_dirs: ["private"],
     local_include_dirs: ["private"],
     srcs: [
         "client.cpp",
         "service.cpp",
+        "service_dispatcher.cpp",
         "status.cpp",
     ],
 }
diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp
index bfa2d87..a01c4d6 100644
--- a/libs/vr/libpdx/client.cpp
+++ b/libs/vr/libpdx/client.cpp
@@ -1,6 +1,5 @@
 #include "pdx/client.h"
 
-#define LOG_TAG "ServiceFramework"
 #include <log/log.h>
 
 #include <pdx/trace.h>
diff --git a/libs/vr/libpdx/mock_tests.cpp b/libs/vr/libpdx/mock_tests.cpp
index 76fd154..4143837 100644
--- a/libs/vr/libpdx/mock_tests.cpp
+++ b/libs/vr/libpdx/mock_tests.cpp
@@ -3,7 +3,6 @@
 #include <pdx/mock_client_channel_factory.h>
 #include <pdx/mock_message_reader.h>
 #include <pdx/mock_message_writer.h>
-#include <pdx/mock_service_dispatcher.h>
 #include <pdx/mock_service_endpoint.h>
 
 TEST(MockTypes, Instantiation) {
@@ -15,6 +14,5 @@
   android::pdx::MockMessageReader message_reader;
   android::pdx::MockOutputResourceMapper output_resource_mapper;
   android::pdx::MockMessageWriter message_writer;
-  android::pdx::MockServiceDispatcher service_dispatcher;
   android::pdx::MockEndpoint endpoint;
 }
diff --git a/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h b/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h
deleted file mode 100644
index 9b51d30..0000000
--- a/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
-
-#include <gmock/gmock.h>
-#include <pdx/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-
-class MockServiceDispatcher : public ServiceDispatcher {
- public:
-  MOCK_METHOD1(AddService, int(const std::shared_ptr<Service>& service));
-  MOCK_METHOD1(RemoveService, int(const std::shared_ptr<Service>& service));
-  MOCK_METHOD0(ReceiveAndDispatch, int());
-  MOCK_METHOD1(ReceiveAndDispatch, int(int timeout));
-  MOCK_METHOD0(EnterDispatchLoop, int());
-  MOCK_METHOD1(SetCanceled, void(bool cancel));
-  MOCK_CONST_METHOD0(IsCanceled, bool());
-};
-
-}  // namespace pdx
-}  // namespace android
-
-#endif  // ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
index e741d4a..7f829e7 100644
--- a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
+++ b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
@@ -66,6 +66,7 @@
   MOCK_METHOD0(AllocateMessageState, void*());
   MOCK_METHOD1(FreeMessageState, void(void* state));
   MOCK_METHOD0(Cancel, Status<void>());
+  MOCK_CONST_METHOD0(epoll_fd, int());
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/service_dispatcher.h b/libs/vr/libpdx/private/pdx/service_dispatcher.h
index c5e342a..bd27000 100644
--- a/libs/vr/libpdx/private/pdx/service_dispatcher.h
+++ b/libs/vr/libpdx/private/pdx/service_dispatcher.h
@@ -2,6 +2,11 @@
 #define ANDROID_PDX_SERVICE_DISPATCHER_H_
 
 #include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <pdx/file_handle.h>
 
 namespace android {
 namespace pdx {
@@ -15,7 +20,10 @@
  */
 class ServiceDispatcher {
  public:
-  virtual ~ServiceDispatcher() = default;
+  // Get a new instance of ServiceDispatcher, or return nullptr if init failed.
+  static std::unique_ptr<ServiceDispatcher> Create();
+
+  ~ServiceDispatcher();
 
   /*
    * Adds a service to the list of services handled by this dispatcher. This
@@ -24,7 +32,7 @@
    *
    * Returns 0 on success; -EEXIST if the service was already added.
    */
-  virtual int AddService(const std::shared_ptr<Service>& service) = 0;
+  int AddService(const std::shared_ptr<Service>& service);
 
   /*
    * Removes a service from this dispatcher. This will fail if any threads are
@@ -33,7 +41,7 @@
    * Returns 0 on success; -ENOENT if the service was not previously added;
    * -EBUSY if there are threads in the dispatcher.
    */
-  virtual int RemoveService(const std::shared_ptr<Service>& service) = 0;
+  int RemoveService(const std::shared_ptr<Service>& service);
 
   /*
    * Receive and dispatch one set of messages. Multiple threads may enter this
@@ -42,14 +50,14 @@
    * cycle, requiring an external loop. This is useful when other work needs
    * to be done in the service dispatch loop.
    */
-  virtual int ReceiveAndDispatch() = 0;
+  int ReceiveAndDispatch();
 
   /*
    * Same as above with timeout in milliseconds. A negative value means
    * infinite timeout, while a value of 0 means return immediately if no
    * messages are available to receive.
    */
-  virtual int ReceiveAndDispatch(int timeout) = 0;
+  int ReceiveAndDispatch(int timeout);
 
   /*
    * Receive and dispatch messages until canceled. When more than one thread
@@ -58,19 +66,39 @@
    * hands Message instances (via move assignment) over to a queue of threads
    * (or perhaps one of several) to handle.
    */
-  virtual int EnterDispatchLoop() = 0;
+  int EnterDispatchLoop();
 
   /*
    * Sets the canceled state of the dispatcher. When canceled is true, any
    * threads blocked waiting for messages will return. This method waits until
    * all dispatch threads have exited the dispatcher.
    */
-  virtual void SetCanceled(bool cancel) = 0;
+  void SetCanceled(bool cancel);
 
   /*
    * Gets the canceled state of the dispatcher.
    */
-  virtual bool IsCanceled() const = 0;
+  bool IsCanceled() const;
+
+ private:
+  ServiceDispatcher();
+
+  // Internal thread accounting.
+  int ThreadEnter();
+  void ThreadExit();
+
+  std::mutex mutex_;
+  std::condition_variable condition_;
+  std::atomic<bool> canceled_{false};
+
+  std::vector<std::shared_ptr<Service>> services_;
+
+  int thread_count_ = 0;
+  LocalHandle event_fd_;
+  LocalHandle epoll_fd_;
+
+  ServiceDispatcher(const ServiceDispatcher&) = delete;
+  void operator=(const ServiceDispatcher&) = delete;
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/service_endpoint.h b/libs/vr/libpdx/private/pdx/service_endpoint.h
index 28bd6bc..d581894 100644
--- a/libs/vr/libpdx/private/pdx/service_endpoint.h
+++ b/libs/vr/libpdx/private/pdx/service_endpoint.h
@@ -136,6 +136,10 @@
   // Cancels the endpoint, unblocking any receiver threads waiting for a
   // message.
   virtual Status<void> Cancel() = 0;
+
+  // Returns an fd that can be used with epoll() to wait for incoming messages
+  // from this endpoint.
+  virtual int epoll_fd() const = 0;
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index fab4770..1d3b62a 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -1,4 +1,3 @@
-#define LOG_TAG "ServiceFramework"
 #include "pdx/service.h"
 
 #include <fcntl.h>
@@ -10,8 +9,6 @@
 
 #include <pdx/trace.h>
 
-#define TRACE 0
-
 namespace android {
 namespace pdx {
 
diff --git a/libs/vr/libpdx_uds/service_dispatcher.cpp b/libs/vr/libpdx/service_dispatcher.cpp
similarity index 83%
rename from libs/vr/libpdx_uds/service_dispatcher.cpp
rename to libs/vr/libpdx/service_dispatcher.cpp
index 2c52578..b112fa3 100644
--- a/libs/vr/libpdx_uds/service_dispatcher.cpp
+++ b/libs/vr/libpdx/service_dispatcher.cpp
@@ -1,26 +1,25 @@
-#include "uds/service_dispatcher.h"
+#include <pdx/service_dispatcher.h>
 
 #include <errno.h>
 #include <log/log.h>
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
 
-#include "pdx/service.h"
-#include "uds/service_endpoint.h"
+#include <pdx/service.h>
+#include <pdx/service_endpoint.h>
 
 static const int kMaxEventsPerLoop = 128;
 
 namespace android {
 namespace pdx {
-namespace uds {
 
-std::unique_ptr<pdx::ServiceDispatcher> ServiceDispatcher::Create() {
+std::unique_ptr<ServiceDispatcher> ServiceDispatcher::Create() {
   std::unique_ptr<ServiceDispatcher> dispatcher{new ServiceDispatcher()};
   if (!dispatcher->epoll_fd_ || !dispatcher->event_fd_) {
     dispatcher.reset();
   }
 
-  return std::move(dispatcher);
+  return dispatcher;
 }
 
 ServiceDispatcher::ServiceDispatcher() {
@@ -70,18 +69,14 @@
 }
 
 int ServiceDispatcher::AddService(const std::shared_ptr<Service>& service) {
-  if (service->endpoint()->GetIpcTag() != Endpoint::kIpcTag)
-    return -EINVAL;
-
   std::lock_guard<std::mutex> autolock(mutex_);
 
-  auto* endpoint = static_cast<Endpoint*>(service->endpoint());
   epoll_event event;
   event.events = EPOLLIN;
   event.data.ptr = service.get();
 
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, endpoint->epoll_fd(), &event) <
-      0) {
+  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, service->endpoint()->epoll_fd(),
+                &event) < 0) {
     ALOGE("Failed to add service to dispatcher because: %s\n", strerror(errno));
     return -errno;
   }
@@ -91,9 +86,6 @@
 }
 
 int ServiceDispatcher::RemoveService(const std::shared_ptr<Service>& service) {
-  if (service->endpoint()->GetIpcTag() != Endpoint::kIpcTag)
-    return -EINVAL;
-
   std::lock_guard<std::mutex> autolock(mutex_);
 
   // It's dangerous to remove a service while other threads may be using it.
@@ -101,16 +93,15 @@
     return -EBUSY;
 
   epoll_event dummy;  // See BUGS in man 2 epoll_ctl.
-
-  auto* endpoint = static_cast<Endpoint*>(service->endpoint());
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, endpoint->epoll_fd(), &dummy) <
-      0) {
+  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, service->endpoint()->epoll_fd(),
+                &dummy) < 0) {
     ALOGE("Failed to remove service from dispatcher because: %s\n",
           strerror(errno));
     return -errno;
   }
 
-  services_.remove(service);
+  services_.erase(std::remove(services_.begin(), services_.end(), service),
+                  services_.end());
   return 0;
 }
 
@@ -139,7 +130,7 @@
       Service* service = static_cast<Service*>(events[i].data.ptr);
 
       ALOGI_IF(TRACE, "Dispatching message: fd=%d\n",
-               static_cast<Endpoint*>(service->endpoint())->epoll_fd());
+               service->endpoint()->epoll_fd());
       service->ReceiveAndDispatch();
     }
   }
@@ -171,7 +162,7 @@
         Service* service = static_cast<Service*>(events[i].data.ptr);
 
         ALOGI_IF(TRACE, "Dispatching message: fd=%d\n",
-                 static_cast<Endpoint*>(service->endpoint())->epoll_fd());
+                 service->endpoint()->epoll_fd());
         service->ReceiveAndDispatch();
       }
     }
@@ -197,6 +188,5 @@
 
 bool ServiceDispatcher::IsCanceled() const { return canceled_; }
 
-}  // namespace uds
 }  // namespace pdx
 }  // namespace android
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 8cfa86f..0f6511b 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -36,10 +36,10 @@
 }
 
 cc_binary {
-    name: "servicetool",
+    name: "pdx_tool",
     defaults: ["pdx_default_transport_compiler_defaults"],
     srcs: [
-        "servicetool.cpp",
+        "pdx_tool.cpp",
     ],
     shared_libs: [
         "liblog",
diff --git a/libs/vr/libpdx_default_transport/servicetool.cpp b/libs/vr/libpdx_default_transport/pdx_tool.cpp
similarity index 100%
rename from libs/vr/libpdx_default_transport/servicetool.cpp
rename to libs/vr/libpdx_default_transport/pdx_tool.cpp
diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h
deleted file mode 100644
index 158871c..0000000
--- a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
-
-#include <servicefs/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace default_transport {
-
-using ServiceDispatcher = ::android::pdx::servicefs::ServiceDispatcher;
-
-}  // namespace default_transport
-}  // namespace pdx
-}  // namespace android
-
-
-#endif  // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h
deleted file mode 100644
index 7cb7a80..0000000
--- a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
-
-#include <uds/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace default_transport {
-
-using ServiceDispatcher = ::android::pdx::uds::ServiceDispatcher;
-
-}  // namespace default_transport
-}  // namespace pdx
-}  // namespace android
-
-
-#endif  // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 82a5ea7..d0b7cab 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -16,7 +16,6 @@
         "client_channel_factory.cpp",
         "client_channel.cpp",
         "ipc_helper.cpp",
-        "service_dispatcher.cpp",
         "service_endpoint.cpp",
     ],
     static_libs: [
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp
index 9d91617..3f785fa 100644
--- a/libs/vr/libpdx_uds/client_channel.cpp
+++ b/libs/vr/libpdx_uds/client_channel.cpp
@@ -90,10 +90,12 @@
   size_t send_len = CountVectorSize(send_vector, send_count);
   InitRequest(&transaction_state->request, opcode, send_len, max_recv_len,
               false);
-  auto status = SendData(socket_fd, transaction_state->request);
-  if (status && send_len > 0)
-    status = SendDataVector(socket_fd, send_vector, send_count);
-  return status;
+  if (send_len == 0) {
+    send_vector = nullptr;
+    send_count = 0;
+  }
+  return SendData(socket_fd, transaction_state->request, send_vector,
+                  send_count);
 }
 
 Status<void> ReceiveResponse(const BorrowedHandle& socket_fd,
diff --git a/libs/vr/libpdx_uds/client_channel_tests.cpp b/libs/vr/libpdx_uds/client_channel_tests.cpp
index 7c3c68a..1560030 100644
--- a/libs/vr/libpdx_uds/client_channel_tests.cpp
+++ b/libs/vr/libpdx_uds/client_channel_tests.cpp
@@ -13,6 +13,7 @@
 #include <pdx/client.h>
 #include <pdx/rpc/remote_method.h>
 #include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
 
 #include <uds/client_channel_factory.h>
 #include <uds/service_endpoint.h>
@@ -81,7 +82,7 @@
     auto endpoint = Endpoint::CreateFromSocketFd(LocalHandle{});
     endpoint->RegisterNewChannelForTests(std::move(channel_socket));
     service_ = TestService::Create(std::move(endpoint));
-    dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+    dispatcher_ = ServiceDispatcher::Create();
     dispatcher_->AddService(service_);
     dispatch_thread_ = std::thread(
         std::bind(&ServiceDispatcher::EnterDispatchLoop, dispatcher_.get()));
diff --git a/libs/vr/libpdx_uds/ipc_helper.cpp b/libs/vr/libpdx_uds/ipc_helper.cpp
index d75ce86..f85b3bb 100644
--- a/libs/vr/libpdx_uds/ipc_helper.cpp
+++ b/libs/vr/libpdx_uds/ipc_helper.cpp
@@ -20,6 +20,9 @@
 
 namespace {
 
+constexpr size_t kMaxFdCount =
+    256;  // Total of 1KiB of data to transfer these FDs.
+
 // Default implementations of Send/Receive interfaces to use standard socket
 // send/sendmsg/recv/recvmsg functions.
 class SocketSender : public SendInterface {
@@ -175,20 +178,31 @@
 }
 
 Status<void> SendPayload::Send(const BorrowedHandle& socket_fd,
-                               const ucred* cred) {
+                               const ucred* cred, const iovec* data_vec,
+                               size_t vec_count) {
+  if (file_handles_.size() > kMaxFdCount) {
+    ALOGE(
+        "SendPayload::Send: Trying to send too many file descriptors (%zu), "
+        "max allowed = %zu",
+        file_handles_.size(), kMaxFdCount);
+    return ErrorStatus{EINVAL};
+  }
+
   SendInterface* sender = sender_ ? sender_ : &g_socket_sender;
   MessagePreamble preamble;
   preamble.magic = kMagicPreamble;
   preamble.data_size = buffer_.size();
   preamble.fd_count = file_handles_.size();
-  Status<void> ret = SendAll(sender, socket_fd, &preamble, sizeof(preamble));
-  if (!ret)
-    return ret;
 
   msghdr msg = {};
-  iovec recv_vect = {buffer_.data(), buffer_.size()};
-  msg.msg_iov = &recv_vect;
-  msg.msg_iovlen = 1;
+  msg.msg_iovlen = 2 + vec_count;
+  msg.msg_iov = static_cast<iovec*>(alloca(sizeof(iovec) * msg.msg_iovlen));
+  msg.msg_iov[0].iov_base = &preamble;
+  msg.msg_iov[0].iov_len = sizeof(preamble);
+  msg.msg_iov[1].iov_base = buffer_.data();
+  msg.msg_iov[1].iov_len = buffer_.size();
+  for (size_t i = 0; i < vec_count; i++)
+    msg.msg_iov[i + 2] = data_vec[i];
 
   if (cred || !file_handles_.empty()) {
     const size_t fd_bytes = file_handles_.size() * sizeof(int);
@@ -270,7 +284,15 @@
                                      ucred* cred) {
   RecvInterface* receiver = receiver_ ? receiver_ : &g_socket_receiver;
   MessagePreamble preamble;
-  Status<void> ret = RecvAll(receiver, socket_fd, &preamble, sizeof(preamble));
+  msghdr msg = {};
+  iovec recv_vect = {&preamble, sizeof(preamble)};
+  msg.msg_iov = &recv_vect;
+  msg.msg_iovlen = 1;
+  const size_t receive_fd_bytes = kMaxFdCount * sizeof(int);
+  msg.msg_controllen = CMSG_SPACE(sizeof(ucred)) + CMSG_SPACE(receive_fd_bytes);
+  msg.msg_control = alloca(msg.msg_controllen);
+
+  Status<void> ret = RecvMsgAll(receiver, socket_fd, &msg);
   if (!ret)
     return ret;
 
@@ -284,23 +306,6 @@
   file_handles_.clear();
   read_pos_ = 0;
 
-  msghdr msg = {};
-  iovec recv_vect = {buffer_.data(), buffer_.size()};
-  msg.msg_iov = &recv_vect;
-  msg.msg_iovlen = 1;
-
-  if (cred || preamble.fd_count) {
-    const size_t receive_fd_bytes = preamble.fd_count * sizeof(int);
-    msg.msg_controllen =
-        (cred ? CMSG_SPACE(sizeof(ucred)) : 0) +
-        (receive_fd_bytes == 0 ? 0 : CMSG_SPACE(receive_fd_bytes));
-    msg.msg_control = alloca(msg.msg_controllen);
-  }
-
-  ret = RecvMsgAll(receiver, socket_fd, &msg);
-  if (!ret)
-    return ret;
-
   bool cred_available = false;
   file_handles_.reserve(preamble.fd_count);
   cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
@@ -320,6 +325,10 @@
     cmsg = CMSG_NXTHDR(&msg, cmsg);
   }
 
+  ret = RecvAll(receiver, socket_fd, buffer_.data(), buffer_.size());
+  if (!ret)
+    return ret;
+
   if (cred && !cred_available) {
     ALOGE("ReceivePayload::Receive: Failed to obtain message credentials");
     ret.SetError(EIO);
diff --git a/libs/vr/libpdx_uds/private/uds/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
index bde16d3..664a0d1 100644
--- a/libs/vr/libpdx_uds/private/uds/ipc_helper.h
+++ b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
@@ -59,7 +59,8 @@
  public:
   SendPayload(SendInterface* sender = nullptr) : sender_{sender} {}
   Status<void> Send(const BorrowedHandle& socket_fd);
-  Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred);
+  Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred,
+                    const iovec* data_vec = nullptr, size_t vec_count = 0);
 
   // MessageWriter
   void* GetNextWriteBufferSection(size_t size) override;
@@ -156,18 +157,22 @@
 };
 
 template <typename T>
-inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data) {
+inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data,
+                             const iovec* data_vec = nullptr,
+                             size_t vec_count = 0) {
   SendPayload payload;
   rpc::Serialize(data, &payload);
-  return payload.Send(socket_fd);
+  return payload.Send(socket_fd, nullptr, data_vec, vec_count);
 }
 
 template <typename FileHandleType>
 inline Status<void> SendData(const BorrowedHandle& socket_fd,
-                             const RequestHeader<FileHandleType>& request) {
+                             const RequestHeader<FileHandleType>& request,
+                             const iovec* data_vec = nullptr,
+                             size_t vec_count = 0) {
   SendPayload payload;
   rpc::Serialize(request, &payload);
-  return payload.Send(socket_fd, &request.cred);
+  return payload.Send(socket_fd, &request.cred, data_vec, vec_count);
 }
 
 Status<void> SendData(const BorrowedHandle& socket_fd, const void* data,
diff --git a/libs/vr/libpdx_uds/private/uds/service_dispatcher.h b/libs/vr/libpdx_uds/private/uds/service_dispatcher.h
deleted file mode 100644
index 23af4f4..0000000
--- a/libs/vr/libpdx_uds/private/uds/service_dispatcher.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
-
-#include <list>
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-
-#include <pdx/file_handle.h>
-#include <pdx/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace uds {
-
-class ServiceDispatcher : public pdx::ServiceDispatcher {
- public:
-  // Get a new instance of ServiceDispatcher, or return nullptr if init failed.
-  static std::unique_ptr<pdx::ServiceDispatcher> Create();
-
-  ~ServiceDispatcher() override;
-  int AddService(const std::shared_ptr<Service>& service) override;
-  int RemoveService(const std::shared_ptr<Service>& service) override;
-  int ReceiveAndDispatch() override;
-  int ReceiveAndDispatch(int timeout) override;
-  int EnterDispatchLoop() override;
-  void SetCanceled(bool cancel) override;
-  bool IsCanceled() const override;
-
- private:
-  ServiceDispatcher();
-
-  // Internal thread accounting.
-  int ThreadEnter();
-  void ThreadExit();
-
-  std::mutex mutex_;
-  std::condition_variable condition_;
-  std::atomic<bool> canceled_{false};
-
-  std::list<std::shared_ptr<Service>> services_;
-
-  int thread_count_ = 0;
-  LocalHandle event_fd_;
-  LocalHandle epoll_fd_;
-
-  ServiceDispatcher(const ServiceDispatcher&) = delete;
-  void operator=(const ServiceDispatcher&) = delete;
-};
-
-}  // namespace uds
-}  // namespace pdx
-}  // namespace android
-
-#endif  // ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
index 368891c..a163812 100644
--- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h
+++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
@@ -12,7 +12,6 @@
 #include <pdx/service.h>
 #include <pdx/service_endpoint.h>
 #include <uds/channel_event_set.h>
-#include <uds/service_dispatcher.h>
 
 namespace android {
 namespace pdx {
@@ -105,7 +104,7 @@
   // socket file descriptor.
   Status<void> RegisterNewChannelForTests(LocalHandle channel_fd);
 
-  int epoll_fd() const { return epoll_fd_.Get(); }
+  int epoll_fd() const override { return epoll_fd_.Get(); }
 
  private:
   struct ChannelData {
diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp
index 3109753..3f25776 100644
--- a/libs/vr/libpdx_uds/remote_method_tests.cpp
+++ b/libs/vr/libpdx_uds/remote_method_tests.cpp
@@ -15,9 +15,9 @@
 #include <pdx/rpc/remote_method.h>
 #include <pdx/rpc/serializable.h>
 #include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
 #include <uds/client_channel.h>
 #include <uds/client_channel_factory.h>
-#include <uds/service_dispatcher.h>
 #include <uds/service_endpoint.h>
 
 using android::pdx::BorrowedHandle;
@@ -561,7 +561,7 @@
 
   void SetUp() override {
     // Create a dispatcher to handle messages to services.
-    dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+    dispatcher_ = android::pdx::ServiceDispatcher::Create();
     ASSERT_NE(nullptr, dispatcher_);
 
     // Start the message dispatch loop in a separate thread.
diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp
index 2943239..5943b0a 100644
--- a/libs/vr/libpdx_uds/service_framework_tests.cpp
+++ b/libs/vr/libpdx_uds/service_framework_tests.cpp
@@ -16,10 +16,10 @@
 #include <pdx/client.h>
 #include <pdx/file_handle.h>
 #include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
 #include <private/android_filesystem_config.h>
 #include <uds/client_channel.h>
 #include <uds/client_channel_factory.h>
-#include <uds/service_dispatcher.h>
 #include <uds/service_endpoint.h>
 
 using android::pdx::BorrowedChannelHandle;
@@ -425,7 +425,7 @@
 
   void SetUp() override {
     // Create a dispatcher to handle messages to services.
-    dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+    dispatcher_ = android::pdx::ServiceDispatcher::Create();
     ASSERT_NE(nullptr, dispatcher_);
 
     // Start the message dispatch loop in a separate thread.
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index fda9585..9614c6d 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -9,8 +9,8 @@
 namespace dvr {
 
 AcquiredBuffer::AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
-                               LocalHandle acquire_fence)
-    : buffer_(buffer), acquire_fence_(std::move(acquire_fence)) {}
+                               LocalHandle acquire_fence, std::size_t slot)
+    : buffer_(buffer), acquire_fence_(std::move(acquire_fence)), slot_(slot) {}
 
 AcquiredBuffer::AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
                                int* error) {
@@ -31,18 +31,20 @@
   }
 }
 
-AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other)
-    : buffer_(std::move(other.buffer_)),
-      acquire_fence_(std::move(other.acquire_fence_)) {}
+AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) {
+  *this = std::move(other);
+}
 
 AcquiredBuffer::~AcquiredBuffer() { Release(LocalHandle(kEmptyFence)); }
 
 AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) {
   if (this != &other) {
-    Release(LocalHandle(kEmptyFence));
+    Release();
 
-    buffer_ = std::move(other.buffer_);
-    acquire_fence_ = std::move(other.acquire_fence_);
+    using std::swap;
+    swap(buffer_, other.buffer_);
+    swap(acquire_fence_, other.acquire_fence_);
+    swap(slot_, other.slot_);
   }
   return *this;
 }
@@ -81,8 +83,6 @@
   ALOGD_IF(TRACE, "AcquiredBuffer::Release: buffer_id=%d release_fence=%d",
            buffer_ ? buffer_->id() : -1, release_fence.Get());
   if (buffer_) {
-    // Close the release fence since we can't transfer it with an async release.
-    release_fence.Close();
     const int ret = buffer_->ReleaseAsync();
     if (ret < 0) {
       ALOGE("AcquiredBuffer::Release: Failed to release buffer %d: %s",
@@ -92,9 +92,10 @@
     }
 
     buffer_ = nullptr;
-    acquire_fence_.Close();
   }
 
+  acquire_fence_.Close();
+  slot_ = 0;
   return 0;
 }
 
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index e0dc9f2..32e912a 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -21,7 +21,7 @@
   // this constructor; the constructor does not attempt to ACQUIRE the buffer
   // itself.
   AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
-                 pdx::LocalHandle acquire_fence);
+                 pdx::LocalHandle acquire_fence, std::size_t slot = 0);
 
   // Constructs an AcquiredBuffer from a BufferConsumer. The BufferConsumer MUST
   // be in the POSTED state prior to calling this constructor, as this
@@ -64,13 +64,18 @@
   // to the producer. On success, the BufferConsumer and acquire fence are set
   // to empty state; if release fails, the BufferConsumer and acquire fence are
   // left in place and a negative error code is returned.
-  int Release(pdx::LocalHandle release_fence);
+  int Release(pdx::LocalHandle release_fence = {});
+
+  // Returns the slot in the queue this buffer belongs to. Buffers that are not
+  // part of a queue return 0.
+  std::size_t slot() const { return slot_; }
 
  private:
   std::shared_ptr<BufferConsumer> buffer_;
   // Mutable so that the fence can be closed when it is determined to be
   // signaled during IsAvailable().
   mutable pdx::LocalHandle acquire_fence_;
+  std::size_t slot_{0};
 
   AcquiredBuffer(const AcquiredBuffer&) = delete;
   void operator=(const AcquiredBuffer&) = delete;
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 40396b9..ef8cca3 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -65,6 +65,7 @@
 }
 
 pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) {
+  ATRACE_NAME("DisplayManagerService::HandleMessage");
   auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());
 
   switch (message.GetOp()) {
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 733edc6..ac68a5e 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -40,10 +40,8 @@
 DisplayService::DisplayService(Hwc2::Composer* hidl,
                                RequestDisplayCallback request_display_callback)
     : BASE("DisplayService",
-           Endpoint::Create(display::DisplayProtocol::kClientPath)),
-      hardware_composer_(hidl, request_display_callback),
-      request_display_callback_(request_display_callback) {
-  hardware_composer_.Initialize();
+           Endpoint::Create(display::DisplayProtocol::kClientPath)) {
+  hardware_composer_.Initialize(hidl, request_display_callback);
 }
 
 bool DisplayService::IsInitialized() const {
@@ -126,6 +124,8 @@
 // surface-specific messages to the per-instance handlers.
 Status<void> DisplayService::HandleMessage(pdx::Message& message) {
   ALOGD_IF(TRACE, "DisplayService::HandleMessage: opcode=%d", message.GetOp());
+  ATRACE_NAME("DisplayService::HandleMessage");
+
   switch (message.GetOp()) {
     case DisplayProtocol::GetMetrics::Opcode:
       DispatchRemoteMethod<DisplayProtocol::GetMetrics>(
@@ -245,18 +245,16 @@
           surface_status.GetErrorMessage().c_str());
     return ErrorStatus(surface_status.error());
   }
+  auto surface = surface_status.take();
+  message.SetChannel(surface);
 
-  SurfaceType surface_type = surface_status.get()->surface_type();
-  display::SurfaceUpdateFlags update_flags =
-      surface_status.get()->update_flags();
-  display::SurfaceInfo surface_info{surface_status.get()->surface_id(),
-                                    surface_status.get()->visible(),
-                                    surface_status.get()->z_order()};
+  // Update the surface with the attributes supplied with the create call. For
+  // application surfaces this has the side effect of notifying the display
+  // manager of the new surface. For direct surfaces, this may trigger a mode
+  // change, depending on the value of the visible attribute.
+  surface->OnSetAttributes(message, attributes);
 
-  message.SetChannel(surface_status.take());
-
-  SurfaceUpdated(surface_type, update_flags);
-  return {surface_info};
+  return {{surface->surface_id(), surface->visible(), surface->z_order()}};
 }
 
 void DisplayService::SurfaceUpdated(SurfaceType surface_type,
@@ -353,17 +351,9 @@
 
 void DisplayService::UpdateActiveDisplaySurfaces() {
   auto visible_surfaces = GetVisibleDisplaySurfaces();
-
-  std::sort(visible_surfaces.begin(), visible_surfaces.end(),
-            [](const std::shared_ptr<DisplaySurface>& a,
-               const std::shared_ptr<DisplaySurface>& b) {
-              return a->z_order() < b->z_order();
-            });
-
   ALOGD_IF(TRACE,
            "DisplayService::UpdateActiveDisplaySurfaces: %zd visible surfaces",
            visible_surfaces.size());
-
   hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
 }
 
@@ -398,10 +388,6 @@
   return {0};
 }
 
-void DisplayService::OnHardwareComposerRefresh() {
-  hardware_composer_.OnHardwareComposerRefresh();
-}
-
 void DisplayService::SetDisplayConfigurationUpdateNotifier(
     DisplayConfigurationUpdateNotifier update_notifier) {
   update_notifier_ = update_notifier;
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 6efe264..55e33ab 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -72,8 +72,6 @@
   void GrantDisplayOwnership() { hardware_composer_.Enable(); }
   void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
 
-  void OnHardwareComposerRefresh();
-
  private:
   friend BASE;
   friend DisplaySurface;
@@ -119,7 +117,6 @@
   pdx::Status<void> HandleSurfaceMessage(pdx::Message& message);
 
   HardwareComposer hardware_composer_;
-  RequestDisplayCallback request_display_callback_;
   EpollEventDispatcher dispatcher_;
   DisplayConfigurationUpdateNotifier update_notifier_;
 
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 0d6a732..3d132c9 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -26,14 +26,12 @@
 
 DisplaySurface::DisplaySurface(DisplayService* service,
                                SurfaceType surface_type, int surface_id,
-                               int process_id, int user_id,
-                               const display::SurfaceAttributes& attributes)
+                               int process_id, int user_id)
     : service_(service),
       surface_type_(surface_type),
       surface_id_(surface_id),
       process_id_(process_id),
       user_id_(user_id),
-      attributes_(attributes),
       update_flags_(display::SurfaceUpdateFlags::NewSurface) {}
 
 DisplaySurface::~DisplaySurface() {
@@ -301,6 +299,9 @@
     }
 
     direct_queue_ = producer->CreateConsumerQueue();
+    if (direct_queue_->metadata_size() > 0) {
+      metadata_.reset(new uint8_t[direct_queue_->metadata_size()]);
+    }
     auto status = RegisterQueue(direct_queue_);
     if (!status) {
       ALOGE(
@@ -345,7 +346,12 @@
   while (true) {
     LocalHandle acquire_fence;
     size_t slot;
-    auto buffer_status = direct_queue_->Dequeue(0, &slot, &acquire_fence);
+    auto buffer_status = direct_queue_->Dequeue(
+        0, &slot, metadata_.get(),
+        direct_queue_->metadata_size(), &acquire_fence);
+    ALOGD_IF(TRACE,
+             "DirectDisplaySurface::DequeueBuffersLocked: Dequeue with metadata_size: %zu",
+             direct_queue_->metadata_size());
     if (!buffer_status) {
       ALOGD_IF(
           TRACE > 1 && buffer_status.error() == ETIMEDOUT,
@@ -376,7 +382,7 @@
     }
 
     acquired_buffers_.Append(
-        AcquiredBuffer(buffer_consumer, std::move(acquire_fence)));
+        AcquiredBuffer(buffer_consumer, std::move(acquire_fence), slot));
   }
 }
 
@@ -463,8 +469,8 @@
   if (direct) {
     const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
     if (trusted) {
-      return {std::shared_ptr<DisplaySurface>{new DirectDisplaySurface(
-          service, surface_id, process_id, user_id, attributes)}};
+      return {std::shared_ptr<DisplaySurface>{
+          new DirectDisplaySurface(service, surface_id, process_id, user_id)}};
     } else {
       ALOGE(
           "DisplaySurface::Create: Direct surfaces may only be created by "
@@ -474,7 +480,7 @@
     }
   } else {
     return {std::shared_ptr<DisplaySurface>{new ApplicationDisplaySurface(
-        service, surface_id, process_id, user_id, attributes)}};
+        service, surface_id, process_id, user_id)}};
   }
 }
 
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index 5cbee57..c8b1a07 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -53,8 +53,7 @@
 
  protected:
   DisplaySurface(DisplayService* service, SurfaceType surface_type,
-                 int surface_id, int process_id, int user_id,
-                 const display::SurfaceAttributes& attributes);
+                 int surface_id, int process_id, int user_id);
 
   // Utility to retrieve a shared pointer to this channel as the desired derived
   // type.
@@ -119,10 +118,9 @@
 class ApplicationDisplaySurface : public DisplaySurface {
  public:
   ApplicationDisplaySurface(DisplayService* service, int surface_id,
-                            int process_id, int user_id,
-                            const display::SurfaceAttributes& attributes)
+                            int process_id, int user_id)
       : DisplaySurface(service, SurfaceType::Application, surface_id,
-                       process_id, user_id, attributes) {}
+                       process_id, user_id) {}
 
   std::shared_ptr<ConsumerQueue> GetQueue(int32_t queue_id);
   std::vector<int32_t> GetQueueIds() const override;
@@ -140,11 +138,11 @@
 class DirectDisplaySurface : public DisplaySurface {
  public:
   DirectDisplaySurface(DisplayService* service, int surface_id, int process_id,
-                       int user_id,
-                       const display::SurfaceAttributes& attributes)
+                       int user_id)
       : DisplaySurface(service, SurfaceType::Direct, surface_id, process_id,
-                       user_id, attributes),
-        acquired_buffers_(kMaxPostedBuffers) {}
+                       user_id),
+        acquired_buffers_(kMaxPostedBuffers),
+        metadata_(nullptr) {}
   std::vector<int32_t> GetQueueIds() const override;
   bool IsBufferAvailable();
   bool IsBufferPosted();
@@ -179,6 +177,9 @@
   RingBuffer<AcquiredBuffer> acquired_buffers_;
 
   std::shared_ptr<ConsumerQueue> direct_queue_;
+
+  // Stores metadata when it dequeue buffers from consumer queue.
+  std::unique_ptr<uint8_t[]> metadata_;
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index def9b7d..fb69d5c 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -5,12 +5,14 @@
 #include <fcntl.h>
 #include <log/log.h>
 #include <poll.h>
+#include <stdint.h>
 #include <sync/sync.h>
 #include <sys/eventfd.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
 #include <sys/system_properties.h>
 #include <sys/timerfd.h>
+#include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 #include <utils/Trace.h>
@@ -28,7 +30,11 @@
 #include <private/dvr/clock_ns.h>
 #include <private/dvr/ion_buffer.h>
 
+using android::hardware::Return;
+using android::hardware::Void;
+using android::pdx::ErrorStatus;
 using android::pdx::LocalHandle;
+using android::pdx::Status;
 using android::pdx::rpc::EmptyVariant;
 using android::pdx::rpc::IfAnyOf;
 
@@ -42,12 +48,8 @@
 const char kBacklightBrightnessSysFile[] =
     "/sys/class/leds/lcd-backlight/brightness";
 
-const char kPrimaryDisplayVSyncEventFile[] =
-    "/sys/class/graphics/fb0/vsync_event";
-
-const char kPrimaryDisplayWaitPPEventFile[] = "/sys/class/graphics/fb0/wait_pp";
-
 const char kDvrPerformanceProperty[] = "sys.dvr.performance";
+const char kDvrStandaloneProperty[] = "ro.boot.vr";
 
 const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
 
@@ -84,24 +86,33 @@
   return true;
 }
 
+// Utility to generate scoped tracers with arguments.
+// TODO(eieio): Move/merge this into utils/Trace.h?
+class TraceArgs {
+ public:
+  template <typename... Args>
+  TraceArgs(const char* format, Args&&... args) {
+    std::array<char, 1024> buffer;
+    snprintf(buffer.data(), buffer.size(), format, std::forward<Args>(args)...);
+    atrace_begin(ATRACE_TAG, buffer.data());
+  }
+
+  ~TraceArgs() { atrace_end(ATRACE_TAG); }
+
+ private:
+  TraceArgs(const TraceArgs&) = delete;
+  void operator=(const TraceArgs&) = delete;
+};
+
+// Macro to define a scoped tracer with arguments. Uses PASTE(x, y) macro
+// defined in utils/Trace.h.
+#define TRACE_FORMAT(format, ...) \
+  TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ }
+
 }  // anonymous namespace
 
-// Layer static data.
-Hwc2::Composer* Layer::hwc2_hidl_;
-const HWCDisplayMetrics* Layer::display_metrics_;
-
-// HardwareComposer static data;
-constexpr size_t HardwareComposer::kMaxHardwareLayers;
-
 HardwareComposer::HardwareComposer()
-    : HardwareComposer(nullptr, RequestDisplayCallback()) {}
-
-HardwareComposer::HardwareComposer(
-    Hwc2::Composer* hwc2_hidl, RequestDisplayCallback request_display_callback)
-    : initialized_(false),
-      hwc2_hidl_(hwc2_hidl),
-      request_display_callback_(request_display_callback),
-      callbacks_(new ComposerCallback) {}
+    : initialized_(false), request_display_callback_(nullptr) {}
 
 HardwareComposer::~HardwareComposer(void) {
   UpdatePostThreadState(PostThreadState::Quit, true);
@@ -109,16 +120,21 @@
     post_thread_.join();
 }
 
-bool HardwareComposer::Initialize() {
+bool HardwareComposer::Initialize(
+    Hwc2::Composer* composer, RequestDisplayCallback request_display_callback) {
   if (initialized_) {
     ALOGE("HardwareComposer::Initialize: already initialized.");
     return false;
   }
 
+  is_standalone_device_ = property_get_bool(kDvrStandaloneProperty, false);
+
+  request_display_callback_ = request_display_callback;
+
   HWC::Error error = HWC::Error::None;
 
   Hwc2::Config config;
-  error = hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
+  error = composer->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
 
   if (error != HWC::Error::None) {
     ALOGE("HardwareComposer: Failed to get current display config : %d",
@@ -126,8 +142,8 @@
     return false;
   }
 
-  error =
-      GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_);
+  error = GetDisplayMetrics(composer, HWC_DISPLAY_PRIMARY, config,
+                            &native_display_metrics_);
 
   if (error != HWC::Error::None) {
     ALOGE(
@@ -149,8 +165,8 @@
   display_transform_ = HWC_TRANSFORM_NONE;
   display_metrics_ = native_display_metrics_;
 
-  // Pass hwc instance and metrics to setup globals for Layer.
-  Layer::InitializeGlobals(hwc2_hidl_, &native_display_metrics_);
+  // Setup the display metrics used by all Layer instances.
+  Layer::SetDisplayMetrics(native_display_metrics_);
 
   post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
   LOG_ALWAYS_FATAL_IF(
@@ -210,15 +226,19 @@
 }
 
 void HardwareComposer::OnPostThreadResumed() {
-  hwc2_hidl_->resetCommands();
+  // Phones create a new composer client on resume and destroy it on pause.
+  // Standalones only create the composer client once and then use SetPowerMode
+  // to control the screen on pause/resume.
+  if (!is_standalone_device_ || !composer_) {
+    composer_.reset(new Hwc2::Composer("default"));
+    composer_callback_ = new ComposerCallback;
+    composer_->registerCallback(composer_callback_);
+    Layer::SetComposer(composer_.get());
+  } else {
+    SetPowerMode(true);
+  }
 
-  // HIDL HWC seems to have an internal race condition. If we submit a frame too
-  // soon after turning on VSync we don't get any VSync signals. Give poor HWC
-  // implementations a chance to enable VSync before we continue.
-  EnableVsync(false);
-  std::this_thread::sleep_for(100ms);
   EnableVsync(true);
-  std::this_thread::sleep_for(100ms);
 
   // TODO(skiazyk): We need to do something about accessing this directly,
   // supposedly there is a backlight service on the way.
@@ -233,16 +253,19 @@
 
 void HardwareComposer::OnPostThreadPaused() {
   retire_fence_fds_.clear();
-  display_surfaces_.clear();
+  layers_.clear();
 
-  for (size_t i = 0; i < kMaxHardwareLayers; ++i) {
-    layers_[i].Reset();
+  if (composer_) {
+    EnableVsync(false);
   }
-  active_layer_count_ = 0;
 
-  EnableVsync(false);
-
-  hwc2_hidl_->resetCommands();
+  if (!is_standalone_device_) {
+    composer_callback_ = nullptr;
+    composer_.reset(nullptr);
+    Layer::SetComposer(nullptr);
+  } else {
+    SetPowerMode(false);
+  }
 
   // Trigger target-specific performance mode change.
   property_set(kDvrPerformanceProperty, "idle");
@@ -252,29 +275,35 @@
   uint32_t num_types;
   uint32_t num_requests;
   HWC::Error error =
-      hwc2_hidl_->validateDisplay(display, &num_types, &num_requests);
+      composer_->validateDisplay(display, &num_types, &num_requests);
 
   if (error == HWC2_ERROR_HAS_CHANGES) {
     // TODO(skiazyk): We might need to inspect the requested changes first, but
     // so far it seems like we shouldn't ever hit a bad state.
     // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_,
     //                                               display);
-    error = hwc2_hidl_->acceptDisplayChanges(display);
+    error = composer_->acceptDisplayChanges(display);
   }
 
   return error;
 }
 
-int32_t HardwareComposer::EnableVsync(bool enabled) {
-  return (int32_t)hwc2_hidl_->setVsyncEnabled(
+HWC::Error HardwareComposer::EnableVsync(bool enabled) {
+  return composer_->setVsyncEnabled(
       HWC_DISPLAY_PRIMARY,
       (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE
                                              : HWC2_VSYNC_DISABLE));
 }
 
+HWC::Error HardwareComposer::SetPowerMode(bool active) {
+  HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off;
+  return composer_->setPowerMode(
+      HWC_DISPLAY_PRIMARY, power_mode.cast<Hwc2::IComposerClient::PowerMode>());
+}
+
 HWC::Error HardwareComposer::Present(hwc2_display_t display) {
   int32_t present_fence;
-  HWC::Error error = hwc2_hidl_->presentDisplay(display, &present_fence);
+  HWC::Error error = composer_->presentDisplay(display, &present_fence);
 
   // According to the documentation, this fence is signaled at the time of
   // vsync/DMA for physical displays.
@@ -288,20 +317,21 @@
   return error;
 }
 
-HWC::Error HardwareComposer::GetDisplayAttribute(hwc2_display_t display,
+HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* composer,
+                                                 hwc2_display_t display,
                                                  hwc2_config_t config,
                                                  hwc2_attribute_t attribute,
                                                  int32_t* out_value) const {
-  return hwc2_hidl_->getDisplayAttribute(
+  return composer->getDisplayAttribute(
       display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value);
 }
 
 HWC::Error HardwareComposer::GetDisplayMetrics(
-    hwc2_display_t display, hwc2_config_t config,
+    Hwc2::Composer* composer, hwc2_display_t display, hwc2_config_t config,
     HWCDisplayMetrics* out_metrics) const {
   HWC::Error error;
 
-  error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_WIDTH,
+  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_WIDTH,
                               &out_metrics->width);
   if (error != HWC::Error::None) {
     ALOGE(
@@ -310,7 +340,7 @@
     return error;
   }
 
-  error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_HEIGHT,
+  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_HEIGHT,
                               &out_metrics->height);
   if (error != HWC::Error::None) {
     ALOGE(
@@ -319,7 +349,8 @@
     return error;
   }
 
-  error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_VSYNC_PERIOD,
+  error = GetDisplayAttribute(composer, display, config,
+                              HWC2_ATTRIBUTE_VSYNC_PERIOD,
                               &out_metrics->vsync_period_ns);
   if (error != HWC::Error::None) {
     ALOGE(
@@ -328,7 +359,7 @@
     return error;
   }
 
-  error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_X,
+  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_X,
                               &out_metrics->dpi.x);
   if (error != HWC::Error::None) {
     ALOGE(
@@ -337,7 +368,7 @@
     return error;
   }
 
-  error = GetDisplayAttribute(display, config, HWC2_ATTRIBUTE_DPI_Y,
+  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_Y,
                               &out_metrics->dpi.y);
   if (error != HWC::Error::None) {
     ALOGE(
@@ -360,10 +391,10 @@
          << std::endl;
 
   stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
-  stream << "Active layers:       " << active_layer_count_ << std::endl;
+  stream << "Active layers:       " << layers_.size() << std::endl;
   stream << std::endl;
 
-  for (size_t i = 0; i < active_layer_count_; i++) {
+  for (size_t i = 0; i < layers_.size(); i++) {
     stream << "Layer " << i << ":";
     stream << " type=" << layers_[i].GetCompositionType().to_string();
     stream << " surface_id=" << layers_[i].GetSurfaceId();
@@ -374,7 +405,7 @@
 
   if (post_thread_resumed_) {
     stream << "Hardware Composer Debug Info:" << std::endl;
-    stream << hwc2_hidl_->dumpDebugInfo();
+    stream << composer_->dumpDebugInfo();
   }
 
   return stream.str();
@@ -384,8 +415,8 @@
   ATRACE_NAME("HardwareComposer::PostLayers");
 
   // Setup the hardware composer layers with current buffers.
-  for (size_t i = 0; i < active_layer_count_; i++) {
-    layers_[i].Prepare();
+  for (auto& layer : layers_) {
+    layer.Prepare();
   }
 
   HWC::Error error = Validate(HWC_DISPLAY_PRIMARY);
@@ -407,20 +438,18 @@
     retire_fence_fds_.erase(retire_fence_fds_.begin());
   }
 
-  const bool is_frame_pending = IsFramePendingInDriver();
-  const bool is_fence_pending = retire_fence_fds_.size() >
+  const bool is_fence_pending = static_cast<int32_t>(retire_fence_fds_.size()) >
                                 post_thread_config_.allowed_pending_fence_count;
 
-  if (is_fence_pending || is_frame_pending) {
+  if (is_fence_pending) {
     ATRACE_INT("frame_skip_count", ++frame_skip_count_);
 
-    ALOGW_IF(is_frame_pending, "Warning: frame already queued, dropping frame");
     ALOGW_IF(is_fence_pending,
              "Warning: dropping a frame to catch up with HWC (pending = %zd)",
              retire_fence_fds_.size());
 
-    for (size_t i = 0; i < active_layer_count_; i++) {
-      layers_[i].Drop();
+    for (auto& layer : layers_) {
+      layer.Drop();
     }
     return;
   } else {
@@ -430,7 +459,7 @@
   }
 
 #if TRACE > 1
-  for (size_t i = 0; i < active_layer_count_; i++) {
+  for (size_t i = 0; i < layers_.size(); i++) {
     ALOGI("HardwareComposer::PostLayers: layer=%zu buffer_id=%d composition=%s",
           i, layers_[i].GetBufferId(),
           layers_[i].GetCompositionType().to_string().c_str());
@@ -446,18 +475,18 @@
 
   std::vector<Hwc2::Layer> out_layers;
   std::vector<int> out_fences;
-  error = hwc2_hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
-                                       &out_fences);
+  error = composer_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
+                                      &out_fences);
   ALOGE_IF(error != HWC::Error::None,
            "HardwareComposer::PostLayers: Failed to get release fences: %s",
            error.to_string().c_str());
 
-  // Perform post-frame bookkeeping. Unused layers are a no-op.
+  // Perform post-frame bookkeeping.
   uint32_t num_elements = out_layers.size();
   for (size_t i = 0; i < num_elements; ++i) {
-    for (size_t j = 0; j < active_layer_count_; ++j) {
-      if (layers_[j].GetLayerHandle() == out_layers[i]) {
-        layers_[j].Finish(out_fences[i]);
+    for (auto& layer : layers_) {
+      if (layer.GetLayerHandle() == out_layers[i]) {
+        layer.Finish(out_fences[i]);
       }
     }
   }
@@ -473,7 +502,7 @@
     pending_surfaces_ = std::move(surfaces);
   }
 
-  if (request_display_callback_)
+  if (request_display_callback_ && (!is_standalone_device_ || !composer_))
     request_display_callback_(!display_idle);
 
   // Set idle state based on whether there are any surfaces to handle.
@@ -546,7 +575,7 @@
 }
 
 int HardwareComposer::PostThreadPollInterruptible(
-    const pdx::LocalHandle& event_fd, int requested_events) {
+    const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms) {
   pollfd pfd[2] = {
       {
           .fd = event_fd.Get(),
@@ -561,7 +590,7 @@
   };
   int ret, error;
   do {
-    ret = poll(pfd, 2, -1);
+    ret = poll(pfd, 2, timeout_ms);
     error = errno;
     ALOGW_IF(ret < 0,
              "HardwareComposer::PostThreadPollInterruptible: Error during "
@@ -571,167 +600,40 @@
 
   if (ret < 0) {
     return -error;
+  } else if (ret == 0) {
+    return -ETIMEDOUT;
   } else if (pfd[0].revents != 0) {
     return 0;
   } else if (pfd[1].revents != 0) {
-    ALOGI("VrHwcPost thread interrupted");
+    ALOGI("VrHwcPost thread interrupted: revents=%x", pfd[1].revents);
     return kPostThreadInterrupted;
   } else {
     return 0;
   }
 }
 
-// Reads the value of the display driver wait_pingpong state. Returns 0 or 1
-// (the value of the state) on success or a negative error otherwise.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::ReadWaitPPState() {
-  // Gracefully handle when the kernel does not support this feature.
-  if (!primary_display_wait_pp_fd_)
-    return 0;
-
-  const int wait_pp_fd = primary_display_wait_pp_fd_.Get();
-  int ret, error;
-
-  ret = lseek(wait_pp_fd, 0, SEEK_SET);
-  if (ret < 0) {
-    error = errno;
-    ALOGE("HardwareComposer::ReadWaitPPState: Failed to seek wait_pp fd: %s",
-          strerror(error));
-    return -error;
-  }
-
-  char data = -1;
-  ret = read(wait_pp_fd, &data, sizeof(data));
-  if (ret < 0) {
-    error = errno;
-    ALOGE("HardwareComposer::ReadWaitPPState: Failed to read wait_pp state: %s",
-          strerror(error));
-    return -error;
-  }
-
-  switch (data) {
-    case '0':
-      return 0;
-    case '1':
-      return 1;
-    default:
-      ALOGE(
-          "HardwareComposer::ReadWaitPPState: Unexpected value for wait_pp: %d",
-          data);
-      return -EINVAL;
-  }
-}
-
-// Reads the timestamp of the last vsync from the display driver.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::ReadVSyncTimestamp(int64_t* timestamp) {
-  const int event_fd = primary_display_vsync_event_fd_.Get();
-  int ret, error;
-
-  // The driver returns data in the form "VSYNC=<timestamp ns>".
-  std::array<char, 32> data;
-  data.fill('\0');
-
-  // Seek back to the beginning of the event file.
-  ret = lseek(event_fd, 0, SEEK_SET);
-  if (ret < 0) {
-    error = errno;
-    ALOGE(
-        "HardwareComposer::ReadVSyncTimestamp: Failed to seek vsync event fd: "
-        "%s",
-        strerror(error));
-    return -error;
-  }
-
-  // Read the vsync event timestamp.
-  ret = read(event_fd, data.data(), data.size());
-  if (ret < 0) {
-    error = errno;
-    ALOGE_IF(
-        error != EAGAIN,
-        "HardwareComposer::ReadVSyncTimestamp: Error while reading timestamp: "
-        "%s",
-        strerror(error));
-    return -error;
-  }
-
-  ret = sscanf(data.data(), "VSYNC=%" PRIu64,
-               reinterpret_cast<uint64_t*>(timestamp));
-  if (ret < 0) {
-    error = errno;
-    ALOGE(
-        "HardwareComposer::ReadVSyncTimestamp: Error while parsing timestamp: "
-        "%s",
-        strerror(error));
-    return -error;
-  }
-
-  return 0;
-}
-
-// Blocks until the next vsync event is signaled by the display driver.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::BlockUntilVSync() {
-  // Vsync is signaled by POLLPRI on the fb vsync node.
-  return PostThreadPollInterruptible(primary_display_vsync_event_fd_, POLLPRI);
+Status<int64_t> HardwareComposer::GetVSyncTime() {
+  auto status = composer_callback_->GetVsyncTime(HWC_DISPLAY_PRIMARY);
+  ALOGE_IF(!status,
+           "HardwareComposer::GetVSyncTime: Failed to get vsync timestamp: %s",
+           status.GetErrorMessage().c_str());
+  return status;
 }
 
 // Waits for the next vsync and returns the timestamp of the vsync event. If
 // vsync already passed since the last call, returns the latest vsync timestamp
-// instead of blocking. This method updates the last_vsync_timeout_ in the
-// process.
-//
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::WaitForVSync(int64_t* timestamp) {
-  int error;
-
-  // Get the current timestamp and decide what to do.
-  while (true) {
-    int64_t current_vsync_timestamp;
-    error = ReadVSyncTimestamp(&current_vsync_timestamp);
-    if (error < 0 && error != -EAGAIN)
-      return error;
-
-    if (error == -EAGAIN) {
-      // Vsync was turned off, wait for the next vsync event.
-      error = BlockUntilVSync();
-      if (error < 0 || error == kPostThreadInterrupted)
-        return error;
-
-      // Try again to get the timestamp for this new vsync interval.
-      continue;
-    }
-
-    // Check that we advanced to a later vsync interval.
-    if (TimestampGT(current_vsync_timestamp, last_vsync_timestamp_)) {
-      *timestamp = last_vsync_timestamp_ = current_vsync_timestamp;
-      return 0;
-    }
-
-    // See how close we are to the next expected vsync. If we're within 1ms,
-    // sleep for 1ms and try again.
-    const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
-    const int64_t threshold_ns = 1000000;  // 1ms
-
-    const int64_t next_vsync_est = last_vsync_timestamp_ + ns_per_frame;
-    const int64_t distance_to_vsync_est = next_vsync_est - GetSystemClockNs();
-
-    if (distance_to_vsync_est > threshold_ns) {
-      // Wait for vsync event notification.
-      error = BlockUntilVSync();
-      if (error < 0 || error == kPostThreadInterrupted)
-        return error;
-    } else {
-      // Sleep for a short time (1 millisecond) before retrying.
-      error = SleepUntil(GetSystemClockNs() + threshold_ns);
-      if (error < 0 || error == kPostThreadInterrupted)
-        return error;
-    }
+// instead of blocking.
+Status<int64_t> HardwareComposer::WaitForVSync() {
+  const int64_t predicted_vsync_time =
+      last_vsync_timestamp_ +
+      display_metrics_.vsync_period_ns * vsync_prediction_interval_;
+  const int error = SleepUntil(predicted_vsync_time);
+  if (error < 0) {
+    ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s",
+          strerror(-error));
+    return error;
   }
+  return {predicted_vsync_time};
 }
 
 int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) {
@@ -749,7 +651,8 @@
     return -error;
   }
 
-  return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN);
+  return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN,
+                                     /*timeout_ms*/ -1);
 }
 
 void HardwareComposer::PostThread() {
@@ -772,24 +675,6 @@
            strerror(errno));
 #endif  // ENABLE_BACKLIGHT_BRIGHTNESS
 
-  // Open the vsync event node for the primary display.
-  // TODO(eieio): Move this into a platform-specific class.
-  primary_display_vsync_event_fd_ =
-      LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY);
-  ALOGE_IF(!primary_display_vsync_event_fd_,
-           "HardwareComposer: Failed to open vsync event node for primary "
-           "display: %s",
-           strerror(errno));
-
-  // Open the wait pingpong status node for the primary display.
-  // TODO(eieio): Move this into a platform-specific class.
-  primary_display_wait_pp_fd_ =
-      LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY);
-  ALOGW_IF(
-      !primary_display_wait_pp_fd_,
-      "HardwareComposer: Failed to open wait_pp node for primary display: %s",
-      strerror(errno));
-
   // Create a timerfd based on CLOCK_MONOTINIC.
   vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
   LOG_ALWAYS_FATAL_IF(
@@ -854,26 +739,41 @@
         thread_policy_setup =
             SetThreadPolicy("graphics:high", "/system/performance");
       }
+
+      // Initialize the last vsync timestamp with the current time. The
+      // predictor below uses this time + the vsync interval in absolute time
+      // units for the initial delay. Once the driver starts reporting vsync the
+      // predictor will sync up with the real vsync.
+      last_vsync_timestamp_ = GetSystemClockNs();
     }
 
     int64_t vsync_timestamp = 0;
     {
-      std::array<char, 128> buf;
-      snprintf(buf.data(), buf.size(), "wait_vsync|vsync=%d|",
-               vsync_count_ + 1);
-      ATRACE_NAME(buf.data());
+      TRACE_FORMAT("wait_vsync|vsync=%u;last_timestamp=%" PRId64
+                   ";prediction_interval=%d|",
+                   vsync_count_ + 1, last_vsync_timestamp_,
+                   vsync_prediction_interval_);
 
-      const int error = WaitForVSync(&vsync_timestamp);
+      auto status = WaitForVSync();
       ALOGE_IF(
-          error < 0,
+          !status,
           "HardwareComposer::PostThread: Failed to wait for vsync event: %s",
-          strerror(-error));
-      // Don't bother processing this frame if a pause was requested
-      if (error == kPostThreadInterrupted)
+          status.GetErrorMessage().c_str());
+
+      // If there was an error either sleeping was interrupted due to pausing or
+      // there was an error getting the latest timestamp.
+      if (!status)
         continue;
+
+      // Predicted vsync timestamp for this interval. This is stable because we
+      // use absolute time for the wakeup timer.
+      vsync_timestamp = status.get();
     }
 
-    ++vsync_count_;
+    // Advance the vsync counter only if the system is keeping up with hardware
+    // vsync to give clients an indication of the delays.
+    if (vsync_prediction_interval_ == 1)
+      ++vsync_count_;
 
     const bool layer_config_changed = UpdateLayerConfig();
 
@@ -923,6 +823,38 @@
       }
     }
 
+    {
+      auto status = GetVSyncTime();
+      if (!status) {
+        ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s",
+              status.GetErrorMessage().c_str());
+      }
+
+      // If we failed to read vsync there might be a problem with the driver.
+      // Since there's nothing we can do just behave as though we didn't get an
+      // updated vsync time and let the prediction continue.
+      const int64_t current_vsync_timestamp =
+          status ? status.get() : last_vsync_timestamp_;
+
+      const bool vsync_delayed =
+          last_vsync_timestamp_ == current_vsync_timestamp;
+      ATRACE_INT("vsync_delayed", vsync_delayed);
+
+      // If vsync was delayed advance the prediction interval and allow the
+      // fence logic in PostLayers() to skip the frame.
+      if (vsync_delayed) {
+        ALOGW(
+            "HardwareComposer::PostThread: VSYNC timestamp did not advance "
+            "since last frame: timestamp=%" PRId64 " prediction_interval=%d",
+            current_vsync_timestamp, vsync_prediction_interval_);
+        vsync_prediction_interval_++;
+      } else {
+        // We have an updated vsync timestamp, reset the prediction interval.
+        last_vsync_timestamp_ = current_vsync_timestamp;
+        vsync_prediction_interval_ = 1;
+      }
+    }
+
     PostLayers();
   }
 }
@@ -941,37 +873,60 @@
 
   ATRACE_NAME("UpdateLayerConfig_HwLayers");
 
-  display_surfaces_.clear();
+  // Sort the new direct surface list by z-order to determine the relative order
+  // of the surfaces. This relative order is used for the HWC z-order value to
+  // insulate VrFlinger and HWC z-order semantics from each other.
+  std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
+    return a->z_order() < b->z_order();
+  });
 
-  Layer* target_layer;
-  size_t layer_index;
-  for (layer_index = 0;
-       layer_index < std::min(surfaces.size(), kMaxHardwareLayers);
-       layer_index++) {
+  // Prepare a new layer stack, pulling in layers from the previous
+  // layer stack that are still active and updating their attributes.
+  std::vector<Layer> layers;
+  size_t layer_index = 0;
+  for (const auto& surface : surfaces) {
     // The bottom layer is opaque, other layers blend.
     HWC::BlendMode blending =
         layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage;
-    layers_[layer_index].Setup(surfaces[layer_index], blending,
-                               display_transform_, HWC::Composition::Device,
-                               layer_index);
-    display_surfaces_.push_back(surfaces[layer_index]);
+
+    // Try to find a layer for this surface in the set of active layers.
+    auto search =
+        std::lower_bound(layers_.begin(), layers_.end(), surface->surface_id());
+    const bool found = search != layers_.end() &&
+                       search->GetSurfaceId() == surface->surface_id();
+    if (found) {
+      // Update the attributes of the layer that may have changed.
+      search->SetBlending(blending);
+      search->SetZOrder(layer_index);  // Relative z-order.
+
+      // Move the existing layer to the new layer set and remove the empty layer
+      // object from the current set.
+      layers.push_back(std::move(*search));
+      layers_.erase(search);
+    } else {
+      // Insert a layer for the new surface.
+      layers.emplace_back(surface, blending, display_transform_,
+                          HWC::Composition::Device, layer_index);
+    }
+
+    ALOGI_IF(
+        TRACE,
+        "HardwareComposer::UpdateLayerConfig: layer_index=%zu surface_id=%d",
+        layer_index, layers[layer_index].GetSurfaceId());
+
+    layer_index++;
   }
 
-  // Clear unused layers.
-  for (size_t i = layer_index; i < kMaxHardwareLayers; i++)
-    layers_[i].Reset();
+  // Sort the new layer stack by ascending surface id.
+  std::sort(layers.begin(), layers.end());
 
-  active_layer_count_ = layer_index;
+  // Replace the previous layer set with the new layer set. The destructor of
+  // the previous set will clean up the remaining Layers that are not moved to
+  // the new layer set.
+  layers_ = std::move(layers);
+
   ALOGD_IF(TRACE, "HardwareComposer::UpdateLayerConfig: %zd active layers",
-           active_layer_count_);
-
-  // Any surfaces left over could not be assigned a hardware layer and will
-  // not be displayed.
-  ALOGW_IF(surfaces.size() != display_surfaces_.size(),
-           "HardwareComposer::UpdateLayerConfig: More surfaces than layers: "
-           "pending_surfaces=%zu display_surfaces=%zu",
-           surfaces.size(), display_surfaces_.size());
-
+           layers_.size());
   return true;
 }
 
@@ -979,30 +934,6 @@
   vsync_callback_ = callback;
 }
 
-void HardwareComposer::HwcRefresh(hwc2_callback_data_t /*data*/,
-                                  hwc2_display_t /*display*/) {
-  // TODO(eieio): implement invalidate callbacks.
-}
-
-void HardwareComposer::HwcVSync(hwc2_callback_data_t /*data*/,
-                                hwc2_display_t /*display*/,
-                                int64_t /*timestamp*/) {
-  ATRACE_NAME(__PRETTY_FUNCTION__);
-  // Intentionally empty. HWC may require a callback to be set to enable vsync
-  // signals. We bypass this callback thread by monitoring the vsync event
-  // directly, but signals still need to be enabled.
-}
-
-void HardwareComposer::HwcHotplug(hwc2_callback_data_t /*callbackData*/,
-                                  hwc2_display_t /*display*/,
-                                  hwc2_connection_t /*connected*/) {
-  // TODO(eieio): implement display hotplug callbacks.
-}
-
-void HardwareComposer::OnHardwareComposerRefresh() {
-  // TODO(steventhomas): Handle refresh.
-}
-
 void HardwareComposer::SetBacklightBrightness(int brightness) {
   if (backlight_brightness_fd_) {
     std::array<char, 32> text;
@@ -1011,15 +942,121 @@
   }
 }
 
-void Layer::InitializeGlobals(Hwc2::Composer* hwc2_hidl,
-                              const HWCDisplayMetrics* metrics) {
-  hwc2_hidl_ = hwc2_hidl;
-  display_metrics_ = metrics;
+Return<void> HardwareComposer::ComposerCallback::onHotplug(
+    Hwc2::Display display, IComposerCallback::Connection /*conn*/) {
+  // See if the driver supports the vsync_event node in sysfs.
+  if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES &&
+      !displays_[display].driver_vsync_event_fd) {
+    std::array<char, 1024> buffer;
+    snprintf(buffer.data(), buffer.size(),
+             "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display);
+    if (LocalHandle handle{buffer.data(), O_RDONLY}) {
+      ALOGI(
+          "HardwareComposer::ComposerCallback::onHotplug: Driver supports "
+          "vsync_event node for display %" PRIu64,
+          display);
+      displays_[display].driver_vsync_event_fd = std::move(handle);
+    } else {
+      ALOGI(
+          "HardwareComposer::ComposerCallback::onHotplug: Driver does not "
+          "support vsync_event node for display %" PRIu64,
+          display);
+    }
+  }
+
+  return Void();
 }
 
+Return<void> HardwareComposer::ComposerCallback::onRefresh(
+    Hwc2::Display /*display*/) {
+  return hardware::Void();
+}
+
+Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
+                                                         int64_t timestamp) {
+  TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
+               display, timestamp);
+  if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+    displays_[display].callback_vsync_timestamp = timestamp;
+  } else {
+    ALOGW(
+        "HardwareComposer::ComposerCallback::onVsync: Received vsync on "
+        "non-physical display: display=%" PRId64,
+        display);
+  }
+  return Void();
+}
+
+Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
+    Hwc2::Display display) {
+  if (display >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+    ALOGE(
+        "HardwareComposer::ComposerCallback::GetVsyncTime: Invalid physical "
+        "display requested: display=%" PRIu64,
+        display);
+    return ErrorStatus(EINVAL);
+  }
+
+  // See if the driver supports direct vsync events.
+  LocalHandle& event_fd = displays_[display].driver_vsync_event_fd;
+  if (!event_fd) {
+    // Fall back to returning the last timestamp returned by the vsync
+    // callback.
+    std::lock_guard<std::mutex> autolock(vsync_mutex_);
+    return displays_[display].callback_vsync_timestamp;
+  }
+
+  // When the driver supports the vsync_event sysfs node we can use it to
+  // determine the latest vsync timestamp, even if the HWC callback has been
+  // delayed.
+
+  // The driver returns data in the form "VSYNC=<timestamp ns>".
+  std::array<char, 32> data;
+  data.fill('\0');
+
+  // Seek back to the beginning of the event file.
+  int ret = lseek(event_fd.Get(), 0, SEEK_SET);
+  if (ret < 0) {
+    const int error = errno;
+    ALOGE(
+        "HardwareComposer::ComposerCallback::GetVsyncTime: Failed to seek "
+        "vsync event fd: %s",
+        strerror(error));
+    return ErrorStatus(error);
+  }
+
+  // Read the vsync event timestamp.
+  ret = read(event_fd.Get(), data.data(), data.size());
+  if (ret < 0) {
+    const int error = errno;
+    ALOGE_IF(error != EAGAIN,
+             "HardwareComposer::ComposerCallback::GetVsyncTime: Error "
+             "while reading timestamp: %s",
+             strerror(error));
+    return ErrorStatus(error);
+  }
+
+  int64_t timestamp;
+  ret = sscanf(data.data(), "VSYNC=%" PRIu64,
+               reinterpret_cast<uint64_t*>(&timestamp));
+  if (ret < 0) {
+    const int error = errno;
+    ALOGE(
+        "HardwareComposer::ComposerCallback::GetVsyncTime: Error while "
+        "parsing timestamp: %s",
+        strerror(error));
+    return ErrorStatus(error);
+  }
+
+  return {timestamp};
+}
+
+Hwc2::Composer* Layer::composer_{nullptr};
+HWCDisplayMetrics Layer::display_metrics_{0, 0, {0, 0}, 0};
+
 void Layer::Reset() {
-  if (hwc2_hidl_ != nullptr && hardware_composer_layer_) {
-    hwc2_hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
+  if (hardware_composer_layer_) {
+    composer_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
     hardware_composer_layer_ = 0;
   }
 
@@ -1031,41 +1068,74 @@
   source_ = EmptyVariant{};
   acquire_fence_.Close();
   surface_rect_functions_applied_ = false;
+  pending_visibility_settings_ = true;
+  cached_buffer_map_.clear();
 }
 
-void Layer::Setup(const std::shared_ptr<DirectDisplaySurface>& surface,
-                  HWC::BlendMode blending, HWC::Transform transform,
-                  HWC::Composition composition_type, size_t z_order) {
-  Reset();
-  z_order_ = z_order;
-  blending_ = blending;
-  transform_ = transform;
-  composition_type_ = HWC::Composition::Invalid;
-  target_composition_type_ = composition_type;
-  source_ = SourceSurface{surface};
+Layer::Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
+             HWC::BlendMode blending, HWC::Transform transform,
+             HWC::Composition composition_type, size_t z_order)
+    : z_order_{z_order},
+      blending_{blending},
+      transform_{transform},
+      target_composition_type_{composition_type},
+      source_{SourceSurface{surface}} {
   CommonLayerSetup();
 }
 
-void Layer::Setup(const std::shared_ptr<IonBuffer>& buffer,
-                  HWC::BlendMode blending, HWC::Transform transform,
-                  HWC::Composition composition_type, size_t z_order) {
-  Reset();
-  z_order_ = z_order;
-  blending_ = blending;
-  transform_ = transform;
-  composition_type_ = HWC::Composition::Invalid;
-  target_composition_type_ = composition_type;
-  source_ = SourceBuffer{buffer};
+Layer::Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+             HWC::Transform transform, HWC::Composition composition_type,
+             size_t z_order)
+    : z_order_{z_order},
+      blending_{blending},
+      transform_{transform},
+      target_composition_type_{composition_type},
+      source_{SourceBuffer{buffer}} {
   CommonLayerSetup();
 }
 
+Layer::~Layer() { Reset(); }
+
+Layer::Layer(Layer&& other) { *this = std::move(other); }
+
+Layer& Layer::operator=(Layer&& other) {
+  if (this != &other) {
+    Reset();
+    using std::swap;
+    swap(hardware_composer_layer_, other.hardware_composer_layer_);
+    swap(z_order_, other.z_order_);
+    swap(blending_, other.blending_);
+    swap(transform_, other.transform_);
+    swap(composition_type_, other.composition_type_);
+    swap(target_composition_type_, other.target_composition_type_);
+    swap(source_, other.source_);
+    swap(acquire_fence_, other.acquire_fence_);
+    swap(surface_rect_functions_applied_,
+         other.surface_rect_functions_applied_);
+    swap(pending_visibility_settings_, other.pending_visibility_settings_);
+    swap(cached_buffer_map_, other.cached_buffer_map_);
+  }
+  return *this;
+}
+
 void Layer::UpdateBuffer(const std::shared_ptr<IonBuffer>& buffer) {
   if (source_.is<SourceBuffer>())
     std::get<SourceBuffer>(source_) = {buffer};
 }
 
-void Layer::SetBlending(HWC::BlendMode blending) { blending_ = blending; }
-void Layer::SetZOrder(size_t z_order) { z_order_ = z_order; }
+void Layer::SetBlending(HWC::BlendMode blending) {
+  if (blending_ != blending) {
+    blending_ = blending;
+    pending_visibility_settings_ = true;
+  }
+}
+
+void Layer::SetZOrder(size_t z_order) {
+  if (z_order_ != z_order) {
+    z_order_ = z_order;
+    pending_visibility_settings_ = true;
+  }
+}
 
 IonBuffer* Layer::GetBuffer() {
   struct Visitor {
@@ -1076,93 +1146,108 @@
   return source_.Visit(Visitor{});
 }
 
-void Layer::UpdateLayerSettings() {
-  if (!IsLayerSetup()) {
-    ALOGE(
-        "HardwareComposer::Layer::UpdateLayerSettings: Attempt to update "
-        "unused Layer!");
-    return;
-  }
+void Layer::UpdateVisibilitySettings() {
+  if (pending_visibility_settings_) {
+    pending_visibility_settings_ = false;
 
+    HWC::Error error;
+    hwc2_display_t display = HWC_DISPLAY_PRIMARY;
+
+    error = composer_->setLayerBlendMode(
+        display, hardware_composer_layer_,
+        blending_.cast<Hwc2::IComposerClient::BlendMode>());
+    ALOGE_IF(error != HWC::Error::None,
+             "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
+             error.to_string().c_str());
+
+    error =
+        composer_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
+    ALOGE_IF(error != HWC::Error::None,
+             "Layer::UpdateLayerSettings: Error setting z_ order: %s",
+             error.to_string().c_str());
+  }
+}
+
+void Layer::UpdateLayerSettings() {
   HWC::Error error;
   hwc2_display_t display = HWC_DISPLAY_PRIMARY;
 
-  error = hwc2_hidl_->setLayerCompositionType(
-      display, hardware_composer_layer_,
-      composition_type_.cast<Hwc2::IComposerClient::Composition>());
-  ALOGE_IF(
-      error != HWC::Error::None,
-      "Layer::UpdateLayerSettings: Error setting layer composition type: %s",
-      error.to_string().c_str());
-
-  error = hwc2_hidl_->setLayerBlendMode(
-      display, hardware_composer_layer_,
-      blending_.cast<Hwc2::IComposerClient::BlendMode>());
-  ALOGE_IF(error != HWC::Error::None,
-           "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
-           error.to_string().c_str());
+  UpdateVisibilitySettings();
 
   // TODO(eieio): Use surface attributes or some other mechanism to control
   // the layer display frame.
-  error = hwc2_hidl_->setLayerDisplayFrame(
+  error = composer_->setLayerDisplayFrame(
       display, hardware_composer_layer_,
-      {0, 0, display_metrics_->width, display_metrics_->height});
+      {0, 0, display_metrics_.width, display_metrics_.height});
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer display frame: %s",
            error.to_string().c_str());
 
-  error = hwc2_hidl_->setLayerVisibleRegion(
+  error = composer_->setLayerVisibleRegion(
       display, hardware_composer_layer_,
-      {{0, 0, display_metrics_->width, display_metrics_->height}});
+      {{0, 0, display_metrics_.width, display_metrics_.height}});
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer visible region: %s",
            error.to_string().c_str());
 
   error =
-      hwc2_hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
+      composer_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s",
            error.to_string().c_str());
-
-  error =
-      hwc2_hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
-  ALOGE_IF(error != HWC::Error::None,
-           "Layer::UpdateLayerSettings: Error setting z_ order: %s",
-           error.to_string().c_str());
 }
 
 void Layer::CommonLayerSetup() {
   HWC::Error error =
-      hwc2_hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
-  ALOGE_IF(
-      error != HWC::Error::None,
-      "Layer::CommonLayerSetup: Failed to create layer on primary display: %s",
-      error.to_string().c_str());
+      composer_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
+  ALOGE_IF(error != HWC::Error::None,
+           "Layer::CommonLayerSetup: Failed to create layer on primary "
+           "display: %s",
+           error.to_string().c_str());
   UpdateLayerSettings();
 }
 
+bool Layer::CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id) {
+  auto search = cached_buffer_map_.find(slot);
+  if (search != cached_buffer_map_.end() && search->second == buffer_id)
+    return true;
+
+  // Assign or update the buffer slot.
+  if (buffer_id >= 0)
+    cached_buffer_map_[slot] = buffer_id;
+  return false;
+}
+
 void Layer::Prepare() {
-  int right, bottom;
+  int right, bottom, id;
   sp<GraphicBuffer> handle;
+  std::size_t slot;
 
   // Acquire the next buffer according to the type of source.
   IfAnyOf<SourceSurface, SourceBuffer>::Call(&source_, [&](auto& source) {
-    std::tie(right, bottom, handle, acquire_fence_) = source.Acquire();
+    std::tie(right, bottom, id, handle, acquire_fence_, slot) =
+        source.Acquire();
   });
 
-  // When a layer is first setup there may be some time before the first buffer
-  // arrives. Setup the HWC layer as a solid color to stall for time until the
-  // first buffer arrives. Once the first buffer arrives there will always be a
-  // buffer for the frame even if it is old.
+  TRACE_FORMAT("Layer::Prepare|buffer_id=%d;slot=%zu|", id, slot);
+
+  // Update any visibility (blending, z-order) changes that occurred since
+  // last prepare.
+  UpdateVisibilitySettings();
+
+  // When a layer is first setup there may be some time before the first
+  // buffer arrives. Setup the HWC layer as a solid color to stall for time
+  // until the first buffer arrives. Once the first buffer arrives there will
+  // always be a buffer for the frame even if it is old.
   if (!handle.get()) {
     if (composition_type_ == HWC::Composition::Invalid) {
       composition_type_ = HWC::Composition::SolidColor;
-      hwc2_hidl_->setLayerCompositionType(
+      composer_->setLayerCompositionType(
           HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
           composition_type_.cast<Hwc2::IComposerClient::Composition>());
       Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0};
-      hwc2_hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
-                                layer_color);
+      composer_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+                               layer_color);
     } else {
       // The composition type is already set. Nothing else to do until a
       // buffer arrives.
@@ -1170,15 +1255,20 @@
   } else {
     if (composition_type_ != target_composition_type_) {
       composition_type_ = target_composition_type_;
-      hwc2_hidl_->setLayerCompositionType(
+      composer_->setLayerCompositionType(
           HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
           composition_type_.cast<Hwc2::IComposerClient::Composition>());
     }
 
+    // See if the HWC cache already has this buffer.
+    const bool cached = CheckAndUpdateCachedBuffer(slot, id);
+    if (cached)
+      handle = nullptr;
+
     HWC::Error error{HWC::Error::None};
-    error = hwc2_hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY,
-                                       hardware_composer_layer_, 0, handle,
-                                       acquire_fence_.Get());
+    error =
+        composer_->setLayerBuffer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+                                  slot, handle, acquire_fence_.Get());
 
     ALOGE_IF(error != HWC::Error::None,
              "Layer::Prepare: Error setting layer buffer: %s",
@@ -1187,9 +1277,9 @@
     if (!surface_rect_functions_applied_) {
       const float float_right = right;
       const float float_bottom = bottom;
-      error = hwc2_hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
-                                             hardware_composer_layer_,
-                                             {0, 0, float_right, float_bottom});
+      error = composer_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
+                                            hardware_composer_layer_,
+                                            {0, 0, float_right, float_bottom});
 
       ALOGE_IF(error != HWC::Error::None,
                "Layer::Prepare: Error setting layer source crop: %s",
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index a0c50e1..7010db9 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -52,15 +52,7 @@
 // source supplying buffers for the layer's contents.
 class Layer {
  public:
-  Layer() {}
-
-  // Sets up the global state used by all Layer instances. This must be called
-  // before using any Layer methods.
-  static void InitializeGlobals(Hwc2::Composer* hwc2_hidl,
-                                const HWCDisplayMetrics* metrics);
-
-  // Releases any shared pointers and fence handles held by this instance.
-  void Reset();
+  Layer() = default;
 
   // Sets up the layer to use a display surface as its content source. The Layer
   // automatically handles ACQUIRE/RELEASE phases for the surface's buffer train
@@ -71,9 +63,9 @@
   // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
   // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
   // |index| is the index of this surface in the DirectDisplaySurface array.
-  void Setup(const std::shared_ptr<DirectDisplaySurface>& surface,
-             HWC::BlendMode blending, HWC::Transform transform,
-             HWC::Composition composition_type, size_t z_roder);
+  Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
+        HWC::BlendMode blending, HWC::Transform transform,
+        HWC::Composition composition_type, size_t z_roder);
 
   // Sets up the layer to use a direct buffer as its content source. No special
   // handling of the buffer is performed; responsibility for updating or
@@ -83,9 +75,17 @@
   // |transform| receives HWC_TRANSFORM_* values.
   // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
   // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
-  void Setup(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
-             HWC::Transform transform, HWC::Composition composition_type,
-             size_t z_order);
+  Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+        HWC::Transform transform, HWC::Composition composition_type,
+        size_t z_order);
+
+  Layer(Layer&&);
+  Layer& operator=(Layer&&);
+
+  ~Layer();
+
+  // Releases any shared pointers and fence handles held by this instance.
+  void Reset();
 
   // Layers that use a direct IonBuffer should call this each frame to update
   // which buffer will be used for the next PostLayers.
@@ -120,9 +120,6 @@
   HWC::Layer GetLayerHandle() const { return hardware_composer_layer_; }
   bool IsLayerSetup() const { return !source_.empty(); }
 
-  // Applies all of the settings to this layer using the hwc functions
-  void UpdateLayerSettings();
-
   int GetSurfaceId() const {
     int surface_id = -1;
     pdx::rpc::IfAnyOf<SourceSurface>::Call(
@@ -141,11 +138,47 @@
     return buffer_id;
   }
 
+  // Compares Layers by surface id.
+  bool operator<(const Layer& other) const {
+    return GetSurfaceId() < other.GetSurfaceId();
+  }
+  bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; }
+
+  // Sets the composer instance used by all Layer instances.
+  static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; }
+
+  // Sets the display metrics used by all Layer instances.
+  static void SetDisplayMetrics(HWCDisplayMetrics display_metrics) {
+    display_metrics_ = display_metrics;
+  }
+
  private:
   void CommonLayerSetup();
 
-  static Hwc2::Composer* hwc2_hidl_;
-  static const HWCDisplayMetrics* display_metrics_;
+  // Applies all of the settings to this layer using the hwc functions
+  void UpdateLayerSettings();
+
+  // Applies visibility settings that may have changed.
+  void UpdateVisibilitySettings();
+
+  // Checks whether the buffer, given by id, is associated with the given slot
+  // in the HWC buffer cache. If the slot is not associated with the given
+  // buffer the cache is updated to establish the association and the buffer
+  // should be sent to HWC using setLayerBuffer. Returns true if the association
+  // was already established, false if not. A buffer_id of -1 is never
+  // associated and always returns false.
+  bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id);
+
+  // Composer instance shared by all instances of Layer. This must be set
+  // whenever a new instance of the Composer is created. This may be set to
+  // nullptr as long as there are no instances of Layer that might need to use
+  // it.
+  static Hwc2::Composer* composer_;
+
+  // Display metrics shared by all instances of Layer. This must be set at least
+  // once during VrFlinger initialization and is expected to remain constant
+  // thereafter.
+  static HWCDisplayMetrics display_metrics_;
 
   // The hardware composer layer and metrics to use during the prepare cycle.
   hwc2_layer_t hardware_composer_layer_ = 0;
@@ -173,19 +206,21 @@
     // the previous buffer is returned or an empty value if no buffer has ever
     // been posted. When a new buffer is acquired the previous buffer's release
     // fence is passed out automatically.
-    std::tuple<int, int, sp<GraphicBuffer>, pdx::LocalHandle> Acquire() {
+    std::tuple<int, int, int, sp<GraphicBuffer>, pdx::LocalHandle, std::size_t>
+    Acquire() {
       if (surface->IsBufferAvailable()) {
         acquired_buffer.Release(std::move(release_fence));
         acquired_buffer = surface->AcquireCurrentBuffer();
         ATRACE_ASYNC_END("BufferPost", acquired_buffer.buffer()->id());
       }
       if (!acquired_buffer.IsEmpty()) {
-        return std::make_tuple(acquired_buffer.buffer()->width(),
-                               acquired_buffer.buffer()->height(),
-                               acquired_buffer.buffer()->buffer()->buffer(),
-                               acquired_buffer.ClaimAcquireFence());
+        return std::make_tuple(
+            acquired_buffer.buffer()->width(),
+            acquired_buffer.buffer()->height(), acquired_buffer.buffer()->id(),
+            acquired_buffer.buffer()->buffer()->buffer(),
+            acquired_buffer.ClaimAcquireFence(), acquired_buffer.slot());
       } else {
-        return std::make_tuple(0, 0, nullptr, pdx::LocalHandle{});
+        return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0);
       }
     }
 
@@ -217,12 +252,13 @@
   struct SourceBuffer {
     std::shared_ptr<IonBuffer> buffer;
 
-    std::tuple<int, int, sp<GraphicBuffer>, pdx::LocalHandle> Acquire() {
+    std::tuple<int, int, int, sp<GraphicBuffer>, pdx::LocalHandle, std::size_t>
+    Acquire() {
       if (buffer)
-        return std::make_tuple(buffer->width(), buffer->height(),
-                               buffer->buffer(), pdx::LocalHandle{});
+        return std::make_tuple(buffer->width(), buffer->height(), -1,
+                               buffer->buffer(), pdx::LocalHandle{}, 0);
       else
-        return std::make_tuple(0, 0, nullptr, pdx::LocalHandle{});
+        return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0);
     }
 
     void Finish(pdx::LocalHandle /*fence*/) {}
@@ -239,6 +275,13 @@
 
   pdx::LocalHandle acquire_fence_;
   bool surface_rect_functions_applied_ = false;
+  bool pending_visibility_settings_ = true;
+
+  // Map of buffer slot assignments that have already been established with HWC:
+  // slot -> buffer_id. When this map contains a matching slot and buffer_id the
+  // buffer argument to setLayerBuffer may be nullptr to avoid the cost of
+  // importing a buffer HWC already knows about.
+  std::map<std::size_t, int> cached_buffer_map_;
 
   Layer(const Layer&) = delete;
   void operator=(const Layer&) = delete;
@@ -258,16 +301,11 @@
   using VSyncCallback = std::function<void(int, int64_t, int64_t, uint32_t)>;
   using RequestDisplayCallback = std::function<void(bool)>;
 
-  // Since there is no universal way to query the number of hardware layers,
-  // just set it to 4 for now.
-  static constexpr size_t kMaxHardwareLayers = 4;
-
   HardwareComposer();
-  HardwareComposer(Hwc2::Composer* hidl,
-                   RequestDisplayCallback request_display_callback);
   ~HardwareComposer();
 
-  bool Initialize();
+  bool Initialize(Hwc2::Composer* composer,
+                  RequestDisplayCallback request_display_callback);
 
   bool IsInitialized() const { return initialized_; }
 
@@ -281,11 +319,6 @@
   // Get the HMD display metrics for the current display.
   display::Metrics GetHmdDisplayMetrics() const;
 
-  HWC::Error GetDisplayAttribute(hwc2_display_t display, hwc2_config_t config,
-                                 hwc2_attribute_t attributes,
-                                 int32_t* out_value) const;
-  HWC::Error GetDisplayMetrics(hwc2_display_t display, hwc2_config_t config,
-                               HWCDisplayMetrics* out_metrics) const;
   std::string Dump();
 
   void SetVSyncCallback(VSyncCallback callback);
@@ -308,34 +341,37 @@
   int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer);
   void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
 
-  void OnHardwareComposerRefresh();
-
  private:
-  int32_t EnableVsync(bool enabled);
+  HWC::Error GetDisplayAttribute(Hwc2::Composer* composer,
+                                 hwc2_display_t display, hwc2_config_t config,
+                                 hwc2_attribute_t attributes,
+                                 int32_t* out_value) const;
+  HWC::Error GetDisplayMetrics(Hwc2::Composer* composer, hwc2_display_t display,
+                               hwc2_config_t config,
+                               HWCDisplayMetrics* out_metrics) const;
+
+  HWC::Error EnableVsync(bool enabled);
+  HWC::Error SetPowerMode(bool active);
 
   class ComposerCallback : public Hwc2::IComposerCallback {
    public:
-    ComposerCallback() {}
+    ComposerCallback() = default;
+    hardware::Return<void> onHotplug(Hwc2::Display display,
+                                     Connection conn) override;
+    hardware::Return<void> onRefresh(Hwc2::Display display) override;
+    hardware::Return<void> onVsync(Hwc2::Display display,
+                                   int64_t timestamp) override;
 
-    hardware::Return<void> onHotplug(Hwc2::Display /*display*/,
-                                     Connection /*connected*/) override {
-      // TODO(skiazyk): depending on how the server is implemented, we might
-      // have to set it up to synchronize with receiving this event, as it can
-      // potentially be a critical event for setting up state within the
-      // hwc2 module. That is, we (technically) should not call any other hwc
-      // methods until this method has been called after registering the
-      // callbacks.
-      return hardware::Void();
-    }
+    pdx::Status<int64_t> GetVsyncTime(Hwc2::Display display);
 
-    hardware::Return<void> onRefresh(Hwc2::Display /*display*/) override {
-      return hardware::Void();
-    }
+   private:
+    std::mutex vsync_mutex_;
 
-    hardware::Return<void> onVsync(Hwc2::Display /*display*/,
-                                   int64_t /*timestamp*/) override {
-      return hardware::Void();
-    }
+    struct Display {
+      pdx::LocalHandle driver_vsync_event_fd;
+      int64_t callback_vsync_timestamp{0};
+    };
+    std::array<Display, HWC_NUM_PHYSICAL_DISPLAY_TYPES> displays_;
   };
 
   HWC::Error Validate(hwc2_display_t display);
@@ -364,22 +400,21 @@
   void UpdatePostThreadState(uint32_t state, bool suspend);
 
   // Blocks until either event_fd becomes readable, or we're interrupted by a
-  // control thread. Any errors are returned as negative errno values. If we're
-  // interrupted, kPostThreadInterrupted will be returned.
+  // control thread, or timeout_ms is reached before any events occur. Any
+  // errors are returned as negative errno values, with -ETIMEDOUT returned in
+  // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be
+  // returned.
   int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd,
-                                  int requested_events);
+                                  int requested_events, int timeout_ms);
 
-  // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made
-  // on the post thread that can be interrupted by a control thread. If
-  // interrupted, these calls return kPostThreadInterrupted.
+  // WaitForVSync and SleepUntil are blocking calls made on the post thread that
+  // can be interrupted by a control thread. If interrupted, these calls return
+  // kPostThreadInterrupted.
   int ReadWaitPPState();
-  int BlockUntilVSync();
-  int ReadVSyncTimestamp(int64_t* timestamp);
-  int WaitForVSync(int64_t* timestamp);
+  pdx::Status<int64_t> WaitForVSync();
+  pdx::Status<int64_t> GetVSyncTime();
   int SleepUntil(int64_t wakeup_timestamp);
 
-  bool IsFramePendingInDriver() { return ReadWaitPPState() == 1; }
-
   // Reconfigures the layer stack if the display surfaces changed since the last
   // frame. Called only from the post thread.
   bool UpdateLayerConfig();
@@ -397,12 +432,11 @@
   void UpdateConfigBuffer();
 
   bool initialized_;
+  bool is_standalone_device_;
 
-  // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own
-  // this pointer.
-  Hwc2::Composer* hwc2_hidl_;
+  std::unique_ptr<Hwc2::Composer> composer_;
+  sp<ComposerCallback> composer_callback_;
   RequestDisplayCallback request_display_callback_;
-  sp<ComposerCallback> callbacks_;
 
   // Display metrics of the physical display.
   HWCDisplayMetrics native_display_metrics_;
@@ -417,13 +451,9 @@
   // thread and read by the post thread.
   std::vector<std::shared_ptr<DirectDisplaySurface>> pending_surfaces_;
 
-  // The surfaces displayed by the post thread. Used exclusively by the post
-  // thread.
-  std::vector<std::shared_ptr<DirectDisplaySurface>> display_surfaces_;
-
-  // Layer array for handling buffer flow into hardware composer layers.
-  std::array<Layer, kMaxHardwareLayers> layers_;
-  size_t active_layer_count_ = 0;
+  // Layer set for handling buffer flow into hardware composer layers. This
+  // vector must be sorted by surface_id in ascending order.
+  std::vector<Layer> layers_;
 
   // Handler to hook vsync events outside of this class.
   VSyncCallback vsync_callback_;
@@ -433,7 +463,8 @@
   std::thread post_thread_;
 
   // Post thread state machine and synchronization primitives.
-  PostThreadStateType post_thread_state_{PostThreadState::Idle};
+  PostThreadStateType post_thread_state_{PostThreadState::Idle |
+                                         PostThreadState::Suspended};
   std::atomic<bool> post_thread_quiescent_{true};
   bool post_thread_resumed_{false};
   pdx::LocalHandle post_thread_event_fd_;
@@ -444,18 +475,15 @@
   // Backlight LED brightness sysfs node.
   pdx::LocalHandle backlight_brightness_fd_;
 
-  // Primary display vsync event sysfs node.
-  pdx::LocalHandle primary_display_vsync_event_fd_;
-
-  // Primary display wait_pingpong state sysfs node.
-  pdx::LocalHandle primary_display_wait_pp_fd_;
-
   // VSync sleep timerfd.
   pdx::LocalHandle vsync_sleep_timer_fd_;
 
   // The timestamp of the last vsync.
   int64_t last_vsync_timestamp_ = 0;
 
+  // The number of vsync intervals to predict since the last vsync.
+  int vsync_prediction_interval_ = 1;
+
   // Vsync count since display on.
   uint32_t vsync_count_ = 0;
 
@@ -478,12 +506,6 @@
 
   static constexpr int kPostThreadInterrupted = 1;
 
-  static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display);
-  static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display,
-                       int64_t timestamp);
-  static void HwcHotplug(hwc2_callback_data_t callbackData,
-                         hwc2_display_t display, hwc2_connection_t connected);
-
   HardwareComposer(const HardwareComposer&) = delete;
   void operator=(const HardwareComposer&) = delete;
 };
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index f41da87..33cbc84 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -4,7 +4,7 @@
 #include <thread>
 #include <memory>
 
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
 #include <vr/vr_manager/vr_manager.h>
 
 namespace android {
@@ -29,9 +29,6 @@
   void GrantDisplayOwnership();
   void SeizeDisplayOwnership();
 
-  // Called on a binder thread.
-  void OnHardwareComposerRefresh();
-
   // dump all vr flinger state.
   std::string Dump();
 
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 3a0ca4a..85dc586 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -18,8 +18,6 @@
 #include <sys/prctl.h>
 #include <sys/resource.h>
 
-#include <pdx/default_transport/service_dispatcher.h>
-
 #include <functional>
 
 #include "DisplayHardware/ComposerHal.h"
@@ -66,9 +64,6 @@
 
   ALOGI("Starting up VrFlinger...");
 
-  setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
-  set_sched_policy(0, SP_FOREGROUND);
-
   // We need to be able to create endpoints with full perms.
   umask(0000);
 
@@ -76,7 +71,7 @@
 
   request_display_callback_ = request_display_callback;
 
-  dispatcher_ = android::pdx::default_transport::ServiceDispatcher::Create();
+  dispatcher_ = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher.");
 
   display_service_ =
@@ -102,6 +97,9 @@
     prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
     ALOGI("Entering message loop.");
 
+    setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
+    set_sched_policy(0, SP_FOREGROUND);
+
     int ret = dispatcher_->EnterDispatchLoop();
     if (ret < 0) {
       ALOGE("Dispatch loop exited because: %s\n", strerror(-ret));
@@ -135,10 +133,6 @@
   display_service_->SeizeDisplayOwnership();
 }
 
-void VrFlinger::OnHardwareComposerRefresh() {
-  display_service_->OnHardwareComposerRefresh();
-}
-
 std::string VrFlinger::Dump() {
   // TODO(karthikrs): Add more state information here.
   return display_service_->DumpState(0/*unused*/);
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index 3098b43..fdeb899 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -110,6 +110,7 @@
 }
 
 pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) {
+  ATRACE_NAME("VSyncService::HandleMessage");
   switch (message.GetOp()) {
     case VSyncProtocol::Wait::Opcode:
       AddWaiter(message);
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
index d684ddc..bb25f1d 100644
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ b/libs/vr/libvrsensor/include/dvr/pose_client.h
@@ -157,6 +157,18 @@
 // @return Zero on success
 int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled);
 
+// Requests a burst of data samples from pose service. The data samples are
+// passed through a shared memory buffer obtained by calling
+// dvrPoseClientGetDataReader().
+//
+// @param DvrPoseDataCaptureRequest Parameters on how to capture data.
+// @return Zero on success.
+int dvrPoseClientDataCapture(DvrPoseClient* client,
+                             const DvrPoseDataCaptureRequest* request);
+
+// Destroys the write buffer queue for the given |data_type|.
+int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
index e4455f1..7bf1cd4 100644
--- a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
+++ b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
@@ -17,6 +17,9 @@
   DVR_POSE_GET_CONTROLLER_RING_BUFFER,
   DVR_POSE_LOG_CONTROLLER,
   DVR_POSE_SENSORS_ENABLE,
+  DVR_POSE_GET_TANGO_READER,
+  DVR_POSE_DATA_CAPTURE,
+  DVR_POSE_TANGO_READER_DESTROY,
 };
 
 #ifdef __cplusplus
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
new file mode 100644
index 0000000..39592bb
--- /dev/null
+++ b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
@@ -0,0 +1,19 @@
+#ifndef ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
+#define ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
+
+#include <private/dvr/buffer_hub_queue_client.h>
+
+using android::dvr::ConsumerQueue;
+
+typedef struct DvrPoseClient DvrPoseClient;
+
+namespace android {
+namespace dvr {
+
+int dvrPoseClientGetDataReaderHandle(DvrPoseClient *client, uint64_t data_type,
+                                     ConsumerQueue **queue_out);
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index 4ddf1f3..4acc085 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -9,23 +9,24 @@
 #include <pdx/default_transport/client_channel_factory.h>
 #include <pdx/file_handle.h>
 #include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/buffer_hub_queue_client.h>
 #include <private/dvr/display_client.h>
 #include <private/dvr/pose-ipc.h>
 #include <private/dvr/shared_buffer_helpers.h>
 
+using android::dvr::ConsumerQueue;
 using android::pdx::LocalHandle;
 using android::pdx::LocalChannelHandle;
 using android::pdx::Status;
 using android::pdx::Transaction;
 
-#define arraysize(x) (static_cast<int32_t>(std::extent<decltype(x)>::value))
-
 namespace android {
 namespace dvr {
 namespace {
 
 typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing;
 
+constexpr static int32_t MAX_CONTROLLERS = 2;
 }  // namespace
 
 // PoseClient is a remote interface to the pose service in sensord.
@@ -81,7 +82,7 @@
 
   int GetControllerPose(int32_t controller_id, uint32_t vsync_count,
                         DvrPoseAsync* out_pose) {
-    if (controller_id < 0 || controller_id >= arraysize(controllers_)) {
+    if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) {
       return -EINVAL;
     }
     if (!controllers_[controller_id].mapped_pose_buffer) {
@@ -140,6 +141,44 @@
     return ReturnStatusOrError(status);
   }
 
+  int GetTangoReaderHandle(uint64_t data_type, ConsumerQueue** queue_out) {
+    // Get buffer.
+    Transaction trans{*this};
+    Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>(
+        DVR_POSE_GET_TANGO_READER, &data_type, sizeof(data_type), nullptr, 0);
+
+    if (!status) {
+      ALOGE("PoseClient GetTangoReaderHandle() failed because: %s",
+            status.GetErrorMessage().c_str());
+      *queue_out = nullptr;
+      return -status.error();
+    }
+
+    std::unique_ptr<ConsumerQueue> consumer_queue =
+        ConsumerQueue::Import(status.take());
+    *queue_out = consumer_queue.release();
+    return 0;
+  }
+
+  int DataCapture(const DvrPoseDataCaptureRequest* request) {
+    Transaction trans{*this};
+    Status<int> status = trans.Send<int>(DVR_POSE_DATA_CAPTURE, request,
+                                         sizeof(*request), nullptr, 0);
+    ALOGE_IF(!status, "PoseClient DataCapture() failed because: %s\n",
+             status.GetErrorMessage().c_str());
+    return ReturnStatusOrError(status);
+  }
+
+  int DataReaderDestroy(uint64_t data_type) {
+    Transaction trans{*this};
+    Status<int> status = trans.Send<int>(DVR_POSE_TANGO_READER_DESTROY,
+                                         &data_type, sizeof(data_type), nullptr,
+                                         0);
+    ALOGE_IF(!status, "PoseClient DataReaderDestroy() failed because: %s\n",
+             status.GetErrorMessage().c_str());
+    return ReturnStatusOrError(status);
+  }
+
   // Enables or disables all pose processing from sensors
   int EnableSensors(bool enabled) {
     Transaction trans{*this};
@@ -166,7 +205,7 @@
   }
 
   int GetControllerRingBuffer(int32_t controller_id) {
-    if (controller_id < 0 || controller_id >= arraysize(controllers_)) {
+    if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) {
       return -EINVAL;
     }
     ControllerClientState& client_state = controllers_[controller_id];
@@ -254,9 +293,14 @@
     std::unique_ptr<BufferConsumer> pose_buffer;
     const DvrPoseAsync* mapped_pose_buffer = nullptr;
   };
-  ControllerClientState controllers_[2];
+  ControllerClientState controllers_[MAX_CONTROLLERS];
 };
 
+int dvrPoseClientGetDataReaderHandle(DvrPoseClient* client, uint64_t type,
+                                     ConsumerQueue** queue_out) {
+  return PoseClient::FromC(client)->GetTangoReaderHandle(type, queue_out);
+}
+
 }  // namespace dvr
 }  // namespace android
 
@@ -308,9 +352,17 @@
   return PoseClient::FromC(client)->GetMode(mode);
 }
 
-
 int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) {
   return PoseClient::FromC(client)->EnableSensors(enabled);
 }
 
+int dvrPoseClientDataCapture(DvrPoseClient* client,
+                             const DvrPoseDataCaptureRequest* request) {
+  return PoseClient::FromC(client)->DataCapture(request);
+}
+
+int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type) {
+  return PoseClient::FromC(client)->DataReaderDestroy(data_type);
+}
+
 }  // extern "C"
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index c4073a9..466768a 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -534,11 +534,6 @@
 #endif
 #endif /* EGL_ANDROID_presentation_time */
 
-#ifndef EGL_KHR_no_config_context
-#define EGL_KHR_no_config_context 1
-#define EGL_NO_CONFIG_KHR                 EGL_CAST(EGLConfig,0)
-#endif /* EGL_KHR_no_config_context */
-
 #ifndef EGL_ANDROID_get_frame_timestamps
 #define EGL_ANDROID_get_frame_timestamps 1
 #define EGL_TIMESTAMPS_ANDROID 0x3430
diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp
index bf7aeb1..639f351 100644
--- a/opengl/tests/Android.bp
+++ b/opengl/tests/Android.bp
@@ -1,4 +1,19 @@
+
 subdirs = [
+    "angeles",
+    "configdump",
+    "EGLTest",
+    "fillrate",
+    "filter",
+    "finish",
+    "gl2_basic",
+    "gl2_copyTexImage",
+    "gl2_yuvtex",
+    "gl_basic",
+    "gl_perf",
+    "gl_yuvtex", // just renders magenta frame, broken?
+    "gralloc",
     "hwc",
     "lib",
 ]
+
diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk
index 92d223c..134854a 100644
--- a/opengl/tests/Android.mk
+++ b/opengl/tests/Android.mk
@@ -1,19 +1,4 @@
 dirs := \
-	angeles \
-	configdump \
-	EGLTest \
-	fillrate \
-	filter \
-	finish \
-	gl2_basic \
-	gl2_copyTexImage \
-	gl2_yuvtex \
-	gl_basic \
-	gl_perf \
-	gl_yuvtex \
-	gralloc \
-	include \
-	lib \
 	linetex \
 	swapinterval \
 	textures \
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
new file mode 100644
index 0000000..d85af81
--- /dev/null
+++ b/opengl/tests/EGLTest/Android.bp
@@ -0,0 +1,31 @@
+
+cc_test {
+
+    name: "EGL_test",
+
+    srcs: [
+        "egl_cache_test.cpp",
+        "EGL_test.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
+        "libEGL",
+        "libbase",
+        "libcutils",
+        "libbinder",
+        "libgui",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+
+    include_dirs: [
+        "bionic/libc/private",
+        "frameworks/native/opengl/libs",
+        "frameworks/native/opengl/libs/EGL",
+    ],
+
+}
diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk
deleted file mode 100644
index 5620496..0000000
--- a/opengl/tests/EGLTest/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := EGL_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-    egl_cache_test.cpp \
-    EGL_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	android.hardware.configstore@1.0 \
-	android.hardware.configstore-utils \
-	libEGL \
-	libcutils \
-	libbinder \
-	libhidlbase \
-	libhidltransport \
-	libutils \
-	libgui \
-	libbase \
-	liblog \
-
-LOCAL_C_INCLUDES := \
-    bionic/libc/private \
-    frameworks/native/opengl/libs \
-    frameworks/native/opengl/libs/EGL \
-
-# gold in binutils 2.22 will warn about the usage of mktemp
-LOCAL_LDFLAGS += -Wl,--no-fatal-warnings
-
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 62e6bd3..b67a053 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -200,6 +200,7 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
@@ -285,6 +286,7 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
@@ -370,6 +372,7 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
@@ -431,9 +434,10 @@
     EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
 }
 
-TEST_F(EGLTest, EGL_KHR_no_config_context) {
+TEST_F(EGLTest, EGLNoConfigContext) {
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
@@ -471,6 +475,7 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp
new file mode 100644
index 0000000..bbbc447
--- /dev/null
+++ b/opengl/tests/angeles/Android.bp
@@ -0,0 +1,22 @@
+// Copyright 2006 The Android Open Source Project
+
+cc_test {
+    name: "angeles",
+
+    srcs: [
+        "app-linux.cpp",
+        "demo.c",
+    ],
+
+    gtest: false,
+
+    shared_libs: [
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+
+    static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
deleted file mode 100644
index c78224e..0000000
--- a/opengl/tests/angeles/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2006 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm
-LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui libgui libutils
-LOCAL_STATIC_LIBRARIES += libglTest
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-LOCAL_MODULE:= angeles
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/angeles/demo.c b/opengl/tests/angeles/demo.c
index 39d871e..30c3202 100644
--- a/opengl/tests/angeles/demo.c
+++ b/opengl/tests/angeles/demo.c
@@ -462,7 +462,7 @@
 // Called from the app framework.
 void appInit()
 {
-    int a;
+    unsigned int a;
 
     glEnable(GL_NORMALIZE);
     glEnable(GL_DEPTH_TEST);
@@ -492,7 +492,7 @@
 // Called from the app framework.
 void appDeinit()
 {
-    int a;
+    unsigned int a;
     for (a = 0; a < SUPERSHAPE_COUNT; ++a)
         freeGLObject(sSuperShapeObjects[a]);
     freeGLObject(sGroundPlane);
diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp
new file mode 100644
index 0000000..c46477c
--- /dev/null
+++ b/opengl/tests/configdump/Android.bp
@@ -0,0 +1,13 @@
+cc_test {
+    name: "test-opengl-configdump",
+
+    gtest: false,
+
+    srcs: ["configdump.cpp"],
+
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+    ],
+}
diff --git a/opengl/tests/configdump/Android.mk b/opengl/tests/configdump/Android.mk
deleted file mode 100644
index 3f7c915..0000000
--- a/opengl/tests/configdump/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	configdump.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-    libEGL \
-    libGLESv1_CM
-
-LOCAL_MODULE:= test-opengl-configdump
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/configdump/configdump.cpp b/opengl/tests/configdump/configdump.cpp
index c423105..a4bb879 100644
--- a/opengl/tests/configdump/configdump.cpp
+++ b/opengl/tests/configdump/configdump.cpp
@@ -78,7 +78,7 @@
 
     for (EGLint i=0 ; i<n ; i++) {
         printf("EGLConfig[%d]\n", i);
-        for (int attr = 0 ; attr<sizeof(attributes)/sizeof(Attribute) ; attr++) {
+        for (unsigned attr = 0 ; attr<sizeof(attributes)/sizeof(Attribute) ; attr++) {
             EGLint value;
             eglGetConfigAttrib(dpy, configs[i], attributes[attr].attribute, &value);
             printf("\t%-32s: %10d (0x%08x)\n", attributes[attr].name, value, value);
diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp
new file mode 100644
index 0000000..543f1e3
--- /dev/null
+++ b/opengl/tests/fillrate/Android.bp
@@ -0,0 +1,18 @@
+cc_test {
+    name: "test-opengl-fillrate",
+
+    srcs: ["fillrate.cpp"],
+
+    gtest: false,
+
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+    ],
+
+    static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk
deleted file mode 100644
index 21ff52a..0000000
--- a/opengl/tests/fillrate/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	fillrate.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-    libEGL \
-    libGLESv1_CM \
-    libui \
-    libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-fillrate
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
index 2db63d7..a42f3f2 100644
--- a/opengl/tests/fillrate/fillrate.cpp
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -30,7 +30,7 @@
 
 using namespace android;
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     EGLint configAttribs[] = {
          EGL_DEPTH_SIZE, 0,
@@ -153,7 +153,7 @@
 
      for (int c=1, j=0 ; c<32 ; c++, j++) {
          nsecs_t t = times[j];
-         printf("%lld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
+         printf("%ld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
      }
 
 
diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp
new file mode 100644
index 0000000..5f925c8
--- /dev/null
+++ b/opengl/tests/filter/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+    name: "test-opengl-filter",
+
+    srcs: ["filter.cpp"],
+
+    gtest: false,
+
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+
+    static_libs: ["libglTest"],
+
+    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
deleted file mode 100644
index 4cf9c96..0000000
--- a/opengl/tests/filter/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	filter.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-    libEGL \
-    libGLESv1_CM \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-filter
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp
new file mode 100644
index 0000000..fb5671d
--- /dev/null
+++ b/opengl/tests/finish/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+    name: "test-opengl-finish",
+
+    srcs: ["finish.cpp"],
+
+    gtest: false,
+
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+    ],
+
+    static_libs: ["libglTest"],
+
+    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
deleted file mode 100644
index 0b9b7ea..0000000
--- a/opengl/tests/finish/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	finish.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-    libEGL \
-    libGLESv1_CM \
-    libui \
-    libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-finish
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp
index ea3a60f..ab955fe 100644
--- a/opengl/tests/finish/finish.cpp
+++ b/opengl/tests/finish/finish.cpp
@@ -31,7 +31,7 @@
 
 using namespace android;
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     EGLint configAttribs[] = {
          EGL_DEPTH_SIZE, 0,
diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp
new file mode 100644
index 0000000..7403271
--- /dev/null
+++ b/opengl/tests/gl2_basic/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+    name: "test-opengl-gl2_basic",
+
+    srcs: ["gl2_basic.cpp"],
+
+    gtest: false,
+
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+
+    static_libs: ["libglTest"],
+
+    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/gl2_basic/Android.mk b/opengl/tests/gl2_basic/Android.mk
deleted file mode 100644
index 520395c..0000000
--- a/opengl/tests/gl2_basic/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	gl2_basic.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-    libEGL \
-    libGLESv2 \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl2_basic
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp
new file mode 100644
index 0000000..51e269c
--- /dev/null
+++ b/opengl/tests/gl2_copyTexImage/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+    name: "test-opengl-gl2_copyTexImage",
+
+    srcs: ["gl2_copyTexImage.cpp"],
+
+    gtest: false,
+
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+
+    static_libs: ["libglTest"],
+
+    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/gl2_copyTexImage/Android.mk b/opengl/tests/gl2_copyTexImage/Android.mk
deleted file mode 100644
index ff43558..0000000
--- a/opengl/tests/gl2_copyTexImage/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	gl2_copyTexImage.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-    libEGL \
-    libGLESv2 \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl2_copyTexImage
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
index 405a3f0..e0aafa2 100644
--- a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
+++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
@@ -362,7 +362,7 @@
     return true;
 }
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
     EGLBoolean returnValue;
     EGLConfig myConfig = {0};
 
diff --git a/opengl/tests/gl2_jni/jni/gl_code.cpp b/opengl/tests/gl2_jni/jni/gl_code.cpp
index c4180d4..5af4f6b 100644
--- a/opengl/tests/gl2_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl2_jni/jni/gl_code.cpp
@@ -153,12 +153,12 @@
     JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj);
 };
 
-JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height)
+JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * /*env*/, jobject /*obj*/,  jint width, jint height)
 {
     setupGraphics(width, height);
 }
 
-JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * /*env*/, jobject /*obj*/)
 {
     renderFrame();
 }
diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp
new file mode 100644
index 0000000..613d678
--- /dev/null
+++ b/opengl/tests/gl2_yuvtex/Android.bp
@@ -0,0 +1,24 @@
+cc_test {
+    name: "test-opengl-gl2_yuvtex",
+
+    srcs: ["gl2_yuvtex.cpp"],
+
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libutils",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+
+    gtest: false,
+
+    static_libs: ["libglTest"],
+
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+}
diff --git a/opengl/tests/gl2_yuvtex/Android.mk b/opengl/tests/gl2_yuvtex/Android.mk
deleted file mode 100644
index 42cf771..0000000
--- a/opengl/tests/gl2_yuvtex/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	gl2_yuvtex.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libEGL \
-    libGLESv2 \
-    libutils \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl2_yuvtex
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp
new file mode 100644
index 0000000..881d8ce
--- /dev/null
+++ b/opengl/tests/gl_basic/Android.bp
@@ -0,0 +1,18 @@
+cc_test {
+    name: "test-opengl-gl_basic",
+
+    srcs: ["gl_basic.cpp"],
+
+    gtest: false,
+
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+
+    static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/gl_basic/Android.mk b/opengl/tests/gl_basic/Android.mk
deleted file mode 100644
index 7f2259e..0000000
--- a/opengl/tests/gl_basic/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	gl_basic.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-    libEGL \
-    libGLESv1_CM \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl_basic
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp
index e50d88f..0b663f7 100644
--- a/opengl/tests/gl_basic/gl_basic.cpp
+++ b/opengl/tests/gl_basic/gl_basic.cpp
@@ -189,7 +189,7 @@
     return true;
 }
 
-int main(int argc, char **argv)
+int main(int /*argc*/, char **/*argv*/)
 {
     int q;
     int start, end;
diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp
index 48944e0..3aa8adb 100644
--- a/opengl/tests/gl_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl_jni/jni/gl_code.cpp
@@ -140,13 +140,13 @@
     JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj);
 };
 
-JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj,  jint width, jint height)
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * /*env*/, jobject /*obj*/,  jint width, jint height)
 {
     init_scene(width, height);
     create_texture();
 }
 
-JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * /*env*/, jobject /*obj*/)
 {
     const GLfloat vertices[] = {
             -1,  -1,  0,
@@ -177,7 +177,7 @@
     glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, quadIndices);
 }
 
-JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * /*env*/, jobject /*obj*/)
 {
     background = 1.0f - background;
 }
diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp
new file mode 100644
index 0000000..0ffb121
--- /dev/null
+++ b/opengl/tests/gl_perf/Android.bp
@@ -0,0 +1,24 @@
+cc_test {
+    name: "test-opengl-gl2_perf",
+
+    srcs: [
+        "gl2_perf.cpp",
+        "filltest.cpp",
+    ],
+
+    gtest: false,
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libEGL",
+        "libGLESv2",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+
+    static_libs: ["libglTest"],
+
+    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+}
diff --git a/opengl/tests/gl_perf/Android.mk b/opengl/tests/gl_perf/Android.mk
deleted file mode 100644
index 9a93fab..0000000
--- a/opengl/tests/gl_perf/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	gl2_perf.cpp \
-	filltest.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-    libEGL \
-    libGLESv2 \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl2_perf
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp
index 35df84f..2998864 100644
--- a/opengl/tests/gl_perf/gl2_perf.cpp
+++ b/opengl/tests/gl_perf/gl2_perf.cpp
@@ -56,7 +56,7 @@
 static EGLDisplay dpy;
 static EGLSurface surface;
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
     EGLBoolean returnValue;
     EGLConfig myConfig = {0};
 
diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp
index 946ee07..0cb594a 100644
--- a/opengl/tests/gl_perfapp/jni/gl_code.cpp
+++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp
@@ -61,7 +61,7 @@
     JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj);
 };
 
-JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj,  jint width, jint height)
+JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * /*env*/, jobject /*obj*/,  jint width, jint height)
 {
     gWidth = width;
     gHeight = height;
@@ -87,7 +87,7 @@
     }
 }
 
-JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * /*env*/, jobject /*obj*/)
 {
     if (! done) {
         if (stateClock > 0 && ((stateClock & 1) == 0)) {
diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp
new file mode 100644
index 0000000..b6be327
--- /dev/null
+++ b/opengl/tests/gl_yuvtex/Android.bp
@@ -0,0 +1,23 @@
+cc_test {
+    name: "test-opengl-gl_yuvtex",
+
+    srcs: ["gl_yuvtex.cpp"],
+
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libutils",
+        "libui",
+        "libgui",
+    ],
+
+    gtest: false,
+
+    static_libs: ["libglTest"],
+
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+}
diff --git a/opengl/tests/gl_yuvtex/Android.mk b/opengl/tests/gl_yuvtex/Android.mk
deleted file mode 100644
index 7f2020a..0000000
--- a/opengl/tests/gl_yuvtex/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	gl_yuvtex.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libEGL \
-    libGLESv1_CM \
-    libutils \
-    libui \
-    libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-gl_yuvtex
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
index fad26a6..7ef3f4e 100644
--- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
+++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
@@ -90,7 +90,7 @@
 static sp<GraphicBuffer> yuvTexBuffer;
 static GLuint yuvTex;
 
-bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) {
+static bool setupYuvTexSurface(EGLDisplay dpy) {
     int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1;
     int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1;
     yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat,
@@ -298,7 +298,7 @@
     printGLString("Renderer", GL_RENDERER);
     printGLString("Extensions", GL_EXTENSIONS);
 
-    if(!setupYuvTexSurface(dpy, context)) {
+    if(!setupYuvTexSurface(dpy)) {
         fprintf(stderr, "Could not set up texture surface.\n");
         return 1;
     }
diff --git a/opengl/tests/gldual/jni/gl_code.cpp b/opengl/tests/gldual/jni/gl_code.cpp
index 3b11400..90d150b 100644
--- a/opengl/tests/gldual/jni/gl_code.cpp
+++ b/opengl/tests/gldual/jni/gl_code.cpp
@@ -153,12 +153,12 @@
     JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj);
 };
 
-JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * env, jobject obj, jint width, jint height)

+JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * /*env*/, jobject /*obj*/, jint width, jint height)

 {
     setupGraphics(width, height);
 }
 
-JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * /*env*/, jobject /*obj*/)
 {
     renderFrame();
 }
diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp
new file mode 100644
index 0000000..414c804
--- /dev/null
+++ b/opengl/tests/gralloc/Android.bp
@@ -0,0 +1,13 @@
+cc_test {
+    name: "test-opengl-gralloc",
+
+    srcs: ["gralloc.cpp"],
+
+    gtest: false,
+
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "libui",
+    ],
+}
diff --git a/opengl/tests/gralloc/Android.mk b/opengl/tests/gralloc/Android.mk
deleted file mode 100644
index d43c39a..0000000
--- a/opengl/tests/gralloc/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    gralloc.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libutils \
-    libui
-
-LOCAL_MODULE:= test-opengl-gralloc
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gralloc/gralloc.cpp b/opengl/tests/gralloc/gralloc.cpp
index 8987040..29e0882 100644
--- a/opengl/tests/gralloc/gralloc.cpp
+++ b/opengl/tests/gralloc/gralloc.cpp
@@ -37,7 +37,7 @@
     return d;
 }
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     size_t size = 128*256*4;
     void* temp = malloc(size);
diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp
index 425f374..55f058f 100644
--- a/opengl/tests/hwc/Android.bp
+++ b/opengl/tests/hwc/Android.bp
@@ -55,6 +55,8 @@
         "libnativewindow"
     ],
 
+    gtest: false,
+
     static_libs: [
         "libglTest",
         "libhwcTest",
diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp
index 69e56ff..5956366 100644
--- a/opengl/tests/hwc/hwcRects.cpp
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -170,7 +170,7 @@
 static EGLint width, height;
 
 // Function prototypes
-static Rectangle parseRect(string rectStr);
+static Rectangle parseRect(const string& rectStr);
 void init(void);
 void printSyntax(const char *cmd);
 
@@ -358,7 +358,7 @@
 
 // Parse string description of rectangle and add it to list of rectangles
 // to be rendered.
-static Rectangle parseRect(string rectStr)
+static Rectangle parseRect(const string& rectStr)
 {
     int rv;
     string str;
diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp
index 5ad695b..cdc051b 100644
--- a/opengl/tests/linetex/linetex.cpp
+++ b/opengl/tests/linetex/linetex.cpp
@@ -29,7 +29,7 @@
 
 using namespace android;
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     EGLint configAttribs[] = {
          EGL_DEPTH_SIZE, 0,
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
index 3a8a8a1..c4261e6 100644
--- a/opengl/tests/swapinterval/swapinterval.cpp
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -28,7 +28,7 @@
 
 using namespace android;
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     EGLint configAttribs[] = {
             EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp
index 1e55db0..7be942a 100644
--- a/opengl/tests/textures/textures.cpp
+++ b/opengl/tests/textures/textures.cpp
@@ -27,7 +27,7 @@
 
 using namespace android;
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     EGLint configAttribs[] = {
          EGL_DEPTH_SIZE, 0,
diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp
index e441bda..4c7265b 100644
--- a/services/batteryservice/Android.bp
+++ b/services/batteryservice/Android.bp
@@ -1,3 +1,11 @@
+cc_library_headers {
+    name: "libbatteryservice_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    header_libs: ["libbinder_headers"],
+    export_header_lib_headers: ["libbinder_headers"],
+}
+
 cc_library {
     name: "libbatteryservice",
 
@@ -8,6 +16,9 @@
         "IBatteryPropertiesRegistrar.cpp",
     ],
 
+    header_libs: ["libbatteryservice_headers"],
+    export_header_lib_headers: ["libbatteryservice_headers"],
+
     shared_libs: [
         "libutils",
         "libbinder",
@@ -19,4 +30,4 @@
         "-Wunused",
         "-Wunreachable-code",
     ],
-}
\ No newline at end of file
+}
diff --git a/include/batteryservice/BatteryService.h b/services/batteryservice/include/batteryservice/BatteryService.h
similarity index 100%
rename from include/batteryservice/BatteryService.h
rename to services/batteryservice/include/batteryservice/BatteryService.h
diff --git a/include/batteryservice/BatteryServiceConstants.h b/services/batteryservice/include/batteryservice/BatteryServiceConstants.h
similarity index 100%
rename from include/batteryservice/BatteryServiceConstants.h
rename to services/batteryservice/include/batteryservice/BatteryServiceConstants.h
diff --git a/include/batteryservice/IBatteryPropertiesListener.h b/services/batteryservice/include/batteryservice/IBatteryPropertiesListener.h
similarity index 100%
rename from include/batteryservice/IBatteryPropertiesListener.h
rename to services/batteryservice/include/batteryservice/IBatteryPropertiesListener.h
diff --git a/include/batteryservice/IBatteryPropertiesRegistrar.h b/services/batteryservice/include/batteryservice/IBatteryPropertiesRegistrar.h
similarity index 100%
rename from include/batteryservice/IBatteryPropertiesRegistrar.h
rename to services/batteryservice/include/batteryservice/IBatteryPropertiesRegistrar.h
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index cc81a29..d4266f6 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -147,7 +147,33 @@
 static const size_t keyCodeRotationMapSize =
         sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
 
+static int32_t rotateStemKey(int32_t value, int32_t orientation,
+        const int32_t map[][2], size_t mapSize) {
+    if (orientation == DISPLAY_ORIENTATION_180) {
+        for (size_t i = 0; i < mapSize; i++) {
+            if (value == map[i][0]) {
+                return map[i][1];
+            }
+        }
+    }
+    return value;
+}
+
+// The mapping can be defined using input device configuration properties keyboard.rotated.stem_X
+static int32_t stemKeyRotationMap[][2] = {
+        // key codes enumerated with the original (unrotated) key first
+        // no rotation,           180 degree rotation
+        { AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY },
+        { AKEYCODE_STEM_1,       AKEYCODE_STEM_1 },
+        { AKEYCODE_STEM_2,       AKEYCODE_STEM_2 },
+        { AKEYCODE_STEM_3,       AKEYCODE_STEM_3 },
+};
+static const size_t stemKeyRotationMapSize =
+        sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]);
+
 static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
+    keyCode = rotateStemKey(keyCode, orientation,
+            stemKeyRotationMap, stemKeyRotationMapSize);
     return rotateValueUsingRotationMap(keyCode, orientation,
             keyCodeRotationMap, keyCodeRotationMapSize);
 }
@@ -231,7 +257,7 @@
         const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
     const DisplayViewport* viewport = NULL;
     if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != NULL) {
-        for (DisplayViewport currentViewport : mVirtualDisplays) {
+        for (const DisplayViewport& currentViewport : mVirtualDisplays) {
             if (currentViewport.uniqueId == *uniqueDisplayId) {
                 viewport = &currentViewport;
                 break;
@@ -2260,18 +2286,36 @@
     }
 }
 
+static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const *property) {
+    int32_t mapped = 0;
+    if (config.tryGetProperty(String8(property), mapped) && mapped > 0) {
+        for (size_t i = 0; i < stemKeyRotationMapSize; i++) {
+            if (stemKeyRotationMap[i][0] == keyCode) {
+                stemKeyRotationMap[i][1] = mapped;
+                return;
+            }
+        }
+    }
+}
+
 void KeyboardInputMapper::configureParameters() {
     mParameters.orientationAware = false;
-    getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
+    const PropertyMap& config = getDevice()->getConfiguration();
+    config.tryGetProperty(String8("keyboard.orientationAware"),
             mParameters.orientationAware);
 
     mParameters.hasAssociatedDisplay = false;
     if (mParameters.orientationAware) {
         mParameters.hasAssociatedDisplay = true;
+
+        mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary");
+        mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1");
+        mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2");
+        mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3");
     }
 
     mParameters.handlesKeyRepeat = false;
-    getDevice()->getConfiguration().tryGetProperty(String8("keyboard.handlesKeyRepeat"),
+    config.tryGetProperty(String8("keyboard.handlesKeyRepeat"),
             mParameters.handlesKeyRepeat);
 }
 
@@ -2926,7 +2970,7 @@
 // --- RotaryEncoderInputMapper ---
 
 RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) :
-        InputMapper(device) {
+        InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) {
     mSource = AINPUT_SOURCE_ROTARY_ENCODER;
 }
 
@@ -2968,6 +3012,14 @@
     if (!changes) {
         mRotaryEncoderScrollAccumulator.configure(getDevice());
     }
+    if (!changes || (InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+        DisplayViewport v;
+        if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
+            mOrientation = v.orientation;
+        } else {
+            mOrientation = DISPLAY_ORIENTATION_0;
+        }
+    }
 }
 
 void RotaryEncoderInputMapper::reset(nsecs_t when) {
@@ -3005,6 +3057,10 @@
         policyFlags |= POLICY_FLAG_WAKE;
     }
 
+    if (mOrientation == DISPLAY_ORIENTATION_180) {
+        scroll = -scroll;
+    }
+
     // Send motion event.
     if (scrolled) {
         int32_t metaState = mContext->getGlobalMetaState();
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index c4f786a..a6b9798 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1227,6 +1227,7 @@
 
     int32_t mSource;
     float mScalingFactor;
+    int32_t mOrientation;
 
     void sync(nsecs_t when);
 };
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index b54752b..3ae7972 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -49,7 +49,8 @@
             || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
             || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
             || layoutParamsType == TYPE_DOCK_DIVIDER
-            || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY;
+            || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
+            || layoutParamsType == TYPE_INPUT_CONSUMER;
 }
 
 bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 610290b..9eb2798 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -101,6 +101,7 @@
         TYPE_NAVIGATION_BAR     = FIRST_SYSTEM_WINDOW+19,
         TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
         TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
+        TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22,
         TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
         TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
         TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS
deleted file mode 100644
index 6a38a1f..0000000
--- a/services/sensorservice/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-ashutoshj@google.com
-pengxu@google.com
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index fdb69d3..535d0db 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -217,13 +217,8 @@
 }
 
 void SensorDevice::autoDisable(void *ident, int handle) {
+    Info& info( mActivationCount.editValueFor(handle) );
     Mutex::Autolock _l(mLock);
-    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
-    if (activationIndex < 0) {
-        ALOGW("Handle %d cannot be found in activation record", handle);
-        return;
-    }
-    Info& info(mActivationCount.editValueAt(activationIndex));
     info.removeBatchParamsForIdent(ident);
 }
 
@@ -234,12 +229,7 @@
     bool actuateHardware = false;
 
     Mutex::Autolock _l(mLock);
-    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
-    if (activationIndex < 0) {
-        ALOGW("Handle %d cannot be found in activation record", handle);
-        return BAD_VALUE;
-    }
-    Info& info(mActivationCount.editValueAt(activationIndex));
+    Info& info( mActivationCount.editValueFor(handle) );
 
     ALOGD_IF(DEBUG_CONNECTIONS,
              "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
@@ -333,12 +323,7 @@
              ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
 
     Mutex::Autolock _l(mLock);
-    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
-    if (activationIndex < 0) {
-        ALOGW("Handle %d cannot be found in activation record", handle);
-        return BAD_VALUE;
-    }
-    Info& info(mActivationCount.editValueAt(activationIndex));
+    Info& info(mActivationCount.editValueFor(handle));
 
     if (info.batchParams.indexOfKey(ident) < 0) {
         BatchParams params(samplingPeriodNs, maxBatchReportLatencyNs);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index cc93105..4775e4e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -2,3 +2,5 @@
     name: "libsurfaceflingerincludes",
     export_include_dirs: ["."],
 }
+
+subdirs = ["tests/fakehwc"]
\ No newline at end of file
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index ea04839..bef12ea 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -30,7 +30,7 @@
 #include <utils/Trace.h>
 #include <utils/Vector.h>
 
-#include <ui/Fence.h>
+#include <ui/FenceTime.h>
 
 #include "DispSync.h"
 #include "SurfaceFlinger.h"
@@ -421,25 +421,13 @@
     resetErrorLocked();
 }
 
-bool DispSync::addPresentFence(const sp<Fence>& fence) {
+bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
     Mutex::Autolock lock(mMutex);
 
-    mPresentFences[mPresentSampleOffset] = fence;
-    mPresentTimes[mPresentSampleOffset] = 0;
+    mPresentFences[mPresentSampleOffset] = fenceTime;
     mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES;
     mNumResyncSamplesSincePresent = 0;
 
-    for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        const sp<Fence>& f(mPresentFences[i]);
-        if (f != NULL) {
-            nsecs_t t = f->getSignalTime();
-            if (t < INT64_MAX) {
-                mPresentFences[i].clear();
-                mPresentTimes[i] = t + mPresentTimeOffset;
-            }
-        }
-    }
-
     updateErrorLocked();
 
     return !mModelUpdated || mError > kErrorThreshold;
@@ -604,21 +592,39 @@
     nsecs_t sqErrSum = 0;
 
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        nsecs_t sample = mPresentTimes[i] - mReferenceTime;
-        if (sample > mPhase) {
-            nsecs_t sampleErr = (sample - mPhase) % period;
-            if (sampleErr > period / 2) {
-                sampleErr -= period;
-            }
-            sqErrSum += sampleErr * sampleErr;
-            numErrSamples++;
+        // Only check for the cached value of signal time to avoid unecessary
+        // syscalls. It is the responsibility of the DispSync owner to
+        // call getSignalTime() periodically so the cache is updated when the
+        // fence signals.
+        nsecs_t time = mPresentFences[i]->getCachedSignalTime();
+        if (time == Fence::SIGNAL_TIME_PENDING ||
+                time == Fence::SIGNAL_TIME_INVALID) {
+            continue;
         }
+
+        nsecs_t sample = time - mReferenceTime;
+        if (sample <= mPhase) {
+            continue;
+        }
+
+        nsecs_t sampleErr = (sample - mPhase) % period;
+        if (sampleErr > period / 2) {
+            sampleErr -= period;
+        }
+        sqErrSum += sampleErr * sampleErr;
+        numErrSamples++;
     }
 
     if (numErrSamples > 0) {
         mError = sqErrSum / numErrSamples;
+        mZeroErrSamplesCount = 0;
     } else {
         mError = 0;
+        // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
+        mZeroErrSamplesCount++;
+        ALOGE_IF(
+                (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
+                "No present times for model error.");
     }
 
     if (kTraceDetailedInfo) {
@@ -629,9 +635,9 @@
 void DispSync::resetErrorLocked() {
     mPresentSampleOffset = 0;
     mError = 0;
+    mZeroErrSamplesCount = 0;
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        mPresentFences[i].clear();
-        mPresentTimes[i] = 0;
+        mPresentFences[i] = FenceTime::NO_FENCE;
     }
 }
 
@@ -670,19 +676,19 @@
         previous = sampleTime;
     }
 
-    result.appendFormat("mPresentFences / mPresentTimes [%d]:\n",
+    result.appendFormat("mPresentFences [%d]:\n",
             NUM_PRESENT_SAMPLES);
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    previous = 0;
+    previous = Fence::SIGNAL_TIME_INVALID;
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
         size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES;
-        bool signaled = mPresentFences[idx] == NULL;
-        nsecs_t presentTime = mPresentTimes[idx];
-        if (!signaled) {
+        nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
+        if (presentTime == Fence::SIGNAL_TIME_PENDING) {
             result.appendFormat("  [unsignaled fence]\n");
-        } else if (presentTime == 0) {
-            result.appendFormat("  0\n");
-        } else if (previous == 0) {
+        } else if(presentTime == Fence::SIGNAL_TIME_INVALID) {
+            result.appendFormat("  [invalid fence]\n");
+        } else if (previous == Fence::SIGNAL_TIME_PENDING ||
+                previous == Fence::SIGNAL_TIME_INVALID) {
             result.appendFormat("  %" PRId64 "  (%.3f ms ago)\n", presentTime,
                     (now - presentTime) / 1000000.0);
         } else {
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 3c34fb0..880a24d 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -23,10 +23,14 @@
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 
+#include <ui/FenceTime.h>
+
+#include <memory>
+
 namespace android {
 
 class String8;
-class Fence;
+class FenceTime;
 class DispSyncThread;
 
 // DispSync maintains a model of the periodic hardware-based vsync events of a
@@ -69,7 +73,7 @@
     //
     // This method should be called with the retire fence from each HWComposer
     // set call that affects the display.
-    bool addPresentFence(const sp<Fence>& fence);
+    bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
 
     // The beginResync, addResyncSample, and endResync methods are used to re-
     // synchronize the DispSync's model to the hardware vsync events.  The re-
@@ -131,6 +135,7 @@
     enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 };
     enum { NUM_PRESENT_SAMPLES = 8 };
     enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
+    enum { ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT = 64 };
 
     const char* const mName;
 
@@ -148,9 +153,14 @@
 
     // mError is the computed model error.  It is based on the difference
     // between the estimated vsync event times and those observed in the
-    // mPresentTimes array.
+    // mPresentFences array.
     nsecs_t mError;
 
+    // mZeroErrSamplesCount keeps track of how many times in a row there were
+    // zero timestamps available in the mPresentFences array.
+    // Used to sanity check that we are able to calculate the model error.
+    size_t mZeroErrSamplesCount;
+
     // Whether we have updated the vsync event model since the last resync.
     bool mModelUpdated;
 
@@ -164,8 +174,8 @@
 
     // These member variables store information about the present fences used
     // to validate the currently computed model.
-    sp<Fence> mPresentFences[NUM_PRESENT_SAMPLES];
-    nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES];
+    std::shared_ptr<FenceTime>
+            mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE};
     size_t mPresentSampleOffset;
 
     int mRefreshSkipCount;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index fc60002..248ef53 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -65,7 +65,7 @@
 using namespace android::hardware::configstore::V1_0;
 
 static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
-        &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) == 3;
+        &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3;
 
 #if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
 // Dummy implementation in case it is missing.
@@ -134,9 +134,11 @@
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (config == EGL_NO_CONFIG) {
 #ifdef USE_HWC2
-        config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888);
+        config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888,
+                                               /*logConfig*/ false);
 #else
-        config = RenderEngine::chooseEglConfig(display, format);
+        config = RenderEngine::chooseEglConfig(display, format,
+                                               /*logConfig*/ false);
 #endif
     }
     eglSurface = eglCreateWindowSurface(display, config, window, NULL);
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index e34fa16..7d6d988 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -157,15 +157,11 @@
     write64(metadata.usage);
 }
 
-Composer::Composer(bool useVrComposer)
+Composer::Composer(const std::string& serviceName)
     : mWriter(kWriterInitialSize),
-      mIsUsingVrComposer(useVrComposer)
+      mIsUsingVrComposer(serviceName == std::string("vr"))
 {
-    if (mIsUsingVrComposer) {
-        mComposer = IComposer::getService("vr");
-    } else {
-        mComposer = IComposer::getService(); // use default name
-    }
+    mComposer = IComposer::getService(serviceName);
 
     if (mComposer == nullptr) {
         LOG_ALWAYS_FATAL("failed to get hwcomposer service");
@@ -219,6 +215,10 @@
     }
 }
 
+bool Composer::isRemote() {
+    return mClient->isRemote();
+}
+
 void Composer::resetCommands() {
     mWriter.reset();
 }
@@ -751,7 +751,7 @@
     }
 
     Error error = kDefaultError;
-    mClient->executeCommands(commandLength, commandHandles,
+    auto ret = mClient->executeCommands(commandLength, commandHandles,
             [&](const auto& tmpError, const auto& tmpOutChanged,
                 const auto& tmpOutLength, const auto& tmpOutHandles)
             {
@@ -784,6 +784,11 @@
                     error = Error::NO_RESOURCES;
                 }
             });
+    // executeCommands can fail because of out-of-fd and we do not want to
+    // abort() in that case
+    if (!ret.isOk()) {
+        ALOGE("executeCommands failed because of %s", ret.description().c_str());
+    }
 
     if (error == Error::NONE) {
         std::vector<CommandReader::CommandError> commandErrors =
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 96dd833..31a3c1d 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -136,13 +136,18 @@
 // Composer is a wrapper to IComposer, a proxy to server-side composer.
 class Composer {
 public:
-    Composer(bool useVrComposer);
+    Composer(const std::string& serviceName);
 
     std::vector<IComposer::Capability> getCapabilities();
     std::string dumpDebugInfo();
 
     void registerCallback(const sp<IComposerCallback>& callback);
 
+    // Returns true if the connected composer service is running in a remote
+    // process, false otherwise. This will return false if the service is
+    // configured in passthrough mode, for example.
+    bool isRemote();
+
     // Reset all pending commands in the command buffer. Useful if you want to
     // skip a frame but have already queued some commands.
     void resetCommands();
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 68d7a18..93c6d54 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -34,6 +34,7 @@
 #include <gui/BufferQueue.h>
 #include <gui/Surface.h>
 
+#include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
 
@@ -103,6 +104,7 @@
     sp<Fence> acquireFence(Fence::NO_FENCE);
     android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
     status_t result = nextBuffer(slot, buf, acquireFence, dataspace);
+    mDataSpace = dataspace;
     if (result != NO_ERROR) {
         ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
                 strerror(-result), result);
@@ -173,16 +175,17 @@
     mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
             &outSlot, &outBuffer);
     outDataspace = item.mDataSpace;
-#else
-    outBuffer = mCurrentBuffer;
-#endif
     status_t result =
             mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
     if (result != NO_ERROR) {
         ALOGE("error posting framebuffer: %d", result);
+        return result;
     }
+#else
+    outBuffer = mCurrentBuffer;
+#endif
 
-    return result;
+    return NO_ERROR;
 }
 
 #ifndef USE_HWC2
@@ -248,7 +251,10 @@
 #endif
 
 void FramebufferSurface::dumpAsString(String8& result) const {
-    ConsumerBase::dumpState(result);
+    Mutex::Autolock lock(mMutex);
+    result.appendFormat("FramebufferSurface: dataspace: %s(%d)\n",
+                        dataspaceDetails(mDataSpace).c_str(), mDataSpace);
+    ConsumerBase::dumpLocked(result, "");
 }
 
 void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 69a72d7..a1756ca 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -83,6 +83,13 @@
     // or the buffer is not associated with a slot.
     int mCurrentBufferSlot;
 
+    // mDataSpace is the dataspace of the current composition buffer for
+    // this FramebufferSurface. It will be 0 when HWC is doing the
+    // compositing. Otherwise it will display the dataspace of the buffer
+    // use for compositing which can change as wide-color content is
+    // on/off.
+    android_dataspace mDataSpace;
+
     // mCurrentBuffer is the current buffer or NULL to indicate that there is
     // no current buffer.
     sp<GraphicBuffer> mCurrentBuffer;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 270a732..78c0c85 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -33,45 +33,6 @@
 #include <algorithm>
 #include <inttypes.h>
 
-extern "C" {
-    static void hotplug_hook(hwc2_callback_data_t callbackData,
-            hwc2_display_t displayId, int32_t intConnected) {
-        auto device = static_cast<HWC2::Device*>(callbackData);
-        auto display = device->getDisplayById(displayId);
-        if (display) {
-            auto connected = static_cast<HWC2::Connection>(intConnected);
-            device->callHotplug(std::move(display), connected);
-        } else {
-            ALOGE("Hotplug callback called with unknown display %" PRIu64,
-                    displayId);
-        }
-    }
-
-    static void refresh_hook(hwc2_callback_data_t callbackData,
-            hwc2_display_t displayId) {
-        auto device = static_cast<HWC2::Device*>(callbackData);
-        auto display = device->getDisplayById(displayId);
-        if (display) {
-            device->callRefresh(std::move(display));
-        } else {
-            ALOGE("Refresh callback called with unknown display %" PRIu64,
-                    displayId);
-        }
-    }
-
-    static void vsync_hook(hwc2_callback_data_t callbackData,
-            hwc2_display_t displayId, int64_t timestamp) {
-        auto device = static_cast<HWC2::Device*>(callbackData);
-        auto display = device->getDisplayById(displayId);
-        if (display) {
-            device->callVsync(std::move(display), timestamp);
-        } else {
-            ALOGE("Vsync callback called with unknown display %" PRIu64,
-                    displayId);
-        }
-    }
-}
-
 using android::Fence;
 using android::FloatRect;
 using android::GraphicBuffer;
@@ -86,51 +47,78 @@
 
 namespace Hwc2 = android::Hwc2;
 
+namespace {
+
+class ComposerCallbackBridge : public Hwc2::IComposerCallback {
+public:
+    ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
+            : mCallback(callback), mSequenceId(sequenceId),
+              mHasPrimaryDisplay(false) {}
+
+    Return<void> onHotplug(Hwc2::Display display,
+                           IComposerCallback::Connection conn) override
+    {
+        HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
+        if (!mHasPrimaryDisplay) {
+            LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected,
+                    "Initial onHotplug callback should be "
+                    "primary display connected");
+            mHasPrimaryDisplay = true;
+            mCallback->onHotplugReceived(mSequenceId, display,
+                                         connection, true);
+        } else {
+            mCallback->onHotplugReceived(mSequenceId, display,
+                                         connection, false);
+        }
+        return Void();
+    }
+
+    Return<void> onRefresh(Hwc2::Display display) override
+    {
+        mCallback->onRefreshReceived(mSequenceId, display);
+        return Void();
+    }
+
+    Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
+    {
+        mCallback->onVsyncReceived(mSequenceId, display, timestamp);
+        return Void();
+    }
+
+    bool HasPrimaryDisplay() { return mHasPrimaryDisplay; }
+
+private:
+    ComposerCallback* mCallback;
+    int32_t mSequenceId;
+    bool mHasPrimaryDisplay;
+};
+
+} // namespace anonymous
+
+
 // Device methods
 
-Device::Device(bool useVrComposer)
-  : mComposer(std::make_unique<Hwc2::Composer>(useVrComposer)),
+Device::Device(const std::string& serviceName)
+  : mComposer(std::make_unique<Hwc2::Composer>(serviceName)),
     mCapabilities(),
     mDisplays(),
-    mHotplug(),
-    mPendingHotplugs(),
-    mRefresh(),
-    mPendingRefreshes(),
-    mVsync(),
-    mPendingVsyncs()
+    mRegisteredCallback(false)
 {
     loadCapabilities();
-    registerCallbacks();
 }
 
-Device::~Device()
-{
-    for (auto element : mDisplays) {
-        auto display = element.second.lock();
-        if (!display) {
-            ALOGE("~Device: Found a display (%" PRId64 " that has already been"
-                    " destroyed", element.first);
-            continue;
-        }
-
-        DisplayType displayType = HWC2::DisplayType::Invalid;
-        auto error = display->getType(&displayType);
-        if (error != Error::None) {
-            ALOGE("~Device: Failed to determine type of display %" PRIu64
-                    ": %s (%d)", display->getId(), to_string(error).c_str(),
-                    static_cast<int32_t>(error));
-            continue;
-        }
-
-        if (displayType == HWC2::DisplayType::Physical) {
-            error = display->setVsyncEnabled(HWC2::Vsync::Disable);
-            if (error != Error::None) {
-                ALOGE("~Device: Failed to disable vsync for display %" PRIu64
-                        ": %s (%d)", display->getId(), to_string(error).c_str(),
-                        static_cast<int32_t>(error));
-            }
-        }
+void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) {
+    if (mRegisteredCallback) {
+        ALOGW("Callback already registered. Ignored extra registration "
+                "attempt.");
+        return;
     }
+    mRegisteredCallback = true;
+    sp<ComposerCallbackBridge> callbackBridge(
+            new ComposerCallbackBridge(callback, sequenceId));
+    mComposer->registerCallback(callbackBridge);
+    LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(),
+            "Registered composer callback but didn't get primary display");
 }
 
 // Required by HWC2 device
@@ -146,7 +134,7 @@
 }
 
 Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
-        android_pixel_format_t* format, std::shared_ptr<Display>* outDisplay)
+        android_pixel_format_t* format, Display** outDisplay)
 {
     ALOGI("Creating virtual display");
 
@@ -159,104 +147,66 @@
         return error;
     }
 
-    ALOGI("Created virtual display");
+    auto display = std::make_unique<Display>(
+            *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual);
+    *outDisplay = display.get();
     *format = static_cast<android_pixel_format_t>(intFormat);
-    *outDisplay = getDisplayById(displayId);
-    if (!*outDisplay) {
-        ALOGE("Failed to get display by id");
-        return Error::BadDisplay;
-    }
-    (*outDisplay)->setConnected(true);
+    mDisplays.emplace(displayId, std::move(display));
+    ALOGI("Created virtual display");
     return Error::None;
 }
 
-void Device::registerHotplugCallback(HotplugCallback hotplug)
+void Device::destroyDisplay(hwc2_display_t displayId)
 {
-    ALOGV("registerHotplugCallback");
-    mHotplug = hotplug;
-    for (auto& pending : mPendingHotplugs) {
-        auto& display = pending.first;
-        auto connected = pending.second;
-        ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(),
-                to_string(connected).c_str());
-        mHotplug(std::move(display), connected);
-    }
+    ALOGI("Destroying display %" PRIu64, displayId);
+    mDisplays.erase(displayId);
 }
 
-void Device::registerRefreshCallback(RefreshCallback refresh)
-{
-    mRefresh = refresh;
-    for (auto& pending : mPendingRefreshes) {
-        mRefresh(std::move(pending));
-    }
-}
+void Device::onHotplug(hwc2_display_t displayId, Connection connection) {
+    if (connection == Connection::Connected) {
+        auto display = getDisplayById(displayId);
+        if (display) {
+            if (display->isConnected()) {
+                ALOGW("Attempt to hotplug connect display %" PRIu64
+                        " , which is already connected.", displayId);
+            } else {
+                display->setConnected(true);
+            }
+        } else {
+            DisplayType displayType;
+            auto intError = mComposer->getDisplayType(displayId,
+                    reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(
+                            &displayType));
+            auto error = static_cast<Error>(intError);
+            if (error != Error::None) {
+                ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). "
+                        "Aborting hotplug attempt.",
+                        displayId, to_string(error).c_str(), intError);
+                return;
+            }
 
-void Device::registerVsyncCallback(VsyncCallback vsync)
-{
-    mVsync = vsync;
-    for (auto& pending : mPendingVsyncs) {
-        auto& display = pending.first;
-        auto timestamp = pending.second;
-        mVsync(std::move(display), timestamp);
-    }
-}
-
-// For use by Device callbacks
-
-void Device::callHotplug(std::shared_ptr<Display> display, Connection connected)
-{
-    if (connected == Connection::Connected) {
-        if (!display->isConnected()) {
-            mComposer->setClientTargetSlotCount(display->getId());
-            display->loadConfigs();
-            display->setConnected(true);
+            auto newDisplay = std::make_unique<Display>(
+                    *mComposer.get(), mCapabilities, displayId, displayType);
+            mDisplays.emplace(displayId, std::move(newDisplay));
         }
-    } else {
-        display->setConnected(false);
-        mDisplays.erase(display->getId());
-    }
-
-    if (mHotplug) {
-        mHotplug(std::move(display), connected);
-    } else {
-        ALOGV("callHotplug called, but no valid callback registered, storing");
-        mPendingHotplugs.emplace_back(std::move(display), connected);
-    }
-}
-
-void Device::callRefresh(std::shared_ptr<Display> display)
-{
-    if (mRefresh) {
-        mRefresh(std::move(display));
-    } else {
-        ALOGV("callRefresh called, but no valid callback registered, storing");
-        mPendingRefreshes.emplace_back(std::move(display));
-    }
-}
-
-void Device::callVsync(std::shared_ptr<Display> display, nsecs_t timestamp)
-{
-    if (mVsync) {
-        mVsync(std::move(display), timestamp);
-    } else {
-        ALOGV("callVsync called, but no valid callback registered, storing");
-        mPendingVsyncs.emplace_back(std::move(display), timestamp);
+    } else if (connection == Connection::Disconnected) {
+        // The display will later be destroyed by a call to
+        // destroyDisplay(). For now we just mark it disconnected.
+        auto display = getDisplayById(displayId);
+        if (display) {
+            display->setConnected(false);
+        } else {
+            ALOGW("Attempted to disconnect unknown display %" PRIu64,
+                  displayId);
+        }
     }
 }
 
 // Other Device methods
 
-std::shared_ptr<Display> Device::getDisplayById(hwc2_display_t id) {
-    if (mDisplays.count(id) != 0) {
-        auto strongDisplay = mDisplays[id].lock();
-        ALOGE_IF(!strongDisplay, "Display %" PRId64 " is in mDisplays but is no"
-                " longer alive", id);
-        return strongDisplay;
-    }
-
-    auto display = std::make_shared<Display>(*this, id);
-    mDisplays.emplace(id, display);
-    return display;
+Display* Device::getDisplayById(hwc2_display_t id) {
+    auto iter = mDisplays.find(id);
+    return iter == mDisplays.end() ? nullptr : iter->second.get();
 }
 
 // Device initialization methods
@@ -271,84 +221,37 @@
     }
 }
 
-bool Device::hasCapability(HWC2::Capability capability) const
-{
-    return std::find(mCapabilities.cbegin(), mCapabilities.cend(),
-            capability) != mCapabilities.cend();
-}
-
-namespace {
-class ComposerCallback : public Hwc2::IComposerCallback {
-public:
-    ComposerCallback(Device* device) : mDevice(device) {}
-
-    Return<void> onHotplug(Hwc2::Display display,
-            Connection connected) override
-    {
-        hotplug_hook(mDevice, display, static_cast<int32_t>(connected));
-        return Void();
-    }
-
-    Return<void> onRefresh(Hwc2::Display display) override
-    {
-        refresh_hook(mDevice, display);
-        return Void();
-    }
-
-    Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
-    {
-        vsync_hook(mDevice, display, timestamp);
-        return Void();
-    }
-
-private:
-    Device* mDevice;
-};
-} // namespace anonymous
-
-void Device::registerCallbacks()
-{
-    sp<ComposerCallback> callback = new ComposerCallback(this);
-    mComposer->registerCallback(callback);
-}
-
-
-// For use by Display
-
-void Device::destroyVirtualDisplay(hwc2_display_t display)
-{
-    ALOGI("Destroying virtual display");
-    auto intError = mComposer->destroyVirtualDisplay(display);
-    auto error = static_cast<Error>(intError);
-    ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:"
-            " %s (%d)", display, to_string(error).c_str(), intError);
-    mDisplays.erase(display);
-}
-
 // Display methods
 
-Display::Display(Device& device, hwc2_display_t id)
-  : mDevice(device),
+Display::Display(android::Hwc2::Composer& composer,
+                 const std::unordered_set<Capability>& capabilities,
+                 hwc2_display_t id, DisplayType type)
+  : mComposer(composer),
+    mCapabilities(capabilities),
     mId(id),
     mIsConnected(false),
-    mType(DisplayType::Invalid)
+    mType(type)
 {
     ALOGV("Created display %" PRIu64, id);
-
-    auto intError = mDevice.mComposer->getDisplayType(mId,
-            reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(&mType));
-    auto error = static_cast<Error>(intError);
-    if (error != Error::None) {
-        ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)",
-              id, to_string(error).c_str(), intError);
-    }
+    setConnected(true);
 }
 
-Display::~Display()
-{
-    ALOGV("Destroyed display %" PRIu64, mId);
+Display::~Display() {
+    mLayers.clear();
+
     if (mType == DisplayType::Virtual) {
-        mDevice.destroyVirtualDisplay(mId);
+        ALOGV("Destroying virtual display");
+        auto intError = mComposer.destroyVirtualDisplay(mId);
+        auto error = static_cast<Error>(intError);
+        ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64
+                ") failed: %s (%d)", mId, to_string(error).c_str(), intError);
+    } else if (mType == DisplayType::Physical) {
+        auto error = setVsyncEnabled(HWC2::Vsync::Disable);
+        if (error != Error::None) {
+            ALOGE("~Display: Failed to disable vsync for display %" PRIu64
+                    ": %s (%d)", mId, to_string(error).c_str(),
+                    static_cast<int32_t>(error));
+        }
     }
 }
 
@@ -383,22 +286,35 @@
 
 Error Display::acceptChanges()
 {
-    auto intError = mDevice.mComposer->acceptDisplayChanges(mId);
+    auto intError = mComposer.acceptDisplayChanges(mId);
     return static_cast<Error>(intError);
 }
 
-Error Display::createLayer(std::shared_ptr<Layer>* outLayer)
+Error Display::createLayer(Layer** outLayer)
 {
+    if (!outLayer) {
+        return Error::BadParameter;
+    }
     hwc2_layer_t layerId = 0;
-    auto intError = mDevice.mComposer->createLayer(mId, &layerId);
+    auto intError = mComposer.createLayer(mId, &layerId);
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
         return error;
     }
 
-    auto layer = std::make_shared<Layer>(shared_from_this(), layerId);
-    mLayers.emplace(layerId, layer);
-    *outLayer = std::move(layer);
+    auto layer = std::make_unique<Layer>(
+            mComposer, mCapabilities, mId, layerId);
+    *outLayer = layer.get();
+    mLayers.emplace(layerId, std::move(layer));
+    return Error::None;
+}
+
+Error Display::destroyLayer(Layer* layer)
+{
+    if (!layer) {
+        return Error::BadParameter;
+    }
+    mLayers.erase(layer->getId());
     return Error::None;
 }
 
@@ -407,7 +323,7 @@
 {
     ALOGV("[%" PRIu64 "] getActiveConfig", mId);
     hwc2_config_t configId = 0;
-    auto intError = mDevice.mComposer->getActiveConfig(mId, &configId);
+    auto intError = mComposer.getActiveConfig(mId, &configId);
     auto error = static_cast<Error>(intError);
 
     if (error != Error::None) {
@@ -430,12 +346,12 @@
 }
 
 Error Display::getChangedCompositionTypes(
-        std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes)
+        std::unordered_map<Layer*, Composition>* outTypes)
 {
     std::vector<Hwc2::Layer> layerIds;
     std::vector<Hwc2::IComposerClient::Composition> types;
-    auto intError = mDevice.mComposer->getChangedCompositionTypes(mId,
-            &layerIds, &types);
+    auto intError = mComposer.getChangedCompositionTypes(
+            mId, &layerIds, &types);
     uint32_t numElements = layerIds.size();
     auto error = static_cast<Error>(intError);
     error = static_cast<Error>(intError);
@@ -464,7 +380,7 @@
 Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const
 {
     std::vector<Hwc2::ColorMode> modes;
-    auto intError = mDevice.mComposer->getColorModes(mId, &modes);
+    auto intError = mComposer.getColorModes(mId, &modes);
     uint32_t numModes = modes.size();
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
@@ -489,19 +405,18 @@
 
 Error Display::getName(std::string* outName) const
 {
-    auto intError = mDevice.mComposer->getDisplayName(mId, outName);
+    auto intError = mComposer.getDisplayName(mId, outName);
     return static_cast<Error>(intError);
 }
 
 Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
-        std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
-                outLayerRequests)
+        std::unordered_map<Layer*, LayerRequest>* outLayerRequests)
 {
     uint32_t intDisplayRequests;
     std::vector<Hwc2::Layer> layerIds;
     std::vector<uint32_t> layerRequests;
-    auto intError = mDevice.mComposer->getDisplayRequests(mId,
-            &intDisplayRequests, &layerIds, &layerRequests);
+    auto intError = mComposer.getDisplayRequests(
+            mId, &intDisplayRequests, &layerIds, &layerRequests);
     uint32_t numElements = layerIds.size();
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
@@ -535,7 +450,7 @@
 Error Display::supportsDoze(bool* outSupport) const
 {
     bool intSupport = false;
-    auto intError = mDevice.mComposer->getDozeSupport(mId, &intSupport);
+    auto intError = mComposer.getDozeSupport(mId, &intSupport);
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
         return error;
@@ -552,7 +467,7 @@
     float maxAverageLuminance = -1.0f;
     float minLuminance = -1.0f;
     std::vector<Hwc2::Hdr> intTypes;
-    auto intError = mDevice.mComposer->getHdrCapabilities(mId, &intTypes,
+    auto intError = mComposer.getHdrCapabilities(mId, &intTypes,
             &maxLuminance, &maxAverageLuminance, &minLuminance);
     auto error = static_cast<HWC2::Error>(intError);
 
@@ -571,25 +486,24 @@
 }
 
 Error Display::getReleaseFences(
-        std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const
+        std::unordered_map<Layer*, sp<Fence>>* outFences) const
 {
     std::vector<Hwc2::Layer> layerIds;
     std::vector<int> fenceFds;
-    auto intError = mDevice.mComposer->getReleaseFences(mId,
-            &layerIds, &fenceFds);
+    auto intError = mComposer.getReleaseFences(mId, &layerIds, &fenceFds);
     auto error = static_cast<Error>(intError);
     uint32_t numElements = layerIds.size();
     if (error != Error::None) {
         return error;
     }
 
-    std::unordered_map<std::shared_ptr<Layer>, sp<Fence>> releaseFences;
+    std::unordered_map<Layer*, sp<Fence>> releaseFences;
     releaseFences.reserve(numElements);
     for (uint32_t element = 0; element < numElements; ++element) {
         auto layer = getLayerById(layerIds[element]);
         if (layer) {
             sp<Fence> fence(new Fence(fenceFds[element]));
-            releaseFences.emplace(std::move(layer), fence);
+            releaseFences.emplace(layer, fence);
         } else {
             ALOGE("getReleaseFences: invalid layer %" PRIu64
                     " found on display %" PRIu64, layerIds[element], mId);
@@ -607,7 +521,7 @@
 Error Display::present(sp<Fence>* outPresentFence)
 {
     int32_t presentFenceFd = -1;
-    auto intError = mDevice.mComposer->presentDisplay(mId, &presentFenceFd);
+    auto intError = mComposer.presentDisplay(mId, &presentFenceFd);
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
         return error;
@@ -625,7 +539,7 @@
                 config->getDisplayId(), mId);
         return Error::BadConfig;
     }
-    auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId());
+    auto intError = mComposer.setActiveConfig(mId, config->getId());
     return static_cast<Error>(intError);
 }
 
@@ -634,7 +548,7 @@
 {
     // TODO: Properly encode client target surface damage
     int32_t fenceFd = acquireFence->dup();
-    auto intError = mDevice.mComposer->setClientTarget(mId, slot, target,
+    auto intError = mComposer.setClientTarget(mId, slot, target,
             fenceFd, static_cast<Hwc2::Dataspace>(dataspace),
             std::vector<Hwc2::IComposerClient::Rect>());
     return static_cast<Error>(intError);
@@ -642,15 +556,15 @@
 
 Error Display::setColorMode(android_color_mode_t mode)
 {
-    auto intError = mDevice.mComposer->setColorMode(mId,
-            static_cast<Hwc2::ColorMode>(mode));
+    auto intError = mComposer.setColorMode(
+            mId, static_cast<Hwc2::ColorMode>(mode));
     return static_cast<Error>(intError);
 }
 
 Error Display::setColorTransform(const android::mat4& matrix,
         android_color_transform_t hint)
 {
-    auto intError = mDevice.mComposer->setColorTransform(mId,
+    auto intError = mComposer.setColorTransform(mId,
             matrix.asArray(), static_cast<Hwc2::ColorTransform>(hint));
     return static_cast<Error>(intError);
 }
@@ -660,7 +574,7 @@
 {
     int32_t fenceFd = releaseFence->dup();
     auto handle = buffer->getNativeBuffer()->handle;
-    auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd);
+    auto intError = mComposer.setOutputBuffer(mId, handle, fenceFd);
     close(fenceFd);
     return static_cast<Error>(intError);
 }
@@ -668,14 +582,14 @@
 Error Display::setPowerMode(PowerMode mode)
 {
     auto intMode = static_cast<Hwc2::IComposerClient::PowerMode>(mode);
-    auto intError = mDevice.mComposer->setPowerMode(mId, intMode);
+    auto intError = mComposer.setPowerMode(mId, intMode);
     return static_cast<Error>(intError);
 }
 
 Error Display::setVsyncEnabled(Vsync enabled)
 {
     auto intEnabled = static_cast<Hwc2::IComposerClient::Vsync>(enabled);
-    auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled);
+    auto intError = mComposer.setVsyncEnabled(mId, intEnabled);
     return static_cast<Error>(intError);
 }
 
@@ -683,8 +597,7 @@
 {
     uint32_t numTypes = 0;
     uint32_t numRequests = 0;
-    auto intError = mDevice.mComposer->validateDisplay(mId,
-            &numTypes, &numRequests);
+    auto intError = mComposer.validateDisplay(mId, &numTypes, &numRequests);
     auto error = static_cast<Error>(intError);
     if (error != Error::None && error != Error::HasChanges) {
         return error;
@@ -701,7 +614,8 @@
     uint32_t numTypes = 0;
     uint32_t numRequests = 0;
     int32_t presentFenceFd = -1;
-    auto intError = mDevice.mComposer->presentOrValidateDisplay(mId, &numTypes, &numRequests, &presentFenceFd, state);
+    auto intError = mComposer.presentOrValidateDisplay(
+            mId, &numTypes, &numRequests, &presentFenceFd, state);
     auto error = static_cast<Error>(intError);
     if (error != Error::None && error != Error::HasChanges) {
         return error;
@@ -720,15 +634,23 @@
 
 void Display::discardCommands()
 {
-    mDevice.mComposer->resetCommands();
+    mComposer.resetCommands();
 }
 
 // For use by Device
 
+void Display::setConnected(bool connected) {
+    if (!mIsConnected && connected && mType == DisplayType::Physical) {
+        mComposer.setClientTargetSlotCount(mId);
+        loadConfigs();
+    }
+    mIsConnected = connected;
+}
+
 int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
 {
     int32_t value = 0;
-    auto intError = mDevice.mComposer->getDisplayAttribute(mId, configId,
+    auto intError = mComposer.getDisplayAttribute(mId, configId,
             static_cast<Hwc2::IComposerClient::Attribute>(attribute),
             &value);
     auto error = static_cast<Error>(intError);
@@ -760,7 +682,7 @@
     ALOGV("[%" PRIu64 "] loadConfigs", mId);
 
     std::vector<Hwc2::Config> configIds;
-    auto intError = mDevice.mComposer->getDisplayConfigs(mId, &configIds);
+    auto intError = mComposer.getDisplayConfigs(mId, &configIds);
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
         ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId,
@@ -773,54 +695,51 @@
     }
 }
 
-// For use by Layer
-
-void Display::destroyLayer(hwc2_layer_t layerId)
-{
-    auto intError =mDevice.mComposer->destroyLayer(mId, layerId);
-    auto error = static_cast<Error>(intError);
-    ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
-            " failed: %s (%d)", mId, layerId, to_string(error).c_str(),
-            intError);
-    mLayers.erase(layerId);
-}
-
 // Other Display methods
 
-std::shared_ptr<Layer> Display::getLayerById(hwc2_layer_t id) const
+Layer* Display::getLayerById(hwc2_layer_t id) const
 {
     if (mLayers.count(id) == 0) {
         return nullptr;
     }
 
-    auto layer = mLayers.at(id).lock();
-    return layer;
+    return mLayers.at(id).get();
 }
 
 // Layer methods
 
-Layer::Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id)
-  : mDisplay(display),
-    mDisplayId(display->getId()),
-    mDevice(display->getDevice()),
-    mId(id)
+Layer::Layer(android::Hwc2::Composer& composer,
+             const std::unordered_set<Capability>& capabilities,
+             hwc2_display_t displayId, hwc2_layer_t layerId)
+  : mComposer(composer),
+    mCapabilities(capabilities),
+    mDisplayId(displayId),
+    mId(layerId)
 {
-    ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id,
-            display->getId());
+    ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId);
 }
 
 Layer::~Layer()
 {
-    auto display = mDisplay.lock();
-    if (display) {
-        display->destroyLayer(mId);
+    auto intError = mComposer.destroyLayer(mDisplayId, mId);
+    auto error = static_cast<Error>(intError);
+    ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
+            " failed: %s (%d)", mDisplayId, mId, to_string(error).c_str(),
+            intError);
+    if (mLayerDestroyedListener) {
+        mLayerDestroyedListener(this);
     }
 }
 
+void Layer::setLayerDestroyedListener(std::function<void(Layer*)> listener) {
+    LOG_ALWAYS_FATAL_IF(mLayerDestroyedListener && listener,
+            "Attempt to set layer destroyed listener multiple times");
+    mLayerDestroyedListener = listener;
+}
+
 Error Layer::setCursorPosition(int32_t x, int32_t y)
 {
-    auto intError = mDevice.mComposer->setCursorPosition(mDisplayId,
-            mId, x, y);
+    auto intError = mComposer.setCursorPosition(mDisplayId, mId, x, y);
     return static_cast<Error>(intError);
 }
 
@@ -828,8 +747,8 @@
         const sp<Fence>& acquireFence)
 {
     int32_t fenceFd = acquireFence->dup();
-    auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId,
-            mId, slot, buffer, fenceFd);
+    auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer,
+                                             fenceFd);
     return static_cast<Error>(intError);
 }
 
@@ -839,7 +758,7 @@
     // rects for HWC
     Hwc2::Error intError = Hwc2::Error::NONE;
     if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) {
-        intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId,
+        intError = mComposer.setLayerSurfaceDamage(mDisplayId,
                 mId, std::vector<Hwc2::IComposerClient::Rect>());
     } else {
         size_t rectCount = 0;
@@ -851,8 +770,7 @@
                     rectArray[rect].right, rectArray[rect].bottom});
         }
 
-        intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId,
-                mId, hwcRects);
+        intError = mComposer.setLayerSurfaceDamage(mDisplayId, mId, hwcRects);
     }
 
     return static_cast<Error>(intError);
@@ -861,24 +779,22 @@
 Error Layer::setBlendMode(BlendMode mode)
 {
     auto intMode = static_cast<Hwc2::IComposerClient::BlendMode>(mode);
-    auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId,
-            mId, intMode);
+    auto intError = mComposer.setLayerBlendMode(mDisplayId, mId, intMode);
     return static_cast<Error>(intError);
 }
 
 Error Layer::setColor(hwc_color_t color)
 {
     Hwc2::IComposerClient::Color hwcColor{color.r, color.g, color.b, color.a};
-    auto intError = mDevice.mComposer->setLayerColor(mDisplayId,
-            mId, hwcColor);
+    auto intError = mComposer.setLayerColor(mDisplayId, mId, hwcColor);
     return static_cast<Error>(intError);
 }
 
 Error Layer::setCompositionType(Composition type)
 {
     auto intType = static_cast<Hwc2::IComposerClient::Composition>(type);
-    auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId,
-            mId, intType);
+    auto intError = mComposer.setLayerCompositionType(
+            mDisplayId, mId, intType);
     return static_cast<Error>(intError);
 }
 
@@ -889,8 +805,7 @@
     }
     mDataSpace = dataspace;
     auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace);
-    auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId,
-            mId, intDataspace);
+    auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace);
     return static_cast<Error>(intError);
 }
 
@@ -898,27 +813,24 @@
 {
     Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top,
         frame.right, frame.bottom};
-    auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId,
-            mId, hwcRect);
+    auto intError = mComposer.setLayerDisplayFrame(mDisplayId, mId, hwcRect);
     return static_cast<Error>(intError);
 }
 
 Error Layer::setPlaneAlpha(float alpha)
 {
-    auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId,
-            mId, alpha);
+    auto intError = mComposer.setLayerPlaneAlpha(mDisplayId, mId, alpha);
     return static_cast<Error>(intError);
 }
 
 Error Layer::setSidebandStream(const native_handle_t* stream)
 {
-    if (!mDevice.hasCapability(Capability::SidebandStream)) {
+    if (mCapabilities.count(Capability::SidebandStream) == 0) {
         ALOGE("Attempted to call setSidebandStream without checking that the "
                 "device supports sideband streams");
         return Error::Unsupported;
     }
-    auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId,
-            mId, stream);
+    auto intError = mComposer.setLayerSidebandStream(mDisplayId, mId, stream);
     return static_cast<Error>(intError);
 }
 
@@ -926,16 +838,14 @@
 {
     Hwc2::IComposerClient::FRect hwcRect{
         crop.left, crop.top, crop.right, crop.bottom};
-    auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId,
-            mId, hwcRect);
+    auto intError = mComposer.setLayerSourceCrop(mDisplayId, mId, hwcRect);
     return static_cast<Error>(intError);
 }
 
 Error Layer::setTransform(Transform transform)
 {
     auto intTransform = static_cast<Hwc2::Transform>(transform);
-    auto intError = mDevice.mComposer->setLayerTransform(mDisplayId,
-            mId, intTransform);
+    auto intError = mComposer.setLayerTransform(mDisplayId, mId, intTransform);
     return static_cast<Error>(intError);
 }
 
@@ -950,20 +860,19 @@
                 rectArray[rect].right, rectArray[rect].bottom});
     }
 
-    auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId,
-            mId, hwcRects);
+    auto intError = mComposer.setLayerVisibleRegion(mDisplayId, mId, hwcRects);
     return static_cast<Error>(intError);
 }
 
 Error Layer::setZOrder(uint32_t z)
 {
-    auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z);
+    auto intError = mComposer.setLayerZOrder(mDisplayId, mId, z);
     return static_cast<Error>(intError);
 }
 
 Error Layer::setInfo(uint32_t type, uint32_t appId)
 {
-  auto intError = mDevice.mComposer->setLayerInfo(mDisplayId, mId, type, appId);
+  auto intError = mComposer.setLayerInfo(mDisplayId, mId, type, appId);
   return static_cast<Error>(intError);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 404bb28..fbe4c7e 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -53,24 +53,37 @@
 class Display;
 class Layer;
 
-typedef std::function<void(std::shared_ptr<Display>, Connection)>
-        HotplugCallback;
-typedef std::function<void(std::shared_ptr<Display>)> RefreshCallback;
-typedef std::function<void(std::shared_ptr<Display>, nsecs_t)> VsyncCallback;
+// Implement this interface to receive hardware composer events.
+//
+// These callback functions will generally be called on a hwbinder thread, but
+// when first registering the callback the onHotplugReceived() function will
+// immediately be called on the thread calling registerCallback().
+//
+// All calls receive a sequenceId, which will be the value that was supplied to
+// HWC2::Device::registerCallback(). It's used to help differentiate callbacks
+// from different hardware composer instances.
+class ComposerCallback {
+ public:
+    virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+                                   Connection connection,
+                                   bool primaryDisplay) = 0;
+    virtual void onRefreshReceived(int32_t sequenceId,
+                                   hwc2_display_t display) = 0;
+    virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
+                                 int64_t timestamp) = 0;
+    virtual ~ComposerCallback() = default;
+};
 
 // C++ Wrapper around hwc2_device_t. Load all functions pointers
 // and handle callback registration.
 class Device
 {
 public:
-    // useVrComposer is passed to the composer HAL. When true, the composer HAL
-    // will use the vr composer service, otherwise it uses the real hardware
-    // composer.
-    Device(bool useVrComposer);
-    ~Device();
+    // Service name is expected to be 'default' or 'vr' for normal use.
+    // 'vr' will slightly modify the behavior of the mComposer.
+    Device(const std::string& serviceName);
 
-    friend class HWC2::Display;
-    friend class HWC2::Layer;
+    void registerCallback(ComposerCallback* callback, int32_t sequenceId);
 
     // Required by HWC2
 
@@ -82,27 +95,14 @@
 
     uint32_t getMaxVirtualDisplayCount() const;
     Error createVirtualDisplay(uint32_t width, uint32_t height,
-            android_pixel_format_t* format,
-            std::shared_ptr<Display>* outDisplay);
+            android_pixel_format_t* format, Display** outDisplay);
+    void destroyDisplay(hwc2_display_t displayId);
 
-    void registerHotplugCallback(HotplugCallback hotplug);
-    void registerRefreshCallback(RefreshCallback refresh);
-    void registerVsyncCallback(VsyncCallback vsync);
-
-    // For use by callbacks
-
-    void callHotplug(std::shared_ptr<Display> display, Connection connected);
-    void callRefresh(std::shared_ptr<Display> display);
-    void callVsync(std::shared_ptr<Display> display, nsecs_t timestamp);
+    void onHotplug(hwc2_display_t displayId, Connection connection);
 
     // Other Device methods
 
-    // This will create a Display if one is not found, but it will not be marked
-    // as connected. This Display may be null if the display has been torn down
-    // but has not been removed from the map yet.
-    std::shared_ptr<Display> getDisplayById(hwc2_display_t id);
-
-    bool hasCapability(HWC2::Capability capability) const;
+    Display* getDisplayById(hwc2_display_t id);
 
     android::Hwc2::Composer* getComposer() { return mComposer.get(); }
 
@@ -110,37 +110,23 @@
     // Initialization methods
 
     void loadCapabilities();
-    void registerCallbacks();
-
-    // For use by Display
-
-    void destroyVirtualDisplay(hwc2_display_t display);
 
     // Member variables
     std::unique_ptr<android::Hwc2::Composer> mComposer;
-
     std::unordered_set<Capability> mCapabilities;
-    std::unordered_map<hwc2_display_t, std::weak_ptr<Display>> mDisplays;
-
-    HotplugCallback mHotplug;
-    std::vector<std::pair<std::shared_ptr<Display>, Connection>>
-            mPendingHotplugs;
-    RefreshCallback mRefresh;
-    std::vector<std::shared_ptr<Display>> mPendingRefreshes;
-    VsyncCallback mVsync;
-    std::vector<std::pair<std::shared_ptr<Display>, nsecs_t>> mPendingVsyncs;
+    std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
+    bool mRegisteredCallback;
 };
 
 // Convenience C++ class to access hwc2_device_t Display functions directly.
-class Display : public std::enable_shared_from_this<Display>
+class Display
 {
 public:
-    Display(Device& device, hwc2_display_t id);
+    Display(android::Hwc2::Composer& composer,
+            const std::unordered_set<Capability>& capabilities,
+            hwc2_display_t id, DisplayType type);
     ~Display();
 
-    friend class HWC2::Device;
-    friend class HWC2::Layer;
-
     class Config
     {
     public:
@@ -213,12 +199,12 @@
     // Required by HWC2
 
     [[clang::warn_unused_result]] Error acceptChanges();
-    [[clang::warn_unused_result]] Error createLayer(
-            std::shared_ptr<Layer>* outLayer);
+    [[clang::warn_unused_result]] Error createLayer(Layer** outLayer);
+    [[clang::warn_unused_result]] Error destroyLayer(Layer* layer);
     [[clang::warn_unused_result]] Error getActiveConfig(
             std::shared_ptr<const Config>* outConfig) const;
     [[clang::warn_unused_result]] Error getChangedCompositionTypes(
-            std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes);
+            std::unordered_map<Layer*, Composition>* outTypes);
     [[clang::warn_unused_result]] Error getColorModes(
             std::vector<android_color_mode_t>* outModes) const;
 
@@ -228,14 +214,13 @@
     [[clang::warn_unused_result]] Error getName(std::string* outName) const;
     [[clang::warn_unused_result]] Error getRequests(
             DisplayRequest* outDisplayRequests,
-            std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
-                    outLayerRequests);
+            std::unordered_map<Layer*, LayerRequest>* outLayerRequests);
     [[clang::warn_unused_result]] Error getType(DisplayType* outType) const;
     [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const;
     [[clang::warn_unused_result]] Error getHdrCapabilities(
             std::unique_ptr<android::HdrCapabilities>* outCapabilities) const;
     [[clang::warn_unused_result]] Error getReleaseFences(
-            std::unordered_map<std::shared_ptr<Layer>,
+            std::unordered_map<Layer*,
                     android::sp<android::Fence>>* outFences) const;
     [[clang::warn_unused_result]] Error present(
             android::sp<android::Fence>* outPresentFence);
@@ -267,32 +252,31 @@
 
     // Other Display methods
 
-    Device& getDevice() const { return mDevice; }
     hwc2_display_t getId() const { return mId; }
     bool isConnected() const { return mIsConnected; }
+    void setConnected(bool connected);  // For use by Device only
 
 private:
-    // For use by Device
-
-    void setConnected(bool connected) { mIsConnected = connected; }
     int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
     void loadConfig(hwc2_config_t configId);
     void loadConfigs();
 
-    // For use by Layer
-    void destroyLayer(hwc2_layer_t layerId);
-
     // This may fail (and return a null pointer) if no layer with this ID exists
     // on this display
-    std::shared_ptr<Layer> getLayerById(hwc2_layer_t id) const;
+    Layer* getLayerById(hwc2_layer_t id) const;
 
     // Member variables
 
-    Device& mDevice;
+    // These are references to data owned by HWC2::Device, which will outlive
+    // this HWC2::Display, so these references are guaranteed to be valid for
+    // the lifetime of this object.
+    android::Hwc2::Composer& mComposer;
+    const std::unordered_set<Capability>& mCapabilities;
+
     hwc2_display_t mId;
     bool mIsConnected;
     DisplayType mType;
-    std::unordered_map<hwc2_layer_t, std::weak_ptr<Layer>> mLayers;
+    std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
     // The ordering in this map matters, for getConfigs(), when it is
     // converted to a vector
     std::map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
@@ -302,12 +286,18 @@
 class Layer
 {
 public:
-    Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id);
+    Layer(android::Hwc2::Composer& composer,
+          const std::unordered_set<Capability>& capabilities,
+          hwc2_display_t displayId, hwc2_layer_t layerId);
     ~Layer();
 
-    bool isAbandoned() const { return mDisplay.expired(); }
     hwc2_layer_t getId() const { return mId; }
 
+    // Register a listener to be notified when the layer is destroyed. When the
+    // listener function is called, the Layer will be in the process of being
+    // destroyed, so it's not safe to call methods on it.
+    void setLayerDestroyedListener(std::function<void(Layer*)> listener);
+
     [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y);
     [[clang::warn_unused_result]] Error setBuffer(uint32_t slot,
             const android::sp<android::GraphicBuffer>& buffer,
@@ -334,11 +324,16 @@
     [[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId);
 
 private:
-    std::weak_ptr<Display> mDisplay;
+    // These are references to data owned by HWC2::Device, which will outlive
+    // this HWC2::Layer, so these references are guaranteed to be valid for
+    // the lifetime of this object.
+    android::Hwc2::Composer& mComposer;
+    const std::unordered_set<Capability>& mCapabilities;
+
     hwc2_display_t mDisplayId;
-    Device& mDevice;
     hwc2_layer_t mId;
     android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+    std::function<void(Layer*)> mLayerDestroyedListener;
 };
 
 } // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index ac2dde2..b096a3a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -59,13 +59,12 @@
 
 // ---------------------------------------------------------------------------
 
-HWComposer::HWComposer(bool useVrComposer)
+HWComposer::HWComposer(const std::string& serviceName)
     : mHwcDevice(),
       mDisplayData(2),
       mFreeDisplaySlots(),
       mHwcDisplaySlots(),
       mCBContext(),
-      mEventHandler(nullptr),
       mVSyncCounts(),
       mRemainingHwcVirtualDisplays(0)
 {
@@ -74,40 +73,15 @@
         mVSyncCounts[i] = 0;
     }
 
-    loadHwcModule(useVrComposer);
+    mHwcDevice = std::make_unique<HWC2::Device>(serviceName);
+    mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
 }
 
 HWComposer::~HWComposer() {}
 
-void HWComposer::setEventHandler(EventHandler* handler)
-{
-    if (handler == nullptr) {
-        ALOGE("setEventHandler: Rejected attempt to clear handler");
-        return;
-    }
-
-    bool wasNull = (mEventHandler == nullptr);
-    mEventHandler = handler;
-
-    if (wasNull) {
-        auto hotplugHook = std::bind(&HWComposer::hotplug, this,
-                std::placeholders::_1, std::placeholders::_2);
-        mHwcDevice->registerHotplugCallback(hotplugHook);
-        auto invalidateHook = std::bind(&HWComposer::invalidate, this,
-                std::placeholders::_1);
-        mHwcDevice->registerRefreshCallback(invalidateHook);
-        auto vsyncHook = std::bind(&HWComposer::vsync, this,
-                std::placeholders::_1, std::placeholders::_2);
-        mHwcDevice->registerVsyncCallback(vsyncHook);
-    }
-}
-
-// Load and prepare the hardware composer module.  Sets mHwc.
-void HWComposer::loadHwcModule(bool useVrComposer)
-{
-    ALOGV("loadHwcModule");
-    mHwcDevice = std::make_unique<HWC2::Device>(useVrComposer);
-    mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
+void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
+                                  int32_t sequenceId) {
+    mHwcDevice->registerCallback(callback, sequenceId);
 }
 
 bool HWComposer::hasCapability(HWC2::Capability capability) const
@@ -145,54 +119,51 @@
     }
 }
 
-void HWComposer::hotplug(const std::shared_ptr<HWC2::Display>& display,
-        HWC2::Connection connected) {
-    ALOGV("hotplug: %" PRIu64 ", %s", display->getId(),
-            to_string(connected).c_str());
-    int32_t disp = 0;
+void HWComposer::onHotplug(hwc2_display_t displayId,
+                           HWC2::Connection connection) {
+    ALOGV("hotplug: %" PRIu64 ", %s", displayId,
+            to_string(connection).c_str());
+    mHwcDevice->onHotplug(displayId, connection);
     if (!mDisplayData[0].hwcDisplay) {
-        ALOGE_IF(connected != HWC2::Connection::Connected, "Assumed primary"
+        ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary"
                 " display would be connected");
-        mDisplayData[0].hwcDisplay = display;
-        mHwcDisplaySlots[display->getId()] = 0;
-        disp = DisplayDevice::DISPLAY_PRIMARY;
+        mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId);
+        mHwcDisplaySlots[displayId] = 0;
     } else {
         // Disconnect is handled through HWComposer::disconnectDisplay via
         // SurfaceFlinger's onHotplugReceived callback handling
-        if (connected == HWC2::Connection::Connected) {
-            mDisplayData[1].hwcDisplay = display;
-            mHwcDisplaySlots[display->getId()] = 1;
+        if (connection == HWC2::Connection::Connected) {
+            mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId);
+            mHwcDisplaySlots[displayId] = 1;
         }
-        disp = DisplayDevice::DISPLAY_EXTERNAL;
     }
-    mEventHandler->onHotplugReceived(this, disp,
-            connected == HWC2::Connection::Connected);
 }
 
-void HWComposer::invalidate(const std::shared_ptr<HWC2::Display>& /*display*/) {
-    mEventHandler->onInvalidateReceived(this);
-}
-
-void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display,
-        int64_t timestamp) {
+bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp,
+                         int32_t* outDisplay) {
+    auto display = mHwcDevice->getDisplayById(displayId);
+    if (!display) {
+        ALOGE("onVsync Failed to find display %" PRIu64, displayId);
+        return false;
+    }
     auto displayType = HWC2::DisplayType::Invalid;
     auto error = display->getType(&displayType);
     if (error != HWC2::Error::None) {
-        ALOGE("vsync: Failed to determine type of display %" PRIu64,
+        ALOGE("onVsync: Failed to determine type of display %" PRIu64,
                 display->getId());
-        return;
+        return false;
     }
 
     if (displayType == HWC2::DisplayType::Virtual) {
         ALOGE("Virtual display %" PRIu64 " passed to vsync callback",
                 display->getId());
-        return;
+        return false;
     }
 
     if (mHwcDisplaySlots.count(display->getId()) == 0) {
         ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback",
                 display->getId());
-        return;
+        return false;
     }
 
     int32_t disp = mHwcDisplaySlots[display->getId()];
@@ -206,17 +177,21 @@
         if (timestamp == mLastHwVSync[disp]) {
             ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
                     timestamp);
-            return;
+            return false;
         }
 
         mLastHwVSync[disp] = timestamp;
     }
 
+    if (outDisplay) {
+        *outDisplay = disp;
+    }
+
     char tag[16];
     snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
     ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
 
-    mEventHandler->onVSyncReceived(this, disp, timestamp);
+    return true;
 }
 
 status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
@@ -235,7 +210,7 @@
         return INVALID_OPERATION;
     }
 
-    std::shared_ptr<HWC2::Display> display;
+    HWC2::Display* display;
     auto error = mHwcDevice->createVirtualDisplay(width, height, format,
             &display);
     if (error != HWC2::Error::None) {
@@ -264,13 +239,13 @@
     return NO_ERROR;
 }
 
-std::shared_ptr<HWC2::Layer> HWComposer::createLayer(int32_t displayId) {
+HWC2::Layer* HWComposer::createLayer(int32_t displayId) {
     if (!isValidDisplay(displayId)) {
         ALOGE("Failed to create layer on invalid display %d", displayId);
         return nullptr;
     }
     auto display = mDisplayData[displayId].hwcDisplay;
-    std::shared_ptr<HWC2::Layer> layer;
+    HWC2::Layer* layer;
     auto error = display->createLayer(&layer);
     if (error != HWC2::Error::None) {
         ALOGE("Failed to create layer on display %d: %s (%d)", displayId,
@@ -280,6 +255,19 @@
     return layer;
 }
 
+void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) {
+    if (!isValidDisplay(displayId)) {
+        ALOGE("Failed to destroy layer on invalid display %d", displayId);
+        return;
+    }
+    auto display = mDisplayData[displayId].hwcDisplay;
+    auto error = display->destroyLayer(layer);
+    if (error != HWC2::Error::None) {
+        ALOGE("Failed to destroy layer on display %d: %s (%d)", displayId,
+                to_string(error).c_str(), static_cast<int32_t>(error));
+    }
+}
+
 nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const {
     // this returns the last refresh timestamp.
     // if the last one is not available, we estimate it based on
@@ -347,10 +335,8 @@
                 displayId);
         return modes;
     }
-    const std::shared_ptr<HWC2::Display>& hwcDisplay =
-            mDisplayData[displayId].hwcDisplay;
 
-    auto error = hwcDisplay->getColorModes(&modes);
+    auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes);
     if (error != HWC2::Error::None) {
         ALOGE("getColorModes failed for display %d: %s (%d)", displayId,
                 to_string(error).c_str(), static_cast<int32_t>(error));
@@ -470,7 +456,7 @@
             return UNKNOWN_ERROR;
         }
         if (state == 1) { //Present Succeeded.
-            std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences;
+            std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
             error = hwcDisplay->getReleaseFences(&releaseFences);
             displayData.releaseFences = std::move(releaseFences);
             displayData.lastPresentFence = outPresentFence;
@@ -489,8 +475,7 @@
         return BAD_INDEX;
     }
 
-    std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::Composition>
-        changedTypes;
+    std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes;
     changedTypes.reserve(numTypes);
     error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
     if (error != HWC2::Error::None) {
@@ -502,8 +487,7 @@
 
 
     displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0);
-    std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::LayerRequest>
-        layerRequests;
+    std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests;
     layerRequests.reserve(numRequests);
     error = hwcDisplay->getRequests(&displayData.displayRequests,
             &layerRequests);
@@ -597,7 +581,7 @@
 }
 
 sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
-        const std::shared_ptr<HWC2::Layer>& layer) const {
+        HWC2::Layer* layer) const {
     if (!isValidDisplay(displayId)) {
         ALOGE("getLayerReleaseFence: Invalid display");
         return Fence::NO_FENCE;
@@ -638,7 +622,7 @@
         return UNKNOWN_ERROR;
     }
 
-    std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences;
+    std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
     error = hwcDisplay->getReleaseFences(&releaseFences);
     if (error != HWC2::Error::None) {
         ALOGE("presentAndGetReleaseFences: Failed to get release fences "
@@ -786,6 +770,8 @@
     auto hwcId = displayData.hwcDisplay->getId();
     mHwcDisplaySlots.erase(hwcId);
     displayData.reset();
+
+    mHwcDevice->destroyDisplay(hwcId);
 }
 
 status_t HWComposer::setOutputBuffer(int32_t displayId,
@@ -884,7 +870,7 @@
 HWComposer::DisplayData::DisplayData()
   : hasClientComposition(false),
     hasDeviceComposition(false),
-    hwcDisplay(),
+    hwcDisplay(nullptr),
     lastPresentFence(Fence::NO_FENCE),
     outbufHandle(nullptr),
     outbufAcquireFence(Fence::NO_FENCE),
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 7463362..3640bb5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -65,24 +65,14 @@
 class HWComposer
 {
 public:
-    class EventHandler {
-        friend class HWComposer;
-        virtual void onVSyncReceived(
-            HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
-        virtual void onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) = 0;
-        virtual void onInvalidateReceived(HWComposer* composer) = 0;
-    protected:
-        virtual ~EventHandler() {}
-    };
-
-    // useVrComposer is passed to the composer HAL. When true, the composer HAL
-    // will use the vr composer service, otherwise it uses the real hardware
-    // composer.
-    HWComposer(bool useVrComposer);
+    // Uses the named composer service. Valid choices for normal use
+    // are 'default' and 'vr'.
+    HWComposer(const std::string& serviceName);
 
     ~HWComposer();
 
-    void setEventHandler(EventHandler* handler);
+    void registerCallback(HWC2::ComposerCallback* callback,
+                          int32_t sequenceId);
 
     bool hasCapability(HWC2::Capability capability) const;
 
@@ -92,7 +82,9 @@
             android_pixel_format_t* format, int32_t* outId);
 
     // Attempts to create a new layer on this display
-    std::shared_ptr<HWC2::Layer> createLayer(int32_t displayId);
+    HWC2::Layer* createLayer(int32_t displayId);
+    // Destroy a previously created layer
+    void destroyLayer(int32_t displayId, HWC2::Layer* layer);
 
     // Asks the HAL what it can do
     status_t prepare(DisplayDevice& displayDevice);
@@ -127,7 +119,7 @@
 
     // Get last release fence for the given layer
     sp<Fence> getLayerReleaseFence(int32_t displayId,
-            const std::shared_ptr<HWC2::Layer>& layer) const;
+            HWC2::Layer* layer) const;
 
     // Set the output buffer and acquire fence for a virtual display.
     // Returns INVALID_OPERATION if displayId is not a virtual display.
@@ -143,6 +135,12 @@
 
     // Events handling ---------------------------------------------------------
 
+    // Returns true if successful, false otherwise. The
+    // DisplayDevice::DisplayType of the display is returned as an output param.
+    bool onVsync(hwc2_display_t displayId, int64_t timestamp,
+                 int32_t* outDisplay);
+    void onHotplug(hwc2_display_t displayId, HWC2::Connection connection);
+
     void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
 
     // Query display parameters.  Pass in a display index (e.g.
@@ -170,19 +168,11 @@
 private:
     static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;
 
-    void loadHwcModule(bool useVrComposer);
-
     bool isValidDisplay(int32_t displayId) const;
     static void validateChange(HWC2::Composition from, HWC2::Composition to);
 
     struct cb_context;
 
-    void invalidate(const std::shared_ptr<HWC2::Display>& display);
-    void vsync(const std::shared_ptr<HWC2::Display>& display,
-            int64_t timestamp);
-    void hotplug(const std::shared_ptr<HWC2::Display>& display,
-            HWC2::Connection connected);
-
     struct DisplayData {
         DisplayData();
         ~DisplayData();
@@ -190,11 +180,10 @@
 
         bool hasClientComposition;
         bool hasDeviceComposition;
-        std::shared_ptr<HWC2::Display> hwcDisplay;
+        HWC2::Display* hwcDisplay;
         HWC2::DisplayRequest displayRequests;
         sp<Fence> lastPresentFence;  // signals when the last set op retires
-        std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>>
-                releaseFences;
+        std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
         buffer_handle_t outbufHandle;
         sp<Fence> outbufAcquireFence;
         mutable std::unordered_map<int32_t,
@@ -215,7 +204,6 @@
     mutable Mutex mDisplayLock;
 
     cb_context*                     mCBContext;
-    EventHandler*                   mEventHandler;
     size_t                          mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
     uint32_t                        mRemainingHwcVirtualDisplays;
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index c129ae5..1de5e48 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -345,8 +345,9 @@
         PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
     LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
 
-    status_t result = mSource[source]->dequeueBuffer(sslot, fence,
-            mSinkBufferWidth, mSinkBufferHeight, format, usage, nullptr);
+    status_t result =
+            mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
+                                           format, usage, nullptr, nullptr);
     if (result < 0)
         return result;
     int pslot = mapSource2ProducerSlot(source, *sslot);
@@ -384,12 +385,13 @@
     return result;
 }
 
-status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
-        uint32_t w, uint32_t h, PixelFormat format, uint64_t usage,
-        FrameEventHistoryDelta* outTimestamps) {
+status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h,
+                                              PixelFormat format, uint64_t usage,
+                                              uint64_t* outBufferAge,
+                                              FrameEventHistoryDelta* outTimestamps) {
     if (mDisplayId < 0) {
-        return mSource[SOURCE_SINK]->dequeueBuffer(
-                pslot, fence, w, h, format, usage, outTimestamps);
+        return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge,
+                                                   outTimestamps);
     }
 
     VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
@@ -449,6 +451,9 @@
             *pslot = mapSource2ProducerSlot(source, sslot);
         }
     }
+    if (outBufferAge) {
+        *outBufferAge = 0;
+    }
     return result;
 }
 
@@ -622,6 +627,10 @@
     return INVALID_OPERATION;
 }
 
+status_t VirtualDisplaySurface::getConsumerUsage(uint64_t* outUsage) const {
+    return mSource[SOURCE_SINK]->getConsumerUsage(outUsage);
+}
+
 void VirtualDisplaySurface::updateQueueBufferOutput(
         QueueBufferOutput&& qbo) {
     mQueueBufferOutput = std::move(qbo);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 7f8b39b..1671aba 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -104,9 +104,9 @@
     virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
     virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
     virtual status_t setAsyncMode(bool async);
-    virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, PixelFormat format, uint64_t usage,
-            FrameEventHistoryDelta *outTimestamps);
+    virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h,
+                                   PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+                                   FrameEventHistoryDelta* outTimestamps);
     virtual status_t detachBuffer(int slot);
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence);
@@ -130,6 +130,7 @@
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) override;
     virtual status_t getUniqueId(uint64_t* outId) const override;
+    virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
 
     //
     // Utility methods
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp
index ee6e886..052a959 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -31,34 +31,35 @@
 }
 
 bool EventControlThread::threadLoop() {
-    Mutex::Autolock lock(mMutex);
-
-    bool vsyncEnabled = mVsyncEnabled;
-
-#ifdef USE_HWC2
-    mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
-#else
-    mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC,
-            mVsyncEnabled);
-#endif
+    enum class VsyncState {Unset, On, Off};
+    auto currentVsyncState = VsyncState::Unset;
 
     while (true) {
-        status_t err = mCond.wait(mMutex);
-        if (err != NO_ERROR) {
-            ALOGE("error waiting for new events: %s (%d)",
-                strerror(-err), err);
-            return false;
+        auto requestedVsyncState = VsyncState::On;
+        {
+            Mutex::Autolock lock(mMutex);
+            requestedVsyncState =
+                    mVsyncEnabled ? VsyncState::On : VsyncState::Off;
+            while (currentVsyncState == requestedVsyncState) {
+                status_t err = mCond.wait(mMutex);
+                if (err != NO_ERROR) {
+                    ALOGE("error waiting for new events: %s (%d)",
+                          strerror(-err), err);
+                    return false;
+                }
+                requestedVsyncState =
+                        mVsyncEnabled ? VsyncState::On : VsyncState::Off;
+            }
         }
 
-        if (vsyncEnabled != mVsyncEnabled) {
+        bool enable = requestedVsyncState == VsyncState::On;
 #ifdef USE_HWC2
-            mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
+        mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable);
 #else
-            mFlinger->eventControl(HWC_DISPLAY_PRIMARY,
-                    SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled);
+        mFlinger->eventControl(HWC_DISPLAY_PRIMARY,
+                SurfaceFlinger::EVENT_VSYNC, enable);
 #endif
-            vsyncEnabled = mVsyncEnabled;
-        }
+        currentVsyncState = requestedVsyncState;
     }
 
     return false;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1b864fd..e92565f 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -40,6 +40,7 @@
 
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
+#include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 
 #include "clz.h"
@@ -200,6 +201,14 @@
     }
     mFlinger->deleteTextureAsync(mTextureName);
     mFrameTracker.logAndResetStats(mName);
+
+#ifdef USE_HWC2
+    if (!mHwcLayers.empty()) {
+        ALOGE("Found stale hardware composer layers when destroying "
+                "surface flinger layer %s", mName.string());
+        destroyAllHwcLayers();
+    }
+#endif
 }
 
 // ---------------------------------------------------------------------------
@@ -287,22 +296,29 @@
     }
 }
 
-// called with SurfaceFlinger::mStateLock from the drawing thread after
-// the layer has been remove from the current state list (and just before
-// it's removed from the drawing state list)
-void Layer::onRemoved() {
+void Layer::onRemovedFromCurrentState() {
+    // the layer is removed from SF mCurrentState to mLayersPendingRemoval
+
     if (mCurrentState.zOrderRelativeOf != nullptr) {
         sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
         if (strongRelative != nullptr) {
             strongRelative->removeZOrderRelative(this);
+            mFlinger->setTransactionFlags(eTraversalNeeded);
         }
         mCurrentState.zOrderRelativeOf = nullptr;
     }
 
-    mSurfaceFlingerConsumer->abandon();
+    for (const auto& child : mCurrentChildren) {
+        child->onRemovedFromCurrentState();
+    }
+}
 
+void Layer::onRemoved() {
+    // the layer is removed from SF mLayersPendingRemoval
+
+    mSurfaceFlingerConsumer->abandon();
 #ifdef USE_HWC2
-    clearHwcLayers();
+    destroyAllHwcLayers();
 #endif
 
     for (const auto& child : mCurrentChildren) {
@@ -363,6 +379,48 @@
 // h/w composer set-up
 // ---------------------------------------------------------------------------
 
+#ifdef USE_HWC2
+bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) {
+    LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0,
+                "Already have a layer for hwcId %d", hwcId);
+    HWC2::Layer* layer = hwc->createLayer(hwcId);
+    if (!layer) {
+        return false;
+    }
+    HWCInfo& hwcInfo = mHwcLayers[hwcId];
+    hwcInfo.hwc = hwc;
+    hwcInfo.layer = layer;
+    layer->setLayerDestroyedListener(
+            [this, hwcId] (HWC2::Layer* /*layer*/){mHwcLayers.erase(hwcId);});
+    return true;
+}
+
+void Layer::destroyHwcLayer(int32_t hwcId) {
+    if (mHwcLayers.count(hwcId) == 0) {
+        return;
+    }
+    auto& hwcInfo = mHwcLayers[hwcId];
+    LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr,
+            "Attempt to destroy null layer");
+    LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer");
+    hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer);
+    // The layer destroyed listener should have cleared the entry from
+    // mHwcLayers. Verify that.
+    LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0,
+            "Stale layer entry in mHwcLayers");
+}
+
+void Layer::destroyAllHwcLayers() {
+    size_t numLayers = mHwcLayers.size();
+    for (size_t i = 0; i < numLayers; ++i) {
+        LOG_ALWAYS_FATAL_IF(mHwcLayers.empty(), "destroyAllHwcLayers failed");
+        destroyHwcLayer(mHwcLayers.begin()->first);
+    }
+    LOG_ALWAYS_FATAL_IF(!mHwcLayers.empty(),
+            "All hardware composer layers should have been destroyed");
+}
+#endif
+
 Rect Layer::getContentCrop() const {
     // this is the crop rectangle that applies to the buffer
     // itself (as opposed to the window)
@@ -1309,7 +1367,8 @@
         // able to be latched. To avoid this, grab this buffer anyway.
         return true;
     }
-    return mQueueItems[0].mFence->getSignalTime() != INT64_MAX;
+    return mQueueItems[0].mFenceTime->getSignalTime() !=
+            Fence::SIGNAL_TIME_PENDING;
 #else
     return true;
 #endif
@@ -2011,9 +2070,6 @@
 bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
         const std::shared_ptr<FenceTime>& presentFence,
         const CompositorTiming& compositorTiming) {
-    mAcquireTimeline.updateSignalTimes();
-    mReleaseTimeline.updateSignalTimes();
-
     // mFrameLatencyNeeded is true when a new frame was latched for the
     // composition.
     if (!mFrameLatencyNeeded)
@@ -2064,6 +2120,7 @@
 
     auto releaseFenceTime = std::make_shared<FenceTime>(
             mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+    mReleaseTimeline.updateSignalTimes();
     mReleaseTimeline.push(releaseFenceTime);
 
     Mutex::Autolock lock(mFrameEventHistoryMutex);
@@ -2254,6 +2311,7 @@
 #ifndef USE_HWC2
         auto releaseFenceTime = std::make_shared<FenceTime>(
                 mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+        mReleaseTimeline.updateSignalTimes();
         mReleaseTimeline.push(releaseFenceTime);
         if (mPreviousFrameNumber != 0) {
             mFrameEventHistory.addRelease(mPreviousFrameNumber,
@@ -2363,69 +2421,51 @@
 // debugging
 // ----------------------------------------------------------------------------
 
-void Layer::dump(String8& result, Colorizer& colorizer) const
-{
-    const Layer::State& s(getDrawingState());
-
-    colorizer.colorize(result, Colorizer::GREEN);
-    result.appendFormat(
-            "+ %s %p (%s)\n",
-            getTypeId(), this, getName().string());
-    colorizer.reset(result);
-
-    s.activeTransparentRegion.dump(result, "transparentRegion");
-    visibleRegion.dump(result, "visibleRegion");
-    surfaceDamageRegion.dump(result, "surfaceDamageRegion");
-    sp<Client> client(mClientRef.promote());
-    PixelFormat pf = PIXEL_FORMAT_UNKNOWN;
-    const sp<GraphicBuffer>& buffer(getActiveBuffer());
-    if (buffer != NULL) {
-        pf = buffer->getPixelFormat();
+LayerDebugInfo Layer::getLayerDebugInfo() const {
+    LayerDebugInfo info;
+    const Layer::State& ds = getDrawingState();
+    info.mName = getName();
+    sp<Layer> parent = getParent();
+    info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
+    info.mType = String8(getTypeId());
+    info.mTransparentRegion = ds.activeTransparentRegion;
+    info.mVisibleRegion = visibleRegion;
+    info.mSurfaceDamageRegion = surfaceDamageRegion;
+    info.mLayerStack = getLayerStack();
+    info.mX = ds.active.transform.tx();
+    info.mY = ds.active.transform.ty();
+    info.mZ = ds.z;
+    info.mWidth = ds.active.w;
+    info.mHeight = ds.active.h;
+    info.mCrop = ds.crop;
+    info.mFinalCrop = ds.finalCrop;
+    info.mAlpha = ds.alpha;
+    info.mFlags = ds.flags;
+    info.mPixelFormat = getPixelFormat();
+    info.mDataSpace = getDataSpace();
+    info.mMatrix[0][0] = ds.active.transform[0][0];
+    info.mMatrix[0][1] = ds.active.transform[0][1];
+    info.mMatrix[1][0] = ds.active.transform[1][0];
+    info.mMatrix[1][1] = ds.active.transform[1][1];
+    {
+        sp<const GraphicBuffer> activeBuffer = getActiveBuffer();
+        if (activeBuffer != 0) {
+            info.mActiveBufferWidth = activeBuffer->getWidth();
+            info.mActiveBufferHeight = activeBuffer->getHeight();
+            info.mActiveBufferStride = activeBuffer->getStride();
+            info.mActiveBufferFormat = activeBuffer->format;
+        } else {
+            info.mActiveBufferWidth = 0;
+            info.mActiveBufferHeight = 0;
+            info.mActiveBufferStride = 0;
+            info.mActiveBufferFormat = 0;
+        }
     }
-
-    result.appendFormat(            "      "
-            "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), "
-            "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), "
-            "isOpaque=%1d, invalidate=%1d, "
-            "dataspace=%s, pixelformat=%s "
-#ifdef USE_HWC2
-            "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
-#else
-            "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
-#endif
-            "      client=%p\n",
-            getLayerStack(), s.z,
-            s.active.transform.tx(), s.active.transform.ty(),
-            s.active.w, s.active.h,
-            s.crop.left, s.crop.top,
-            s.crop.right, s.crop.bottom,
-            s.finalCrop.left, s.finalCrop.top,
-            s.finalCrop.right, s.finalCrop.bottom,
-            isOpaque(s), contentDirty,
-            dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(),
-            s.alpha, s.flags,
-            s.active.transform[0][0], s.active.transform[0][1],
-            s.active.transform[1][0], s.active.transform[1][1],
-            client.get());
-
-    sp<const GraphicBuffer> buf0(mActiveBuffer);
-    uint32_t w0=0, h0=0, s0=0, f0=0;
-    if (buf0 != 0) {
-        w0 = buf0->getWidth();
-        h0 = buf0->getHeight();
-        s0 = buf0->getStride();
-        f0 = buf0->format;
-    }
-    result.appendFormat(
-            "      "
-            "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
-            " queued-frames=%d, mRefreshPending=%d\n",
-            mFormat, w0, h0, s0,f0,
-            mQueuedFrames, mRefreshPending);
-
-    if (mSurfaceFlingerConsumer != 0) {
-        mSurfaceFlingerConsumer->dumpState(result, "            ");
-    }
+    info.mNumQueuedFrames = getQueuedFrameCount();
+    info.mRefreshPending = isBufferLatched();
+    info.mIsOpaque = isOpaque(ds);
+    info.mContentDirty = contentDirty;
+    return info;
 }
 
 #ifdef USE_HWC2
@@ -2509,6 +2549,12 @@
         FrameEventHistoryDelta *outDelta) {
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     if (newTimestamps) {
+        // If there are any unsignaled fences in the aquire timeline at this
+        // point, the previously queued frame hasn't been latched yet. Go ahead
+        // and try to get the signal time here so the syscall is taken out of
+        // the main thread's critical path.
+        mAcquireTimeline.updateSignalTimes();
+        // Push the new fence after updating since it's likely still pending.
         mAcquireTimeline.push(newTimestamps->acquireFence);
         mFrameEventHistory.addQueue(*newTimestamps);
     }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2306d1a..f7b82e4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -60,6 +60,7 @@
 class DisplayDevice;
 class GraphicBuffer;
 class SurfaceFlinger;
+class LayerDebugInfo;
 
 // ---------------------------------------------------------------------------
 
@@ -419,8 +420,14 @@
     bool isPotentialCursor() const { return mPotentialCursor;}
 
     /*
-     * called with the state lock when the surface is removed from the
-     * current list
+     * called with the state lock from a binder thread when the layer is
+     * removed from the current list to the pending removal list
+     */
+    void onRemovedFromCurrentState();
+
+    /*
+     * called with the state lock from the main thread when the layer is
+     * removed from the pending removal list
      */
     void onRemoved();
 
@@ -441,40 +448,26 @@
     bool hasQueuedFrame() const { return mQueuedFrames > 0 ||
             mSidebandStreamChanged || mAutoRefresh; }
 
+    int32_t getQueuedFrameCount() const { return mQueuedFrames; }
+
 #ifdef USE_HWC2
     // -----------------------------------------------------------------------
 
+    bool createHwcLayer(HWComposer* hwc, int32_t hwcId);
+    void destroyHwcLayer(int32_t hwcId);
+    void destroyAllHwcLayers();
+
     bool hasHwcLayer(int32_t hwcId) {
-        if (mHwcLayers.count(hwcId) == 0) {
-            return false;
-        }
-        if (mHwcLayers[hwcId].layer->isAbandoned()) {
-            ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId);
-            mHwcLayers.erase(hwcId);
-            return false;
-        }
-        return true;
+        return mHwcLayers.count(hwcId) > 0;
     }
 
-    std::shared_ptr<HWC2::Layer> getHwcLayer(int32_t hwcId) {
+    HWC2::Layer* getHwcLayer(int32_t hwcId) {
         if (mHwcLayers.count(hwcId) == 0) {
             return nullptr;
         }
         return mHwcLayers[hwcId].layer;
     }
 
-    void setHwcLayer(int32_t hwcId, std::shared_ptr<HWC2::Layer>&& layer) {
-        if (layer) {
-            mHwcLayers[hwcId].layer = layer;
-        } else {
-            mHwcLayers.erase(hwcId);
-        }
-    }
-
-    void clearHwcLayers() {
-        mHwcLayers.clear();
-    }
-
 #endif
     // -----------------------------------------------------------------------
 
@@ -489,9 +482,9 @@
     inline  const State&    getCurrentState() const { return mCurrentState; }
     inline  State&          getCurrentState()       { return mCurrentState; }
 
+    LayerDebugInfo getLayerDebugInfo() const;
 
     /* always call base class first */
-    void dump(String8& result, Colorizer& colorizer) const;
 #ifdef USE_HWC2
     static void miniDumpHeader(String8& result);
     void miniDump(String8& result, int32_t hwcId) const;
@@ -689,6 +682,9 @@
     sp<IGraphicBufferProducer> getProducer() const;
     const String8& getName() const;
     void notifyAvailableFrames();
+
+    PixelFormat getPixelFormat() const { return mFormat; }
+
 private:
 
     // -----------------------------------------------------------------------
@@ -760,12 +756,14 @@
     // HWC items, accessed from the main thread
     struct HWCInfo {
         HWCInfo()
-          : layer(),
+          : hwc(nullptr),
+            layer(nullptr),
             forceClientComposition(false),
             compositionType(HWC2::Composition::Invalid),
             clearClientTarget(false) {}
 
-        std::shared_ptr<HWC2::Layer> layer;
+        HWComposer* hwc;
+        HWC2::Layer* layer;
         bool forceClientComposition;
         HWC2::Composition compositionType;
         bool clearClientTarget;
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index e717632..1a5a85e 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -68,11 +68,11 @@
     return mProducer->setAsyncMode(async);
 }
 
-status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence,
-        uint32_t w, uint32_t h, PixelFormat format, uint64_t usage,
-        FrameEventHistoryDelta* outTimestamps) {
-    return mProducer->dequeueBuffer(
-            slot, fence, w, h, format, usage, outTimestamps);
+status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+                                          PixelFormat format, uint64_t usage,
+                                          uint64_t* outBufferAge,
+                                          FrameEventHistoryDelta* outTimestamps) {
+    return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps);
 }
 
 status_t MonitoredProducer::detachBuffer(int slot) {
@@ -158,6 +158,10 @@
     return mProducer->getUniqueId(outId);
 }
 
+status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const {
+    return mProducer->getConsumerUsage(outUsage);
+}
+
 IBinder* MonitoredProducer::onAsBinder() {
     return this;
 }
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 58b9bc4..1246d14 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -39,9 +39,9 @@
     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
     virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
     virtual status_t setAsyncMode(bool async);
-    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, PixelFormat format, uint64_t usage,
-            FrameEventHistoryDelta* outTimestamps);
+    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+                                   PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+                                   FrameEventHistoryDelta* outTimestamps);
     virtual status_t detachBuffer(int slot);
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence);
@@ -68,6 +68,7 @@
     virtual status_t setAutoRefresh(bool autoRefresh) override;
     virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override;
     virtual status_t getUniqueId(uint64_t* outId) const override;
+    virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
 
     // The Layer which created this producer, and on which queued Buffer's will be displayed.
     sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 7e5eda0..56e9ac0 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -64,7 +64,7 @@
                        "EGL_ANDROIDX_no_config_context") &&
         !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
                        "EGL_KHR_no_config_context")) {
-        config = chooseEglConfig(display, hwcFormat);
+        config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
 
     EGLint renderableType = 0;
@@ -108,7 +108,7 @@
 
     EGLConfig dummyConfig = config;
     if (dummyConfig == EGL_NO_CONFIG) {
-        dummyConfig = chooseEglConfig(display, hwcFormat);
+        dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
     EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE };
     EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
@@ -406,7 +406,8 @@
     return err;
 }
 
-EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) {
+EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format,
+                                        bool logConfig) {
     status_t err;
     EGLConfig config;
 
@@ -427,18 +428,20 @@
         }
     }
 
-    // print some debugging info
-    EGLint r,g,b,a;
-    eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
-    eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
-    eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
-    eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
-    ALOGI("EGL information:");
-    ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
-    ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
-    ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
-    ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
-    ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+    if (logConfig) {
+        // print some debugging info
+        EGLint r,g,b,a;
+        eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
+        eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+        eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
+        eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
+        ALOGI("EGL information:");
+        ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
+        ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
+        ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
+        ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+        ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+    }
 
     return config;
 }
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 56f5827..9544579 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -64,7 +64,7 @@
     };
     static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags);
 
-    static EGLConfig chooseEglConfig(EGLDisplay display, int format);
+    static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
 
     void primeCache() const;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d29d9c1..78ec4fd 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -46,6 +46,7 @@
 #include <gui/BufferQueue.h>
 #include <gui/GuiConfig.h>
 #include <gui/IDisplayEventConnection.h>
+#include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 
 #include <ui/GraphicBufferAllocator.h>
@@ -76,6 +77,7 @@
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 
+#include "DisplayHardware/ComposerHal.h"
 #include "DisplayHardware/FramebufferSurface.h"
 #include "DisplayHardware/HWComposer.h"
 #include "DisplayHardware/VirtualDisplaySurface.h"
@@ -100,10 +102,24 @@
 
 namespace android {
 
-
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
+namespace {
+class ConditionalLock {
+public:
+    ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) {
+        if (lock) {
+            mMutex.lock();
+        }
+    }
+    ~ConditionalLock() { if (mLocked) mMutex.unlock(); }
+private:
+    Mutex& mMutex;
+    bool mLocked;
+};
+}  // namespace anonymous
+
 // ---------------------------------------------------------------------------
 
 const String16 sHardwareTest("android.permission.HARDWARE_TEST");
@@ -123,6 +139,21 @@
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 bool SurfaceFlinger::hasWideColorDisplay;
 
+
+std::string getHwcServiceName() {
+    char value[PROPERTY_VALUE_MAX] = {};
+    property_get("debug.sf.hwc_service_name", value, "default");
+    ALOGI("Using HWComposer service: '%s'", value);
+    return std::string(value);
+}
+
+bool useTrebleTestingOverride() {
+    char value[PROPERTY_VALUE_MAX] = {};
+    property_get("debug.sf.treble_testing_override", value, "false");
+    ALOGI("Treble testing override: '%s'", value);
+    return std::string(value) == "true";
+}
+
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
         mTransactionFlags(0),
@@ -131,9 +162,7 @@
         mLayersRemoved(false),
         mLayersAdded(false),
         mRepaintEverything(0),
-        mHwc(nullptr),
-        mRealHwc(nullptr),
-        mVrHwc(nullptr),
+        mHwcServiceName(getHwcServiceName()),
         mRenderEngine(nullptr),
         mBootTime(systemTime()),
         mBuiltinDisplays(),
@@ -160,7 +189,9 @@
         mTotalTime(0),
         mLastSwapTime(0),
         mNumLayers(0),
-        mVrFlingerRequestsDisplay(false)
+        mVrFlingerRequestsDisplay(false),
+        mMainThreadId(std::this_thread::get_id()),
+        mComposerSequenceId(0)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -233,6 +264,15 @@
     // but since /data may be encrypted, we need to wait until after vold
     // comes online to attempt to read the property. The property is
     // instead read after the boot animation
+
+    if (useTrebleTestingOverride()) {
+        // Without the override SurfaceFlinger cannot connect to HIDL
+        // services that are not listed in the manifests.  Considered
+        // deriving the setting from the set service name, but it
+        // would be brittle if the name that's not 'default' is used
+        // for production purposes later on.
+        setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+    }
 }
 
 void SurfaceFlinger::onFirstRef()
@@ -547,61 +587,35 @@
 
     ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
 
-    { // Autolock scope
-        Mutex::Autolock _l(mStateLock);
-
-        // initialize EGL for the default display
-        mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        eglInitialize(mEGLDisplay, NULL, NULL);
-
-        // start the EventThread
-        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
-                vsyncPhaseOffsetNs, true, "app");
-        mEventThread = new EventThread(vsyncSrc, *this, false);
-        sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
-                sfVsyncPhaseOffsetNs, true, "sf");
-        mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
-        mEventQueue.setEventThread(mSFEventThread);
-
-        // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
-        struct sched_param param = {0};
-        param.sched_priority = 2;
-        if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-            ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
-        }
-        if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-            ALOGE("Couldn't set SCHED_FIFO for EventThread");
-        }
-
-        // Get a RenderEngine for the given display / config (can't fail)
-        mRenderEngine = RenderEngine::create(mEGLDisplay,
-                HAL_PIXEL_FORMAT_RGBA_8888,
-                hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
-    }
-
-    // Drop the state lock while we initialize the hardware composer. We drop
-    // the lock because on creation, it will call back into SurfaceFlinger to
-    // initialize the primary display.
-    LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
-        "Starting with vr flinger active is not currently supported.");
-    mRealHwc = new HWComposer(false);
-    mHwc = mRealHwc;
-    mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
-
     Mutex::Autolock _l(mStateLock);
 
-    if (useVrFlinger) {
-        auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
-            ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
-            mVrFlingerRequestsDisplay = requestDisplay;
-            signalTransaction();
-        };
-        mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
-                                            vrFlingerRequestDisplayCallback);
-        if (!mVrFlinger) {
-            ALOGE("Failed to start vrflinger");
-        }
+    // initialize EGL for the default display
+    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    eglInitialize(mEGLDisplay, NULL, NULL);
+
+    // start the EventThread
+    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+            vsyncPhaseOffsetNs, true, "app");
+    mEventThread = new EventThread(vsyncSrc, *this, false);
+    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+            sfVsyncPhaseOffsetNs, true, "sf");
+    mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
+    mEventQueue.setEventThread(mSFEventThread);
+
+    // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
+    struct sched_param param = {0};
+    param.sched_priority = 2;
+    if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
     }
+    if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for EventThread");
+    }
+
+    // Get a RenderEngine for the given display / config (can't fail)
+    mRenderEngine = RenderEngine::create(mEGLDisplay,
+            HAL_PIXEL_FORMAT_RGBA_8888,
+            hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
 
     // retrieve the EGL context that was selected/created
     mEGLContext = mRenderEngine->getEGLContext();
@@ -609,9 +623,32 @@
     LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
             "couldn't create EGLContext");
 
-    // make the GLContext current so that we can create textures when creating
-    // Layers (which may happens before we render something)
-    getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext);
+    LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
+            "Starting with vr flinger active is not currently supported.");
+    mHwc.reset(new HWComposer(mHwcServiceName));
+    mHwc->registerCallback(this, mComposerSequenceId);
+
+    if (useVrFlinger) {
+        auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
+            // This callback is called from the vr flinger dispatch thread. We
+            // need to call signalTransaction(), which requires holding
+            // mStateLock when we're not on the main thread. Acquiring
+            // mStateLock from the vr flinger dispatch thread might trigger a
+            // deadlock in surface flinger (see b/66916578), so post a message
+            // to be handled on the main thread instead.
+            sp<LambdaMessage> message = new LambdaMessage([=]() {
+                ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
+                mVrFlingerRequestsDisplay = requestDisplay;
+                signalTransaction();
+            });
+            postMessageAsync(message);
+        };
+        mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
+                                            vrFlingerRequestDisplayCallback);
+        if (!mVrFlinger) {
+            ALOGE("Failed to start vrflinger");
+        }
+    }
 
     mEventControlThread = new EventControlThread(this);
     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
@@ -691,6 +728,8 @@
         FrameEvent::DEQUEUE_READY,
         FrameEvent::RELEASE,
     };
+    ConditionalLock _l(mStateLock,
+            std::this_thread::get_id() != mMainThreadId);
     if (!getHwComposer().hasCapability(
             HWC2::Capability::PresentFenceIsNotReliable)) {
         outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
@@ -738,6 +777,8 @@
 
     configs->clear();
 
+    ConditionalLock _l(mStateLock,
+            std::this_thread::get_id() != mMainThreadId);
     for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
         DisplayInfo info = DisplayInfo();
 
@@ -761,7 +802,7 @@
             info.density = density;
 
             // TODO: this needs to go away (currently needed only by webkit)
-            sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+            sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
             info.orientation = hw->getOrientation();
         } else {
             // TODO: where should this value come from?
@@ -904,7 +945,12 @@
         return type;
     }
 
-    std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
+    std::vector<android_color_mode_t> modes;
+    {
+        ConditionalLock _l(mStateLock,
+                std::this_thread::get_id() != mMainThreadId);
+        modes = getHwComposer().getColorModes(type);
+    }
     outColorModes->clear();
     std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
 
@@ -1045,6 +1091,33 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_SHELL) &&
+            !PermissionCache::checkPermission(sDump, pid, uid)) {
+        ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
+        return PERMISSION_DENIED;
+    }
+
+    // Try to acquire a lock for 1s, fail gracefully
+    const status_t err = mStateLock.timedLock(s2ns(1));
+    const bool locked = (err == NO_ERROR);
+    if (!locked) {
+        ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err);
+        return TIMED_OUT;
+    }
+
+    outLayers->clear();
+    mCurrentState.traverseInZOrder([&](Layer* layer) {
+        outLayers->push_back(layer->getLayerDebugInfo());
+    });
+
+    mStateLock.unlock();
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -1155,11 +1228,16 @@
     sLastResyncAttempted = now;
 }
 
-void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type,
-                                     nsecs_t timestamp) {
+void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
+        hwc2_display_t displayId, int64_t timestamp) {
     Mutex::Autolock lock(mStateLock);
-    // Ignore any vsyncs from the non-active hardware composer.
-    if (composer != mHwc) {
+    // Ignore any vsyncs from a previous hardware composer.
+    if (sequenceId != mComposerSequenceId) {
+        return;
+    }
+
+    int32_t type;
+    if (!mHwc->onVsync(displayId, timestamp, &type)) {
         return;
     }
 
@@ -1167,7 +1245,7 @@
 
     { // Scope for the lock
         Mutex::Autolock _l(mHWVsyncLock);
-        if (type == 0 && mPrimaryHWVsyncEnabled) {
+        if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) {
             needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
         }
     }
@@ -1185,7 +1263,7 @@
 }
 
 void SurfaceFlinger::createDefaultDisplayDevice() {
-    const int32_t type = DisplayDevice::DISPLAY_PRIMARY;
+    const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY;
     wp<IBinder> token = mBuiltinDisplays[type];
 
     // All non-virtual displays are currently considered secure.
@@ -1220,28 +1298,49 @@
     }
     setActiveColorModeInternal(hw, defaultColorMode);
     hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
+
+    // Add the primary display token to mDrawingState so we don't try to
+    // recreate the DisplayDevice for the primary display.
+    mDrawingState.displays.add(token, DisplayDeviceState(type, true));
+
+    // make the GLContext current so that we can create textures when creating
+    // Layers (which may happens before we render something)
+    hw->makeCurrent(mEGLDisplay, mEGLContext);
 }
 
-void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) {
-    ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false");
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
+        hwc2_display_t display, HWC2::Connection connection,
+        bool primaryDisplay) {
+    ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)",
+          sequenceId, display,
+          connection == HWC2::Connection::Connected ?
+                  "connected" : "disconnected",
+          primaryDisplay ? "primary" : "external");
 
-    if (composer->isUsingVrComposer()) {
-        // We handle initializing the primary display device for the VR
-        // window manager hwc explicitly at the time of transition.
-        if (disp != DisplayDevice::DISPLAY_PRIMARY) {
-            ALOGE("External displays are not supported by the vr hardware composer.");
+    // Only lock if we're not on the main thread. This function is normally
+    // called on a hwbinder thread, but for the primary display it's called on
+    // the main thread with the state lock already held, so don't attempt to
+    // acquire it here.
+    ConditionalLock lock(mStateLock,
+            std::this_thread::get_id() != mMainThreadId);
+
+    if (primaryDisplay) {
+        mHwc->onHotplug(display, connection);
+        if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) {
+            createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
         }
-        return;
-    }
-
-    if (disp == DisplayDevice::DISPLAY_PRIMARY) {
-        Mutex::Autolock lock(mStateLock);
-        createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
         createDefaultDisplayDevice();
     } else {
+        if (sequenceId != mComposerSequenceId) {
+            return;
+        }
+        if (mHwc->isUsingVrComposer()) {
+            ALOGE("External displays are not supported by the vr hardware composer.");
+            return;
+        }
+        mHwc->onHotplug(display, connection);
         auto type = DisplayDevice::DISPLAY_EXTERNAL;
-        Mutex::Autolock _l(mStateLock);
-        if (connected) {
+        if (connection == HWC2::Connection::Connected) {
             createBuiltinDisplayLocked(type);
         } else {
             mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
@@ -1253,46 +1352,31 @@
     }
 }
 
-void SurfaceFlinger::onInvalidateReceived(HWComposer* composer) {
+void SurfaceFlinger::onRefreshReceived(int sequenceId,
+                                       hwc2_display_t /*display*/) {
     Mutex::Autolock lock(mStateLock);
-    if (composer == mHwc) {
-        repaintEverything();
-    } else {
-        // This isn't from our current hardware composer. If it's a callback
-        // from the real composer, forward the refresh request to vr
-        // flinger. Otherwise ignore it.
-        if (!composer->isUsingVrComposer()) {
-            mVrFlinger->OnHardwareComposerRefresh();
-        }
+    if (sequenceId != mComposerSequenceId) {
+        return;
     }
+    repaintEverythingLocked();
 }
 
 void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
     ATRACE_CALL();
+    Mutex::Autolock lock(mStateLock);
     getHwComposer().setVsyncEnabled(disp,
             enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
 }
 
 // Note: it is assumed the caller holds |mStateLock| when this is called
-void SurfaceFlinger::resetHwcLocked() {
+void SurfaceFlinger::resetDisplayState() {
     disableHardwareVsync(true);
-    clearHwcLayers(mDrawingState.layersSortedByZ);
-    clearHwcLayers(mCurrentState.layersSortedByZ);
-    for (size_t disp = 0; disp < mDisplays.size(); ++disp) {
-        clearHwcLayers(mDisplays[disp]->getVisibleLayersSortedByZ());
-    }
     // Clear the drawing state so that the logic inside of
     // handleTransactionLocked will fire. It will determine the delta between
     // mCurrentState and mDrawingState and re-apply all changes when we make the
     // transition.
     mDrawingState.displays.clear();
-    // Release virtual display hwcId during vr mode transition.
-    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
-        const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
-        if (displayDevice->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL) {
-            displayDevice->disconnect(getHwComposer());
-        }
-    }
+    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     mDisplays.clear();
 }
 
@@ -1304,57 +1388,54 @@
         return;
     }
 
-    if (vrFlingerRequestsDisplay && !mVrHwc) {
-        // Construct new HWComposer without holding any locks.
-        mVrHwc = new HWComposer(true);
-
-        // Set up the event handlers. This step is neccessary to initialize the internal state of
-        // the hardware composer object properly. Our callbacks are designed such that if they are
-        // triggered between now and the point where the display is properly re-initialized, they
-        // will not have any effect, so this is safe to do here, before the lock is aquired.
-        mVrHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
-        ALOGV("Vr HWC created");
+    if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) {
+        ALOGE("Vr flinger is only supported for remote hardware composer"
+              " service connections. Ignoring request to transition to vr"
+              " flinger.");
+        mVrFlingerRequestsDisplay = false;
+        return;
     }
 
     Mutex::Autolock _l(mStateLock);
 
-    if (vrFlingerRequestsDisplay) {
-        resetHwcLocked();
+    int currentDisplayPowerMode = getDisplayDeviceLocked(
+            mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode();
 
-        mHwc = mVrHwc;
-        mVrFlinger->GrantDisplayOwnership();
-
-    } else {
+    if (!vrFlingerRequestsDisplay) {
         mVrFlinger->SeizeDisplayOwnership();
+    }
 
-        resetHwcLocked();
+    resetDisplayState();
+    mHwc.reset();  // Delete the current instance before creating the new one
+    mHwc.reset(new HWComposer(
+            vrFlingerRequestsDisplay ? "vr" : mHwcServiceName));
+    mHwc->registerCallback(this, ++mComposerSequenceId);
 
-        mHwc = mRealHwc;
+    LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(),
+            "Switched to non-remote hardware composer");
+
+    if (vrFlingerRequestsDisplay) {
+        mVrFlinger->GrantDisplayOwnership();
+    } else {
         enableHardwareVsync();
     }
 
     mVisibleRegionsDirty = true;
     invalidateHwcGeometry();
 
-    // Explicitly re-initialize the primary display. This is because some other
-    // parts of this class rely on the primary display always being available.
-    createDefaultDisplayDevice();
-
     // Re-enable default display.
-    sp<LambdaMessage> requestMessage = new LambdaMessage([&]() {
-        sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
-        setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL);
+    sp<DisplayDevice> hw(getDisplayDeviceLocked(
+            mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
+    setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true);
 
-        // Reset the timing values to account for the period of the swapped in HWC
-        const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
-        const nsecs_t period = activeConfig->getVsyncPeriod();
-        mAnimFrameTracker.setDisplayRefreshPeriod(period);
+    // Reset the timing values to account for the period of the swapped in HWC
+    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const nsecs_t period = activeConfig->getVsyncPeriod();
+    mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
-        // Use phase of 0 since phase is not known.
-        // Use latency of 0, which will snap to the ideal latency.
-        setCompositorTimingSnapped(0, period, 0);
-    });
-    postMessageAsync(requestMessage);
+    // Use phase of 0 since phase is not known.
+    // Use latency of 0, which will snap to the ideal latency.
+    setCompositorTimingSnapped(0, period, 0);
 
     android_atomic_or(1, &mRepaintEverything);
     setTransactionFlags(eDisplayTransactionNeeded);
@@ -1370,7 +1451,6 @@
                             Fence::SIGNAL_TIME_PENDING);
             ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
             if (mPropagateBackpressure && frameMissed) {
-                ALOGD("Backpressure trigger, skipping transaction & refresh!");
                 signalLayerUpdate();
                 break;
             }
@@ -1572,6 +1652,7 @@
     // |mStateLock| not needed as we are on the main thread
     const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
 
+    mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
     if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
         glCompositionDoneFenceTime =
@@ -1580,12 +1661,11 @@
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
-    mGlCompositionDoneTimeline.updateSignalTimes();
 
+    mDisplayTimeline.updateSignalTimes();
     sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
     auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
     mDisplayTimeline.push(presentFenceTime);
-    mDisplayTimeline.updateSignalTimes();
 
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
     nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1610,8 +1690,8 @@
         }
     });
 
-    if (presentFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(presentFence)) {
+    if (presentFenceTime->isValid()) {
+        if (mPrimaryDispSync.addPresentFence(presentFenceTime)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -1691,15 +1771,14 @@
                         } else {
                             // Clear out the HWC layer if this layer was
                             // previously visible, but no longer is
-                            layer->setHwcLayer(displayDevice->getHwcDisplayId(),
-                                    nullptr);
+                            layer->destroyHwcLayer(
+                                    displayDevice->getHwcDisplayId());
                         }
                     } else {
                         // WM changes displayDevice->layerStack upon sleep/awake.
                         // Here we make sure we delete the HWC layers even if
                         // WM changed their layer stack.
-                        layer->setHwcLayer(displayDevice->getHwcDisplayId(),
-                                nullptr);
+                        layer->destroyHwcLayer(displayDevice->getHwcDisplayId());
                     }
                 });
             }
@@ -1814,10 +1893,7 @@
                 for (size_t i = 0; i < currentLayers.size(); i++) {
                     const auto& layer = currentLayers[i];
                     if (!layer->hasHwcLayer(hwcId)) {
-                        auto hwcLayer = mHwc->createLayer(hwcId);
-                        if (hwcLayer) {
-                            layer->setHwcLayer(hwcId, std::move(hwcLayer));
-                        } else {
+                        if (!layer->createHwcLayer(mHwc.get(), hwcId)) {
                             layer->forceClientComposition(hwcId);
                             continue;
                         }
@@ -2098,7 +2174,7 @@
                         if (state.surface != NULL) {
 
                             // Allow VR composer to use virtual displays.
-                            if (mUseHwcVirtualDisplays || mHwc == mVrHwc) {
+                            if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) {
                                 int width = 0;
                                 int status = state.surface->query(
                                         NATIVE_WINDOW_WIDTH, &width);
@@ -2775,6 +2851,7 @@
         return NO_ERROR;
     }
 
+    layer->onRemovedFromCurrentState();
     mLayersPendingRemoval.add(layer);
     mLayersRemoved = true;
     mNumLayers -= 1 + layer->getChildrenCount();
@@ -2972,7 +3049,10 @@
             }
         }
         if (what & layer_state_t::eRelativeLayerChanged) {
+            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
             if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
+                mCurrentState.layersSortedByZ.removeAt(idx);
+                mCurrentState.layersSortedByZ.add(layer);
                 flags |= eTransactionNeeded|eTraversalNeeded;
             }
         }
@@ -3221,7 +3301,8 @@
     d.height = 0;
     displays.add(d);
     setTransactionState(state, displays, 0);
-    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
+    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
+                         /*stateLockHeld*/ false);
 
     const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
@@ -3247,7 +3328,7 @@
 }
 
 void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
-        int mode) {
+             int mode, bool stateLockHeld) {
     ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
             this);
     int32_t type = hw->getDisplayType();
@@ -3264,7 +3345,7 @@
     }
 
     if (mInterceptor.isEnabled()) {
-        Mutex::Autolock _l(mStateLock);
+        ConditionalLock lock(mStateLock, !stateLockHeld);
         ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken());
         if (idx < 0) {
             ALOGW("Surface Interceptor SavePowerMode: invalid display token");
@@ -3285,7 +3366,7 @@
 
         mVisibleRegionsDirty = true;
         mHasPoweredOff = true;
-        repaintEverything();
+        repaintEverythingLocked();
 
         struct sched_param param = {0};
         param.sched_priority = 1;
@@ -3350,7 +3431,8 @@
                 ALOGW("Attempt to set power mode = %d for virtual display",
                         mMode);
             } else {
-                mFlinger.setPowerModeInternal(hw, mMode);
+                mFlinger.setPowerModeInternal(
+                        hw, mMode, /*stateLockHeld*/ false);
             }
             return true;
         }
@@ -3695,7 +3777,7 @@
     result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
     colorizer.reset(result);
     mCurrentState.traverseInZOrder([&](Layer* layer) {
-        layer->dump(result, colorizer);
+        result.append(to_string(layer->getLayerDebugInfo()).c_str());
     });
 
     /*
@@ -3928,6 +4010,7 @@
                 return NO_ERROR;
             }
             case 1005:{ // force transaction
+                Mutex::Autolock _l(mStateLock);
                 setTransactionFlags(
                         eTransactionNeeded|
                         eDisplayTransactionNeeded|
@@ -4064,11 +4147,17 @@
     return err;
 }
 
-void SurfaceFlinger::repaintEverything() {
+void SurfaceFlinger::repaintEverythingLocked() {
     android_atomic_or(1, &mRepaintEverything);
     signalTransaction();
 }
 
+void SurfaceFlinger::repaintEverything() {
+    ConditionalLock _l(mStateLock,
+            std::this_thread::get_id() != mMainThreadId);
+    repaintEverythingLocked();
+}
+
 // Checks that the requested width and height are valid and updates them to the display dimensions
 // if they are set to 0
 static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index acfad46..1b77aaf 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -60,13 +60,20 @@
 #include "SurfaceInterceptor.h"
 #include "StartPropertySetThread.h"
 
+#ifdef USE_HWC2
+#include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/HWComposer.h"
+#else
+#include "DisplayHardware/HWComposer_hwc1.h"
+#endif
+
 #include "Effects/Daltonizer.h"
 
 #include <map>
 #include <mutex>
 #include <queue>
 #include <string>
+#include <thread>
 #include <utility>
 
 namespace android {
@@ -99,7 +106,11 @@
 
 class SurfaceFlinger : public BnSurfaceComposer,
                        private IBinder::DeathRecipient,
+#ifdef USE_HWC2
+                       private HWC2::ComposerCallback
+#else
                        private HWComposer::EventHandler
+#endif
 {
 public:
 
@@ -181,6 +192,8 @@
 
     // force full composition on all displays
     void repaintEverything();
+    // Can only be called from the main thread or with mStateLock held
+    void repaintEverythingLocked();
 
     // returns the default Display
     sp<const DisplayDevice> getDefaultDisplayDevice() const {
@@ -300,6 +313,7 @@
             HdrCapabilities* outCapabilities) const;
     virtual status_t enableVSyncInjections(bool enable);
     virtual status_t injectVSync(nsecs_t when);
+    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
 
 
     /* ------------------------------------------------------------------------
@@ -313,17 +327,28 @@
     virtual void onFirstRef();
 
     /* ------------------------------------------------------------------------
-     * HWComposer::EventHandler interface
+     * HWC2::ComposerCallback / HWComposer::EventHandler interface
      */
-    virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp);
-    virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected);
-    virtual void onInvalidateReceived(HWComposer* composer);
+#ifdef USE_HWC2
+    void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
+                         int64_t timestamp) override;
+    void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+                           HWC2::Connection connection,
+                           bool primaryDisplay) override;
+    void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override;
+#else
+    void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp) override;
+    void onHotplugReceived(HWComposer* composer, int disp, bool connected) override;
+    void onInvalidateReceived(HWComposer* composer) override;
+#endif
 
     /* ------------------------------------------------------------------------
      * Message handling
      */
     void waitForEvent();
+    // Can only be called from the main thread or with mStateLock held
     void signalTransaction();
+    // Can only be called from the main thread or with mStateLock held
     void signalLayerUpdate();
     void signalRefresh();
 
@@ -332,7 +357,12 @@
     // called on the main thread in response to setActiveConfig()
     void setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode);
     // called on the main thread in response to setPowerMode()
+#ifdef USE_HWC2
+    void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode,
+                              bool stateLockHeld);
+#else
     void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode);
+#endif
 
     // Called on the main thread in response to setActiveColorMode()
     void setActiveColorModeInternal(const sp<DisplayDevice>& hw, android_color_mode_t colorMode);
@@ -361,6 +391,7 @@
      */
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t peekTransactionFlags();
+    // Can only be called from the main thread or with mStateLock held
     uint32_t setTransactionFlags(uint32_t flags);
     void commitTransaction();
     uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s);
@@ -590,13 +621,7 @@
     /* ------------------------------------------------------------------------
      * VrFlinger
      */
-    template<typename T>
-    void clearHwcLayers(const T& layers) {
-        for (size_t i = 0; i < layers.size(); ++i) {
-            layers[i]->clearHwcLayers();
-        }
-    }
-    void resetHwcLocked();
+    void resetDisplayState();
 
     // Check to see if we should handoff to vr flinger.
     void updateVrFlinger();
@@ -623,12 +648,32 @@
     // access must be protected by mInvalidateLock
     volatile int32_t mRepaintEverything;
 
-    // current, real and vr hardware composers.
-    HWComposer* mHwc;
+    // The current hardware composer interface.
+    //
+    // The following thread safety rules apply when accessing mHwc, either
+    // directly or via getHwComposer():
+    //
+    // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
+    //    only when switching into and out of vr. Recreating mHwc must only be
+    //    done on the main thread.
+    //
+    // 2. When accessing mHwc on the main thread, it's not necessary to acquire
+    //    mStateLock.
+    //
+    // 3. When accessing mHwc on a thread other than the main thread, we always
+    //    need to acquire mStateLock. This is because the main thread could be
+    //    in the process of destroying the current mHwc instance.
+    //
+    // The above thread safety rules only apply to SurfaceFlinger.cpp. In
+    // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
+    // destroy it, so it's always safe to access mHwc from any thread without
+    // acquiring mStateLock.
+    std::unique_ptr<HWComposer> mHwc;
+
 #ifdef USE_HWC2
-    HWComposer* mRealHwc;
-    HWComposer* mVrHwc;
+    const std::string mHwcServiceName; // "default" for real use, something else for testing.
 #endif
+
     // constant members (no synchronization needed for access)
     RenderEngine* mRenderEngine;
     nsecs_t mBootTime;
@@ -642,10 +687,6 @@
     EGLDisplay mEGLDisplay;
     sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
 
-#ifdef USE_HWC2
-    std::unique_ptr<dvr::VrFlinger> mVrFlinger;
-#endif
-
     // Can only accessed from the main thread, these members
     // don't need synchronization
     State mDrawingState{LayerVector::StateSet::Drawing};
@@ -767,8 +808,14 @@
     status_t CheckTransactCodeCredentials(uint32_t code);
 
 #ifdef USE_HWC2
+    std::unique_ptr<dvr::VrFlinger> mVrFlinger;
     std::atomic<bool> mVrFlingerRequestsDisplay;
     static bool useVrFlinger;
+    std::thread::id mMainThreadId;
+    // The composer sequence id is a monotonically increasing integer that we
+    // use to differentiate callbacks from different hardware composer
+    // instances. Each hardware composer instance gets a different sequence id.
+    int32_t mComposerSequenceId;
 #endif
 
     float mSaturation = 1.0f;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index e2fdf96..a92e1f9 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -41,6 +41,7 @@
 #include <gui/BufferQueue.h>
 #include <gui/GuiConfig.h>
 #include <gui/IDisplayEventConnection.h>
+#include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 
 #include <ui/GraphicBufferAllocator.h>
@@ -534,8 +535,8 @@
 
     // Initialize the H/W composer object.  There may or may not be an
     // actual hardware composer underneath.
-    mHwc = new HWComposer(this,
-            *static_cast<HWComposer::EventHandler *>(this));
+    mHwc.reset(new HWComposer(this,
+            *static_cast<HWComposer::EventHandler *>(this)));
 
     // get a RenderEngine for the given display / config (can't fail)
     mRenderEngine = RenderEngine::create(mEGLDisplay,
@@ -931,6 +932,34 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_SHELL) &&
+            !PermissionCache::checkPermission(sDump, pid, uid)) {
+        ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
+        return PERMISSION_DENIED;
+    }
+
+    // Try to acquire a lock for 1s, fail gracefully
+    status_t err = mStateLock.timedLock(s2ns(1));
+    bool locked = (err == NO_ERROR);
+    if (!locked) {
+        ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err);
+        return TIMED_OUT;
+    }
+
+    outLayers->clear();
+    mCurrentState.traverseInZOrder([&](Layer* layer) {
+            outLayers->push_back(layer->getLayerDebugInfo());
+        });
+
+    mStateLock.unlock();
+
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -1257,6 +1286,7 @@
     const HWComposer& hwc = getHwComposer();
     const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
 
+    mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
     if (getHwComposer().hasGlesComposition(hw->getHwcDisplayId())) {
         glCompositionDoneFenceTime =
@@ -1265,12 +1295,11 @@
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
-    mGlCompositionDoneTimeline.updateSignalTimes();
 
+    mDisplayTimeline.updateSignalTimes();
     sp<Fence> retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY);
     auto retireFenceTime = std::make_shared<FenceTime>(retireFence);
     mDisplayTimeline.push(retireFenceTime);
-    mDisplayTimeline.updateSignalTimes();
 
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
     nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1298,7 +1327,7 @@
     });
 
     if (retireFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(retireFence)) {
+        if (mPrimaryDispSync.addPresentFence(retireFenceTime)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -2382,6 +2411,7 @@
         return NO_ERROR;
     }
 
+    layer->onRemovedFromCurrentState();
     mLayersPendingRemoval.add(layer);
     mLayersRemoved = true;
     mNumLayers -= 1 + layer->getChildrenCount();
@@ -2576,6 +2606,14 @@
                 }
             }
         }
+        if (what & layer_state_t::eRelativeLayerChanged) {
+            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+            if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
+                mCurrentState.layersSortedByZ.removeAt(idx);
+                mCurrentState.layersSortedByZ.add(layer);
+                flags |= eTransactionNeeded|eTraversalNeeded;
+            }
+        }
         if (what & layer_state_t::eSizeChanged) {
             if (layer->setSize(s.w, s.h)) {
                 flags |= eTraversalNeeded;
@@ -3253,7 +3291,7 @@
     result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
     colorizer.reset(result);
     mCurrentState.traverseInZOrder([&](Layer* layer) {
-        layer->dump(result, colorizer);
+        result.append(to_string(layer->getLayerDebugInfo()).c_str());
     });
 
     /*
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 915b5cd..6be708a 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*" 
+            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*"
         }
 }
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index b7792c7..4ce14f8 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -566,6 +566,15 @@
         sc->expectBGColor(127, 127);
         sc->expectBGColor(128, 128);
     }
+
+    void EXPECT_RESIZE_STATE(const char* trace) {
+        SCOPED_TRACE(trace);
+        ScreenCapture::captureScreen(&sc);
+        // The FG is now resized too 128,128 at 64,64
+        sc->expectFGColor(64, 64);
+        sc->expectFGColor(191, 191);
+        sc->expectBGColor(192, 192);
+    }
 };
 
 TEST_F(CropLatchingTest, CropLatching) {
@@ -666,15 +675,17 @@
     mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
     SurfaceComposerClient::closeGlobalTransaction(true);
 
+    EXPECT_INITIAL_STATE("after setting crops with geometryAppliesWithResize");
+
     SurfaceComposerClient::openGlobalTransaction();
     mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
     SurfaceComposerClient::closeGlobalTransaction(true);
 
-    EXPECT_INITIAL_STATE("after setting crops with geometryAppliesWithResize");
+    EXPECT_INITIAL_STATE("after setting another crop");
 
     completeFGResize();
 
-    EXPECT_INITIAL_STATE("after the resize finishes");
+    EXPECT_RESIZE_STATE("after the resize finishes");
 }
 
 TEST_F(LayerUpdateTest, DeferredTransactionTest) {
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
new file mode 100644
index 0000000..94f3f25
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -0,0 +1,35 @@
+cc_test {
+    name: "sffakehwc_test",
+    srcs: [
+         "FakeComposerClient.cpp",
+         "FakeComposerService.cpp",
+         "FakeComposerUtils.cpp",
+         "SFFakeHwc_test.cpp"
+    ],
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libui",
+        "libgui",
+        "liblog",
+        "libnativewindow",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "libhwbinder",
+        "libhardware",
+        "libhidlbase",
+        "libsync",
+        "libfmq",
+        "libbase",
+        "libhidltransport"
+    ],
+    static_libs: [
+        "libhwcomposer-client",
+        "libsurfaceflingerincludes",
+        "libtrace_proto",
+        "libgmock"
+    ],
+    tags: ["tests"],
+    test_suites: ["device-tests"]
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
new file mode 100644
index 0000000..60916f3
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -0,0 +1,613 @@
+/*
+ * Copyright (C) 2017 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
+#undef LOG_TAG
+#define LOG_TAG "FakeComposer"
+
+#include "FakeComposerClient.h"
+
+#include <gui/SurfaceComposerClient.h>
+
+#include <log/log.h>
+
+#include <gtest/gtest.h>
+
+#include <inttypes.h>
+#include <time.h>
+#include <algorithm>
+#include <condition_variable>
+#include <iostream>
+#include <mutex>
+#include <set>
+#include <thread>
+
+constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0);
+constexpr Display DEFAULT_DISPLAY = static_cast<Display>(1);
+
+using namespace sftest;
+
+using android::Condition;
+using android::Mutex;
+
+using Clock = std::chrono::steady_clock;
+using TimePoint = std::chrono::time_point<Clock>;
+
+namespace {
+
+// Internal state of a layer in the HWC API.
+class LayerImpl {
+public:
+    LayerImpl() = default;
+
+    bool mValid = true;
+    RenderState mRenderState;
+    uint32_t mZ = 0;
+};
+
+// Struct for storing per frame rectangle state. Contains the render
+// state shared to the test case. Basically a snapshot and a subset of
+// LayerImpl sufficient to re-create the pixels of a layer for the
+// frame.
+struct FrameRect {
+public:
+    FrameRect(Layer layer_, const RenderState& state, uint32_t z_)
+          : layer(layer_), renderState(state), z(z_) {}
+
+    const Layer layer;
+    const RenderState renderState;
+    const uint32_t z;
+};
+
+// Collection of FrameRects forming one rendered frame. Could store
+// related fences and other data in the future.
+class Frame {
+public:
+    Frame() = default;
+    std::vector<std::unique_ptr<FrameRect>> rectangles;
+};
+
+class DelayedEventGenerator {
+public:
+    DelayedEventGenerator(std::function<void()> onTimerExpired)
+          : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {}
+
+    ~DelayedEventGenerator() {
+        ALOGI("DelayedEventGenerator exiting.");
+        {
+            std::unique_lock<std::mutex> lock(mMutex);
+            mRunning = false;
+            mWakeups.clear();
+            mCondition.notify_one();
+        }
+        mThread.join();
+        ALOGI("DelayedEventGenerator exited.");
+    }
+
+    void wakeAfter(std::chrono::nanoseconds waitTime) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mWakeups.insert(Clock::now() + waitTime);
+        mCondition.notify_one();
+    }
+
+private:
+    void loop() {
+        while (true) {
+            // Lock scope
+            {
+                std::unique_lock<std::mutex> lock(mMutex);
+                mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); });
+                if (!mRunning && mWakeups.empty()) {
+                    // This thread should only exit once the destructor has been called and all
+                    // wakeups have been processed
+                    return;
+                }
+
+                // At this point, mWakeups will not be empty
+
+                TimePoint target = *(mWakeups.begin());
+                auto status = mCondition.wait_until(lock, target);
+                while (status == std::cv_status::no_timeout) {
+                    // This was either a spurious wakeup or another wakeup was added, so grab the
+                    // oldest point and wait again
+                    target = *(mWakeups.begin());
+                    status = mCondition.wait_until(lock, target);
+                }
+
+                // status must have been timeout, so we can finally clear this point
+                mWakeups.erase(target);
+            }
+            // Callback *without* locks!
+            mOnTimerExpired();
+        }
+    }
+
+    std::function<void()> mOnTimerExpired;
+    std::thread mThread;
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+    bool mRunning = true;
+    std::set<TimePoint> mWakeups;
+};
+
+} // namespace
+
+FakeComposerClient::FakeComposerClient()
+      : mCallbacksOn(false),
+        mClient(nullptr),
+        mCurrentConfig(NULL_DISPLAY_CONFIG),
+        mVsyncEnabled(false),
+        mLayers(),
+        mDelayedEventGenerator(
+                std::make_unique<DelayedEventGenerator>([this]() { this->requestVSync(); })),
+        mSurfaceComposer(nullptr) {}
+
+FakeComposerClient::~FakeComposerClient() {}
+
+void FakeComposerClient::removeClient() {
+    ALOGV("removeClient");
+    // TODO: Ahooga! Only thing current lifetime management choices in
+    // APIs make possible. Sad.
+    delete this;
+}
+
+void FakeComposerClient::enableCallback(bool enable) {
+    ALOGV("enableCallback");
+    mCallbacksOn = enable;
+    if (mCallbacksOn) {
+        mClient->onHotplug(DEFAULT_DISPLAY, IComposerCallback::Connection::CONNECTED);
+    }
+}
+
+void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) {
+    if (mCallbacksOn) {
+        mClient->onHotplug(display, state);
+    }
+}
+
+uint32_t FakeComposerClient::getMaxVirtualDisplayCount() {
+    ALOGV("getMaxVirtualDisplayCount");
+    return 1;
+}
+
+Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
+                                               PixelFormat* /*format*/, Display* /*outDisplay*/) {
+    ALOGV("createVirtualDisplay");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
+    ALOGV("destroyVirtualDisplay");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
+    ALOGV("createLayer");
+    *outLayer = mLayers.size();
+    auto newLayer = std::make_unique<LayerImpl>();
+    mLayers.push_back(std::move(newLayer));
+    return Error::NONE;
+}
+
+Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
+    ALOGV("destroyLayer");
+    mLayers[layer]->mValid = false;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) {
+    ALOGV("getActiveConfig");
+
+    // TODO Assert outConfig != nullptr
+
+    // TODO This is my reading of the
+    // IComposerClient::getActiveConfig, but returning BAD_CONFIG
+    // seems to not fit SurfaceFlinger plans. See version 2 below.
+    // if (mCurrentConfig == NULL_DISPLAY_CONFIG) {
+    //     return Error::BAD_CONFIG;
+    // }
+    //*outConfig = mCurrentConfig;
+    *outConfig = 1; // Very special config for you my friend
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
+                                                 uint32_t /*height*/, PixelFormat /*format*/,
+                                                 Dataspace /*dataspace*/) {
+    ALOGV("getClientTargetSupport");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec<ColorMode>* /*outModes*/) {
+    ALOGV("getColorModes");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
+                                              IComposerClient::Attribute attribute,
+                                              int32_t* outValue) {
+    ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display),
+          static_cast<int>(config), static_cast<int>(attribute), outValue);
+
+    // TODO: SOOO much fun to be had with these alone
+    switch (attribute) {
+        case IComposerClient::Attribute::WIDTH:
+            *outValue = 1920;
+            break;
+        case IComposerClient::Attribute::HEIGHT:
+            *outValue = 1080;
+            break;
+        case IComposerClient::Attribute::VSYNC_PERIOD:
+            *outValue = 1666666666;
+            break; // TOOD: Tests break down if lowered to 16ms?
+        case IComposerClient::Attribute::DPI_X:
+            *outValue = 240;
+            break;
+        case IComposerClient::Attribute::DPI_Y:
+            *outValue = 240;
+            break;
+        default:
+            LOG_ALWAYS_FATAL("Say what!?! New attribute");
+    }
+
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec<Config>* outConfigs) {
+    ALOGV("getDisplayConfigs");
+    // TODO assert display == 1, outConfigs != nullptr
+
+    outConfigs->resize(1);
+    (*outConfigs)[0] = 1;
+
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
+    ALOGV("getDisplayName");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayType(Display /*display*/,
+                                         IComposerClient::DisplayType* outType) {
+    ALOGV("getDisplayType");
+    // TODO: This setting nothing on the output had no effect on initial trials. Is first display
+    // assumed to be physical?
+    *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
+    ALOGV("getDozeSupport");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec<Hdr>* /*outTypes*/,
+                                             float* /*outMaxLuminance*/,
+                                             float* /*outMaxAverageLuminance*/,
+                                             float* /*outMinLuminance*/) {
+    ALOGV("getHdrCapabilities");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) {
+    ALOGV("setActiveConfig");
+    mCurrentConfig = config;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) {
+    ALOGV("setColorMode");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) {
+    ALOGV("setPowerMode");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) {
+    mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
+    ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
+                                            int32_t /*hint*/) {
+    ALOGV("setColorTransform");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
+                                          int32_t /*acquireFence*/, int32_t /*dataspace*/,
+                                          const std::vector<hwc_rect_t>& /*damage*/) {
+    ALOGV("setClientTarget");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
+                                          int32_t /*releaseFence*/) {
+    ALOGV("setOutputBuffer");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::validateDisplay(
+        Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
+        std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
+        uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
+        std::vector<uint32_t>* /*outRequestMasks*/) {
+    ALOGV("validateDisplay");
+    // TODO: Assume touching nothing means All Korrekt!
+    return Error::NONE;
+}
+
+Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
+    ALOGV("acceptDisplayChanges");
+    // Didn't ask for changes because software is omnipotent.
+    return Error::NONE;
+}
+
+bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
+    return a->z <= b->z;
+}
+
+Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
+                                         std::vector<Layer>* /*outLayers*/,
+                                         std::vector<int32_t>* /*outReleaseFences*/) {
+    ALOGV("presentDisplay");
+    // TODO Leaving layers and their fences out for now. Doing so
+    // means that we've already processed everything. Important to
+    // test that the fences are respected, though. (How?)
+
+    std::unique_ptr<Frame> newFrame(new Frame);
+    for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
+        const LayerImpl& layerImpl = *mLayers[layer];
+
+        if (!layerImpl.mValid) continue;
+
+        auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
+        newFrame->rectangles.push_back(std::move(rect));
+    }
+    std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
+    {
+        Mutex::Autolock _l(mStateMutex);
+        mFrames.push_back(std::move(newFrame));
+        mFramesAvailable.broadcast();
+    }
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
+                                                 int32_t /*x*/, int32_t /*y*/) {
+    ALOGV("setLayerCursorPosition");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer,
+                                         int32_t acquireFence) {
+    ALOGV("setLayerBuffer");
+    LayerImpl& l = getLayerImpl(layer);
+    if (buffer != l.mRenderState.mBuffer) {
+        l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
+    }
+    l.mRenderState.mBuffer = buffer;
+    l.mRenderState.mAcquireFence = acquireFence;
+
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
+                                                const std::vector<hwc_rect_t>& /*damage*/) {
+    ALOGV("setLayerSurfaceDamage");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
+    ALOGV("setLayerBlendMode");
+    getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
+                                        IComposerClient::Color color) {
+    ALOGV("setLayerColor");
+    getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
+    getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
+    getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
+    getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
+                                                  int32_t /*type*/) {
+    ALOGV("setLayerCompositionType");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
+                                            int32_t /*dataspace*/) {
+    ALOGV("setLayerDataspace");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
+                                               const hwc_rect_t& frame) {
+    ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
+          frame.bottom);
+    getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
+    ALOGV("setLayerPlaneAlpha");
+    getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
+                                                 buffer_handle_t /*stream*/) {
+    ALOGV("setLayerSidebandStream");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
+                                             const hwc_frect_t& crop) {
+    ALOGV("setLayerSourceCrop");
+    getLayerImpl(layer).mRenderState.mSourceCrop = crop;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) {
+    ALOGV("setLayerTransform");
+    getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
+                                                const std::vector<hwc_rect_t>& visible) {
+    ALOGV("setLayerVisibleRegion");
+    getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
+    ALOGV("setLayerZOrder");
+    getLayerImpl(layer).mZ = z;
+    return Error::NONE;
+}
+
+//////////////////////////////////////////////////////////////////
+
+void FakeComposerClient::setClient(ComposerClient* client) {
+    mClient = client;
+}
+
+void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
+    if (mCallbacksOn) {
+        uint64_t timestamp = vsyncTime;
+        ALOGV("Vsync");
+        if (timestamp == 0) {
+            struct timespec ts;
+            clock_gettime(CLOCK_MONOTONIC, &ts);
+            timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+        }
+        if (mSurfaceComposer != nullptr) {
+            mSurfaceComposer->injectVSync(timestamp);
+        } else {
+            mClient->onVsync(DEFAULT_DISPLAY, timestamp);
+        }
+    }
+}
+
+void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) {
+    mDelayedEventGenerator->wakeAfter(wait);
+}
+
+LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) {
+    // TODO Change these to an internal state check that can be
+    // invoked from the gtest? GTest macros do not seem all that safe
+    // when used outside the test class
+    EXPECT_GE(handle, static_cast<Layer>(0));
+    EXPECT_LT(handle, mLayers.size());
+    return *(mLayers[handle]);
+}
+
+int FakeComposerClient::getFrameCount() const {
+    return mFrames.size();
+}
+
+static std::vector<RenderState> extractRenderState(
+        const std::vector<std::unique_ptr<FrameRect>>& internalRects) {
+    std::vector<RenderState> result;
+    result.reserve(internalRects.size());
+    for (const std::unique_ptr<FrameRect>& rect : internalRects) {
+        result.push_back(rect->renderState);
+    }
+    return result;
+}
+
+std::vector<RenderState> FakeComposerClient::getFrameRects(int frame) const {
+    Mutex::Autolock _l(mStateMutex);
+    return extractRenderState(mFrames[frame]->rectangles);
+}
+
+std::vector<RenderState> FakeComposerClient::getLatestFrame() const {
+    Mutex::Autolock _l(mStateMutex);
+    return extractRenderState(mFrames[mFrames.size() - 1]->rectangles);
+}
+
+void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) {
+    int currentFrame = 0;
+    {
+        Mutex::Autolock _l(mStateMutex); // I hope this is ok...
+        currentFrame = static_cast<int>(mFrames.size());
+        requestVSync();
+    }
+    waitUntilFrame(currentFrame + 1, maxWait);
+}
+
+void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const {
+    Mutex::Autolock _l(mStateMutex);
+    while (mFrames.size() < static_cast<size_t>(targetFrame)) {
+        android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count());
+        if (result == android::TIMED_OUT) {
+            ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame,
+                  mFrames.size(), maxWait.count());
+            return;
+        }
+    }
+}
+
+void FakeComposerClient::clearFrames() {
+    Mutex::Autolock _l(mStateMutex);
+    mFrames.clear();
+    for (const std::unique_ptr<LayerImpl>& layer : mLayers) {
+        if (layer->mValid) {
+            layer->mRenderState.mSwapCount = 0;
+        }
+    }
+}
+
+void FakeComposerClient::onSurfaceFlingerStart() {
+    mSurfaceComposer == nullptr;
+    do {
+        mSurfaceComposer = new android::SurfaceComposerClient;
+        android::status_t initResult = mSurfaceComposer->initCheck();
+        if (initResult != android::NO_ERROR) {
+            ALOGD("Init result: %d", initResult);
+            mSurfaceComposer = nullptr;
+            std::this_thread::sleep_for(10ms);
+        }
+    } while (mSurfaceComposer == nullptr);
+    ALOGD("SurfaceComposerClient created");
+    mSurfaceComposer->enableVSyncInjections(true);
+}
+
+void FakeComposerClient::onSurfaceFlingerStop() {
+    mSurfaceComposer->dispose();
+    mSurfaceComposer.clear();
+}
+
+// Includes destroyed layers, stored in order of creation.
+int FakeComposerClient::getLayerCount() const {
+    return mLayers.size();
+}
+
+Layer FakeComposerClient::getLayer(size_t index) const {
+    // NOTE: If/when passing calls through to actual implementation,
+    // this might get more involving.
+    return static_cast<Layer>(index);
+}
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
new file mode 100644
index 0000000..294abb2
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "ComposerClient.h"
+#include "RenderState.h"
+
+#include <utils/Condition.h>
+
+#include <chrono>
+
+using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_1::implementation;
+using namespace android::hardware;
+using namespace std::chrono_literals;
+
+namespace {
+class LayerImpl;
+class Frame;
+class DelayedEventGenerator;
+} // namespace
+
+namespace android {
+class SurfaceComposerClient;
+} // namespace android
+
+namespace sftest {
+
+class FakeComposerClient : public ComposerBase {
+public:
+    FakeComposerClient();
+    virtual ~FakeComposerClient();
+
+    void removeClient() override;
+    void enableCallback(bool enable) override;
+    uint32_t getMaxVirtualDisplayCount() override;
+    Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+                               Display* outDisplay) override;
+    Error destroyVirtualDisplay(Display display) override;
+    Error createLayer(Display display, Layer* outLayer) override;
+    Error destroyLayer(Display display, Layer layer) override;
+
+    Error getActiveConfig(Display display, Config* outConfig) override;
+    Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+                                 PixelFormat format, Dataspace dataspace) override;
+    Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override;
+    Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
+                              int32_t* outValue) override;
+    Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
+    Error getDisplayName(Display display, hidl_string* outName) override;
+    Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
+    Error getDozeSupport(Display display, bool* outSupport) override;
+    Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance,
+                             float* outMaxAverageLuminance, float* outMinLuminance) override;
+
+    Error setActiveConfig(Display display, Config config) override;
+    Error setColorMode(Display display, ColorMode mode) override;
+    Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
+    Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
+
+    Error setColorTransform(Display display, const float* matrix, int32_t hint) override;
+    Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
+                          int32_t dataspace, const std::vector<hwc_rect_t>& damage) override;
+    Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override;
+    Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
+                          std::vector<IComposerClient::Composition>* outCompositionTypes,
+                          uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+                          std::vector<uint32_t>* outRequestMasks) override;
+    Error acceptDisplayChanges(Display display) override;
+    Error presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers,
+                         std::vector<int32_t>* outReleaseFences) override;
+
+    Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
+    Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+                         int32_t acquireFence) override;
+    Error setLayerSurfaceDamage(Display display, Layer layer,
+                                const std::vector<hwc_rect_t>& damage) override;
+    Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
+    Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override;
+    Error setLayerCompositionType(Display display, Layer layer, int32_t type) override;
+    Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override;
+    Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override;
+    Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
+    Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override;
+    Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override;
+    Error setLayerTransform(Display display, Layer layer, int32_t transform) override;
+    Error setLayerVisibleRegion(Display display, Layer layer,
+                                const std::vector<hwc_rect_t>& visible) override;
+    Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+
+    void setClient(ComposerClient* client);
+
+    void requestVSync(uint64_t vsyncTime = 0);
+    // We don't want tests hanging, so always use a timeout. Remember
+    // to always check the number of frames with test ASSERT_!
+    // Wait until next frame is rendered after requesting vsync.
+    void runVSyncAndWait(std::chrono::nanoseconds maxWait = 100ms);
+    void runVSyncAfter(std::chrono::nanoseconds wait);
+
+    int getFrameCount() const;
+    // We don't want tests hanging, so always use a timeout. Remember
+    // to always check the number of frames with test ASSERT_!
+    void waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait = 100ms) const;
+    std::vector<RenderState> getFrameRects(int frame) const;
+    std::vector<RenderState> getLatestFrame() const;
+    void clearFrames();
+
+    void onSurfaceFlingerStart();
+    void onSurfaceFlingerStop();
+
+    int getLayerCount() const;
+    Layer getLayer(size_t index) const;
+
+    void hotplugDisplay(Display display, IComposerCallback::Connection state);
+
+private:
+    LayerImpl& getLayerImpl(Layer handle);
+
+    bool mCallbacksOn;
+    ComposerClient* mClient;
+    Config mCurrentConfig;
+    bool mVsyncEnabled;
+    std::vector<std::unique_ptr<LayerImpl>> mLayers;
+    std::vector<std::unique_ptr<Frame>> mFrames;
+    // Using a pointer to hide the implementation into the CPP file.
+    std::unique_ptr<DelayedEventGenerator> mDelayedEventGenerator;
+    android::sp<android::SurfaceComposerClient> mSurfaceComposer; // For VSync injections
+    mutable android::Mutex mStateMutex;
+    mutable android::Condition mFramesAvailable;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
new file mode 100644
index 0000000..c411604
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcService"
+#include <log/log.h>
+
+#include "FakeComposerService.h"
+
+using namespace android::hardware;
+
+namespace sftest {
+
+FakeComposerService::FakeComposerService(android::sp<ComposerClient>& client) : mClient(client) {}
+
+FakeComposerService::~FakeComposerService() {
+    ALOGI("Maybe killing client %p", mClient.get());
+    // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService::getCapabilities(getCapabilities_cb hidl_cb) {
+    ALOGI("FakeComposerService::getCapabilities");
+    hidl_cb(hidl_vec<Capability>());
+    return Void();
+}
+
+Return<void> FakeComposerService::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+    ALOGI("FakeComposerService::dumpDebugInfo");
+    hidl_cb(hidl_string());
+    return Void();
+}
+
+Return<void> FakeComposerService::createClient(createClient_cb hidl_cb) {
+    ALOGI("FakeComposerService::createClient %p", mClient.get());
+    mClient->initialize();
+    hidl_cb(Error::NONE, mClient);
+    return Void();
+}
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
new file mode 100644
index 0000000..5204084
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "ComposerClient.h"
+
+using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_1::implementation;
+using android::hardware::Return;
+
+namespace sftest {
+
+class FakeComposerService : public IComposer {
+public:
+    FakeComposerService(android::sp<ComposerClient>& client);
+    virtual ~FakeComposerService();
+
+    Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+    Return<void> createClient(createClient_cb hidl_cb) override;
+
+private:
+    android::sp<ComposerClient> mClient;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
new file mode 100644
index 0000000..51956ec
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2017 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
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcUtil"
+#include <log/log.h>
+
+#include "FakeComposerUtils.h"
+#include "RenderState.h"
+
+#include "SurfaceFlinger.h" // Get the name of the service...
+
+#include <binder/IServiceManager.h>
+
+#include <cutils/properties.h>
+
+#include <iomanip>
+#include <thread>
+
+using android::String16;
+using android::sp;
+using namespace std::chrono_literals;
+using namespace sftest;
+using std::setw;
+
+namespace sftest {
+
+// clang-format off
+inline void printSourceRectAligned(::std::ostream& os, const hwc_frect_t& sourceRect, int align) {
+    os << std::fixed << std::setprecision(1) << "("
+       << setw(align) << sourceRect.left << setw(0) << ","
+       << setw(align) << sourceRect.top << setw(0) << ","
+       << setw(align) << sourceRect.right << setw(0) << ","
+       << setw(align) << sourceRect.bottom << setw(0) << ")";
+}
+
+inline void printDisplayRectAligned(::std::ostream& os, const hwc_rect_t& displayRect, int align) {
+    os << "("
+       << setw(align) << displayRect.left << setw(0) << ","
+       << setw(align) << displayRect.top << setw(0) << ","
+       << setw(align) << displayRect.right << setw(0) << ","
+       << setw(align) << displayRect.bottom << setw(0) << ")";
+}
+// clang-format on
+
+inline ::std::ostream& operator<<(::std::ostream& os, const sftest::RenderState& state) {
+    printSourceRectAligned(os, state.mSourceCrop, 7);
+    os << "->";
+    printDisplayRectAligned(os, state.mDisplayFrame, 5);
+    return os << " Swaps:" << state.mSwapCount << " Alpha:" << std::setprecision(3)
+              << state.mPlaneAlpha << " Xform:" << state.mTransform;
+}
+
+// Helper for verifying the parts of the RenderState
+template <typename T>
+bool valuesMatch(::testing::AssertionResult& message, const T& ref, const T& val,
+                 const char* name) {
+    if (ref != val) {
+        message = message << "Expected " << name << ":" << ref << ", got:" << val << ".";
+        return false;
+    }
+    return true;
+}
+
+::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val) {
+    // TODO: Message could start as success and be assigned as failure.
+    // Only problem is that utility assumes it to be failure and just adds stuff. Would
+    // need still special case the initial failure in the utility?
+    // TODO: ... or would it be possible to break this back to gtest primitives?
+    ::testing::AssertionResult message = ::testing::AssertionFailure();
+    bool passes = true;
+
+    // The work here is mostly about providing good log strings for differences
+    passes &= valuesMatch(message, ref.mDisplayFrame, val.mDisplayFrame, "display frame");
+    passes &= valuesMatch(message, ref.mPlaneAlpha, val.mPlaneAlpha, "alpha");
+    passes &= valuesMatch(message, ref.mSwapCount, val.mSwapCount, "swap count");
+    passes &= valuesMatch(message, ref.mSourceCrop, val.mSourceCrop, "source crop");
+    // ... add more
+    if (passes) {
+        return ::testing::AssertionSuccess();
+    }
+    return message;
+}
+
+::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
+                                         const std::vector<RenderState>& val) {
+    ::testing::AssertionResult message = ::testing::AssertionFailure();
+    bool passed = true;
+    if (ref.size() != val.size()) {
+        message << "Expected " << ref.size() << " rects, got " << val.size() << ".";
+        passed = false;
+    }
+    for (size_t rectIndex = 0; rectIndex < std::min(ref.size(), val.size()); rectIndex++) {
+        ::testing::AssertionResult rectResult = rectsAreSame(ref[rectIndex], val[rectIndex]);
+        if (rectResult == false) {
+            message << "First different rect at " << rectIndex << ": " << rectResult.message();
+            passed = false;
+            break;
+        }
+    }
+
+    if (passed) {
+        return ::testing::AssertionSuccess();
+    } else {
+        message << "\nReference:";
+        for (auto state = ref.begin(); state != ref.end(); ++state) {
+            message << "\n" << *state;
+        }
+        message << "\nActual:";
+        for (auto state = val.begin(); state != val.end(); ++state) {
+            message << "\n" << *state;
+        }
+    }
+    return message;
+}
+
+void startSurfaceFlinger() {
+    ALOGI("Start SurfaceFlinger");
+    system("start surfaceflinger");
+
+    sp<android::IServiceManager> sm(android::defaultServiceManager());
+    sp<android::IBinder> sf;
+    while (sf == nullptr) {
+        std::this_thread::sleep_for(10ms);
+        sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
+    }
+    ALOGV("SurfaceFlinger running");
+}
+
+void stopSurfaceFlinger() {
+    ALOGI("Stop SurfaceFlinger");
+    system("stop surfaceflinger");
+    sp<android::IServiceManager> sm(android::defaultServiceManager());
+    sp<android::IBinder> sf;
+    while (sf != nullptr) {
+        std::this_thread::sleep_for(10ms);
+        sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
+    }
+    ALOGV("SurfaceFlinger stopped");
+}
+
+////////////////////////////////////////////////
+
+void FakeHwcEnvironment::SetUp() {
+    ALOGI("Test env setup");
+    system("setenforce 0");
+    system("stop");
+    property_set("debug.sf.nobootanimation", "1");
+    {
+        char value[PROPERTY_VALUE_MAX];
+        property_get("debug.sf.nobootanimation", value, "0");
+        LOG_FATAL_IF(atoi(value) != 1, "boot skip not set");
+    }
+    // TODO: Try registering the mock as the default service instead.
+    property_set("debug.sf.hwc_service_name", "mock");
+    // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files.
+    property_set("debug.sf.treble_testing_override", "true");
+}
+
+void FakeHwcEnvironment::TearDown() {
+    ALOGI("Test env tear down");
+    system("stop");
+    // Wait for mock call signaling teardown?
+    property_set("debug.sf.nobootanimation", "0");
+    property_set("debug.sf.hwc_service_name", "default");
+    ALOGI("Test env tear down - done");
+}
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
new file mode 100644
index 0000000..74dc0e5
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "FakeComposerClient.h"
+
+#include <gui/SurfaceComposerClient.h>
+
+#include <hardware/hwcomposer_defs.h>
+
+#include <log/log.h>
+
+#include <gtest/gtest.h>
+
+// clang-format off
+// Note: This needs to reside in the global namespace for the GTest to use it
+inline ::std::ostream& operator<<(::std::ostream& os, const hwc_rect_t& rect) {
+    return os << "(" << rect.left << ","
+              << rect.top << ","
+              << rect.right << ","
+              << rect.bottom << ")";
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, const hwc_frect_t& rect) {
+    return os << "(" << rect.left << ","
+              << rect.top << ","
+              << rect.right << ","
+              << rect.bottom << ")";
+}
+// clang-format on
+
+namespace sftest {
+
+class RenderState;
+
+// clang-format off
+inline bool operator==(const hwc_rect_t& a, const hwc_rect_t& b) {
+    return a.top == b.top &&
+            a.left == b.left &&
+            a.bottom == b.bottom &&
+            a.right == b.right;
+}
+
+inline bool operator==(const hwc_frect_t& a, const hwc_frect_t& b) {
+    return a.top == b.top &&
+            a.left == b.left &&
+            a.bottom == b.bottom &&
+            a.right == b.right;
+}
+// clang-format on
+
+inline bool operator!=(const hwc_rect_t& a, const hwc_rect_t& b) {
+    return !(a == b);
+}
+
+inline bool operator!=(const hwc_frect_t& a, const hwc_frect_t& b) {
+    return !(a == b);
+}
+
+::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val);
+::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
+                                         const std::vector<RenderState>& val);
+
+void startSurfaceFlinger();
+void stopSurfaceFlinger();
+
+class FakeHwcEnvironment : public ::testing::Environment {
+public:
+    virtual ~FakeHwcEnvironment() {}
+    void SetUp() override;
+    void TearDown() override;
+};
+
+/*
+ * All surface state changes are supposed to happen inside a global
+ * transaction. GlobalTransactionScope object at the beginning of
+ * scope automates the process. The resulting scope gives a visual cue
+ * on the span of the transaction as well.
+ *
+ * Closing the transaction is synchronous, i.e., it waits for
+ * SurfaceFlinger to composite one frame. Now, the FakeComposerClient
+ * is built to explicitly request vsyncs one at the time. A delayed
+ * request must be made before closing the transaction or the test
+ * thread stalls until SurfaceFlinger does an emergency vsync by
+ * itself. GlobalTransactionScope encapsulates this vsync magic.
+ */
+class GlobalTransactionScope {
+public:
+    GlobalTransactionScope(FakeComposerClient& composer) : mComposer(composer) {
+        android::SurfaceComposerClient::openGlobalTransaction();
+    }
+    ~GlobalTransactionScope() {
+        int frameCount = mComposer.getFrameCount();
+        mComposer.runVSyncAfter(1ms);
+        android::SurfaceComposerClient::closeGlobalTransaction(true);
+        // Make sure that exactly one frame has been rendered.
+        mComposer.waitUntilFrame(frameCount + 1);
+        LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
+                            "Unexpected frame advance. Delta: %d",
+                            mComposer.getFrameCount() - frameCount);
+    }
+    FakeComposerClient& mComposer;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h
new file mode 100644
index 0000000..0059289
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/RenderState.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <hardware/hwcomposer2.h>
+
+#include <vector>
+
+namespace sftest {
+// Description of a rendered rectangle.  Should only contain
+// instructions necessary to rasterize the rectangle. The full scene
+// is given as a sorted list of rectangles, bottom layer at index 0.
+class RenderState {
+public:
+    RenderState() = default;
+    // Default copy-ctor
+
+    hwc_rect_t mDisplayFrame = {0, 0, 0, 0};
+    hwc_frect_t mSourceCrop = {0.f, 0.f, 0.f, 0.f};
+    std::vector<hwc_rect_t> mVisibleRegion;
+    hwc2_blend_mode_t mBlendMode = HWC2_BLEND_MODE_NONE;
+    buffer_handle_t mBuffer = 0;
+    uint32_t mSwapCount = 0;   // How many set buffer calls to the layer.
+    int32_t mAcquireFence = 0; // Probably should not be here.
+    float mPlaneAlpha = 0.f;
+    hwc_color_t mLayerColor = {0, 0, 0, 0};
+    hwc_transform_t mTransform = static_cast<hwc_transform_t>(0);
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
new file mode 100644
index 0000000..8902ede
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -0,0 +1,1306 @@
+/*
+ * Copyright (C) 2017 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
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcTest"
+
+#include "FakeComposerClient.h"
+#include "FakeComposerService.h"
+#include "FakeComposerUtils.h"
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <private/gui/ComposerService.h>
+#include <private/gui/LayerState.h>
+
+#include <ui/DisplayInfo.h>
+
+#include <android/native_window.h>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+
+#include <hwbinder/ProcessState.h>
+
+#include <binder/ProcessState.h>
+
+#include <log/log.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <limits>
+
+using namespace std::chrono_literals;
+
+using namespace android;
+using namespace android::hardware;
+
+using namespace sftest;
+
+namespace {
+
+// Mock test helpers
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::_;
+
+///////////////////////////////////////////////
+
+struct TestColor {
+public:
+    uint8_t r;
+    uint8_t g;
+    uint8_t b;
+    uint8_t a;
+};
+
+constexpr static TestColor RED = {195, 63, 63, 255};
+constexpr static TestColor LIGHT_RED = {255, 177, 177, 255};
+constexpr static TestColor GREEN = {63, 195, 63, 255};
+constexpr static TestColor BLUE = {63, 63, 195, 255};
+constexpr static TestColor DARK_GRAY = {63, 63, 63, 255};
+constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255};
+
+// Fill an RGBA_8888 formatted surface with a single color.
+static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const TestColor& color,
+                             bool unlock = true) {
+    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] = color.r;
+            pixel[1] = color.g;
+            pixel[2] = color.b;
+            pixel[3] = color.a;
+        }
+    }
+    if (unlock) {
+        ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+    }
+}
+
+inline RenderState makeSimpleRect(int left, int top, int right, int bottom) {
+    RenderState res;
+    res.mDisplayFrame = hwc_rect_t{left, top, right, bottom};
+    res.mPlaneAlpha = 1.0f;
+    res.mSwapCount = 0;
+    res.mSourceCrop = hwc_frect_t{0.f, 0.f, static_cast<float>(right - left),
+                                  static_cast<float>(bottom - top)};
+    return res;
+}
+
+inline RenderState makeSimpleRect(unsigned int left, unsigned int top, unsigned int right,
+                                  unsigned int bottom) {
+    EXPECT_LE(left, static_cast<unsigned int>(INT_MAX));
+    EXPECT_LE(top, static_cast<unsigned int>(INT_MAX));
+    EXPECT_LE(right, static_cast<unsigned int>(INT_MAX));
+    EXPECT_LE(bottom, static_cast<unsigned int>(INT_MAX));
+    return makeSimpleRect(static_cast<int>(left), static_cast<int>(top), static_cast<int>(right),
+                          static_cast<int>(bottom));
+}
+
+////////////////////////////////////////////////
+
+class DisplayTest : public ::testing::Test {
+public:
+    class MockComposerClient : public FakeComposerClient {
+    public:
+        MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType));
+        MOCK_METHOD4(getDisplayAttribute,
+                     Error(Display display, Config config, IComposerClient::Attribute attribute,
+                           int32_t* outValue));
+
+        // Re-routing to basic fake implementation
+        Error getDisplayAttributeFake(Display display, Config config,
+                                      IComposerClient::Attribute attribute, int32_t* outValue) {
+            return FakeComposerClient::getDisplayAttribute(display, config, attribute, outValue);
+        }
+    };
+
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    sp<IComposer> mFakeService;
+    sp<SurfaceComposerClient> mComposerClient;
+
+    MockComposerClient* mMockComposer;
+};
+
+void DisplayTest::SetUp() {
+    // TODO: The mMockComposer should be a unique_ptr, but it needs to
+    // outlive the test class.  Currently ComposerClient only dies
+    // when the service is replaced. The Mock deletes itself when
+    // removeClient is called on it, which is ugly.  This can be
+    // changed if HIDL ServiceManager allows removing services or
+    // ComposerClient starts taking the ownership of the contained
+    // implementation class. Moving the fake class to the HWC2
+    // interface instead of the current Composer interface might also
+    // change the situation.
+    mMockComposer = new MockComposerClient;
+    sp<ComposerClient> client = new ComposerClient(*mMockComposer);
+    mMockComposer->setClient(client.get());
+    mFakeService = new FakeComposerService(client);
+    mFakeService->registerAsService("mock");
+
+    android::hardware::ProcessState::self()->startThreadPool();
+    android::ProcessState::self()->startThreadPool();
+
+    EXPECT_CALL(*mMockComposer, getDisplayType(1, _))
+            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
+                            Return(Error::NONE)));
+    // Seems to be doubled right now, once for display ID 1 and once for 0. This sounds fishy
+    // but encoding that here exactly.
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(1, 1, _, _))
+            .Times(5)
+            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+    // TODO: Find out what code is generating the ID 0.
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(0, 1, _, _))
+            .Times(5)
+            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+
+    startSurfaceFlinger();
+
+    // Fake composer wants to enable VSync injection
+    mMockComposer->onSurfaceFlingerStart();
+
+    mComposerClient = new SurfaceComposerClient;
+    ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+}
+
+void DisplayTest::TearDown() {
+    mComposerClient->dispose();
+    mComposerClient = nullptr;
+
+    // Fake composer needs to release SurfaceComposerClient before the stop.
+    mMockComposer->onSurfaceFlingerStop();
+    stopSurfaceFlinger();
+
+    mFakeService = nullptr;
+    // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime
+    // management.
+    mMockComposer = nullptr;
+}
+
+TEST_F(DisplayTest, Hotplug) {
+    ALOGD("DisplayTest::Hotplug");
+
+    EXPECT_CALL(*mMockComposer, getDisplayType(2, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
+                                  Return(Error::NONE)));
+    // The attribute queries will get done twice. This is for defaults
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, _, _))
+            .Times(2 * 3)
+            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+    // ... and then special handling for dimensions. Specifying this
+    // rules later means that gmock will try them first, i.e.,
+    // ordering of width/height vs. the default implementation for
+    // other queries is significant.
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::WIDTH, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
+
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::HEIGHT, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
+
+    // TODO: Width and height queries are not actually called. Display
+    // info returns dimensions 0x0 in display info. Why?
+
+    mMockComposer->hotplugDisplay(static_cast<Display>(2),
+                                  IComposerCallback::Connection::CONNECTED);
+
+    {
+        sp<android::IBinder> display(
+                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+        DisplayInfo info;
+        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ASSERT_EQ(400u, info.w);
+        ASSERT_EQ(200u, info.h);
+
+        auto surfaceControl =
+                mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w, info.h,
+                                               PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(surfaceControl != nullptr);
+        ASSERT_TRUE(surfaceControl->isValid());
+        fillSurfaceRGBA8(surfaceControl, BLUE);
+
+        {
+            GlobalTransactionScope gts(*mMockComposer);
+            mComposerClient->setDisplayLayerStack(display, 0);
+
+            ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2));
+            ASSERT_EQ(NO_ERROR, surfaceControl->show());
+        }
+    }
+
+    mMockComposer->hotplugDisplay(static_cast<Display>(2),
+                                  IComposerCallback::Connection::DISCONNECTED);
+
+    mMockComposer->clearFrames();
+
+    mMockComposer->hotplugDisplay(static_cast<Display>(2),
+                                  IComposerCallback::Connection::CONNECTED);
+
+    {
+        sp<android::IBinder> display(
+                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+        DisplayInfo info;
+        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ASSERT_EQ(400u, info.w);
+        ASSERT_EQ(200u, info.h);
+
+        auto surfaceControl =
+                mComposerClient->createSurface(String8("Display Test Surface Bar"), info.w, info.h,
+                                               PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(surfaceControl != nullptr);
+        ASSERT_TRUE(surfaceControl->isValid());
+        fillSurfaceRGBA8(surfaceControl, BLUE);
+
+        {
+            GlobalTransactionScope gts(*mMockComposer);
+            mComposerClient->setDisplayLayerStack(display, 0);
+
+            ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2));
+            ASSERT_EQ(NO_ERROR, surfaceControl->show());
+        }
+    }
+    mMockComposer->hotplugDisplay(static_cast<Display>(2),
+                                  IComposerCallback::Connection::DISCONNECTED);
+}
+
+////////////////////////////////////////////////
+
+class TransactionTest : public ::testing::Test {
+protected:
+    // Layer array indexing constants.
+    constexpr static int BG_LAYER = 0;
+    constexpr static int FG_LAYER = 1;
+
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+    void SetUp() override;
+    void TearDown() override;
+
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mBGSurfaceControl;
+    sp<SurfaceControl> mFGSurfaceControl;
+    std::vector<RenderState> mBaseFrame;
+    uint32_t mDisplayWidth;
+    uint32_t mDisplayHeight;
+
+    static FakeComposerClient* sFakeComposer;
+};
+
+FakeComposerClient* TransactionTest::sFakeComposer;
+
+void TransactionTest::SetUpTestCase() {
+    // TODO: See TODO comment at DisplayTest::SetUp for background on
+    // the lifetime of the FakeComposerClient.
+    sFakeComposer = new FakeComposerClient;
+    sp<ComposerClient> client = new ComposerClient(*sFakeComposer);
+    sFakeComposer->setClient(client.get());
+    sp<IComposer> fakeService = new FakeComposerService(client);
+    fakeService->registerAsService("mock");
+
+    android::hardware::ProcessState::self()->startThreadPool();
+    android::ProcessState::self()->startThreadPool();
+
+    startSurfaceFlinger();
+
+    // Fake composer wants to enable VSync injection
+    sFakeComposer->onSurfaceFlingerStart();
+}
+
+void TransactionTest::TearDownTestCase() {
+    // Fake composer needs to release SurfaceComposerClient before the stop.
+    sFakeComposer->onSurfaceFlingerStop();
+    stopSurfaceFlinger();
+    // TODO: This is deleted when the ComposerClient calls
+    // removeClient. Devise better lifetime control.
+    sFakeComposer = nullptr;
+}
+
+void TransactionTest::SetUp() {
+    ALOGI("TransactionTest::SetUp");
+    mComposerClient = new SurfaceComposerClient;
+    ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+    ALOGI("TransactionTest::SetUp - display");
+    sp<android::IBinder> display(
+            SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    DisplayInfo info;
+    SurfaceComposerClient::getDisplayInfo(display, &info);
+
+    mDisplayWidth = info.w;
+    mDisplayHeight = info.h;
+
+    // Background surface
+    mBGSurfaceControl = mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth,
+                                                       mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(mBGSurfaceControl != nullptr);
+    ASSERT_TRUE(mBGSurfaceControl->isValid());
+    fillSurfaceRGBA8(mBGSurfaceControl, BLUE);
+
+    // Foreground surface
+    mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
+                                                       PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(mFGSurfaceControl != nullptr);
+    ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+    fillSurfaceRGBA8(mFGSurfaceControl, RED);
+
+    SurfaceComposerClient::openGlobalTransaction();
+
+    mComposerClient->setDisplayLayerStack(display, 0);
+
+    ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX - 2));
+    ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
+
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX - 1));
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64));
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
+
+    // Synchronous transaction will stop this thread, so we set up a
+    // delayed, off-thread vsync request before closing the
+    // transaction. In the test code this is usually done with
+    // GlobalTransactionScope. Leaving here in the 'vanilla' form for
+    // reference.
+    ASSERT_EQ(0, sFakeComposer->getFrameCount());
+    sFakeComposer->runVSyncAfter(1ms);
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    sFakeComposer->waitUntilFrame(1);
+
+    // Reference data. This is what the HWC should see.
+    static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing");
+    mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight));
+    mBaseFrame[BG_LAYER].mSwapCount = 1;
+    mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+    mBaseFrame[FG_LAYER].mSwapCount = 1;
+
+    auto frame = sFakeComposer->getFrameRects(0);
+    ASSERT_TRUE(framesAreSame(mBaseFrame, frame));
+}
+
+void TransactionTest::TearDown() {
+    ALOGD("TransactionTest::TearDown");
+
+    mComposerClient->dispose();
+    mBGSurfaceControl = 0;
+    mFGSurfaceControl = 0;
+    mComposerClient = 0;
+
+    sFakeComposer->runVSyncAndWait();
+    mBaseFrame.clear();
+    sFakeComposer->clearFrames();
+    ASSERT_EQ(0, sFakeComposer->getFrameCount());
+
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    std::vector<LayerDebugInfo> layers;
+    status_t result = sf->getLayerDebugInfo(&layers);
+    if (result != NO_ERROR) {
+        ALOGE("Failed to get layers %s %d", strerror(-result), result);
+    } else {
+        // If this fails, the test being torn down leaked layers.
+        EXPECT_EQ(0u, layers.size());
+        if (layers.size() > 0) {
+            for (auto layer = layers.begin(); layer != layers.end(); ++layer) {
+                std::cout << to_string(*layer).c_str();
+            }
+            // To ensure the next test has clean slate, will run the class
+            // tear down and setup here.
+            TearDownTestCase();
+            SetUpTestCase();
+        }
+    }
+    ALOGD("TransactionTest::TearDown - complete");
+}
+
+TEST_F(TransactionTest, LayerMove) {
+    ALOGD("TransactionTest::LayerMove");
+
+    // The scope opens and closes a global transaction and, at the
+    // same time, makes sure the SurfaceFlinger progresses one frame
+    // after the transaction closes. The results of the transaction
+    // should be available in the latest frame stored by the fake
+    // composer.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
+        // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
+        // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
+        //
+        // sFakeComposer->runVSyncAndWait();
+    }
+
+    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+    sFakeComposer->runVSyncAndWait();
+
+    ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
+                                                  // no extra frames.
+
+    // NOTE: Frame 0 is produced in the SetUp.
+    auto frame1Ref = mBaseFrame;
+    frame1Ref[FG_LAYER].mDisplayFrame =
+            hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves.
+    EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+    auto frame2Ref = frame1Ref;
+    frame2Ref[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+}
+
+TEST_F(TransactionTest, LayerResize) {
+    ALOGD("TransactionTest::LayerResize");
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128));
+    }
+
+    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+    sFakeComposer->runVSyncAndWait();
+
+    ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
+                                                  // no extra frames.
+
+    auto frame1Ref = mBaseFrame;
+    // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size posted.
+    EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+    auto frame2Ref = frame1Ref;
+    frame2Ref[FG_LAYER].mSwapCount++;
+    frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128};
+    frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f};
+    EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+}
+
+TEST_F(TransactionTest, LayerCrop) {
+    // TODO: Add scaling to confirm that crop happens in buffer space?
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        Rect cropRect(16, 16, 32, 32);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect));
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f};
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerFinalCrop) {
+    // TODO: Add scaling to confirm that crop happens in display space?
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        Rect cropRect(32, 32, 32 + 64, 32 + 64);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect));
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    // In display space we are cropping with [32, 32, 96, 96] against display rect
+    // [64, 64, 128, 128]. Should yield display rect [64, 64, 96, 96]
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 32, 64 + 32};
+
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerFinalCropEmpty) {
+    // TODO: Add scaling to confirm that crop happens in display space?
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        Rect cropRect(16, 16, 32, 32);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect));
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    // In display space we are cropping with [16, 16, 32, 32] against display rect
+    // [64, 64, 128, 128]. The intersection is empty and only the background layer is composited.
+    std::vector<RenderState> referenceFrame(1);
+    referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetLayer) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3));
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    // The layers will switch order, but both are rendered because the background layer is
+    // transparent (RGBA8888).
+    std::vector<RenderState> referenceFrame(2);
+    referenceFrame[0] = mBaseFrame[FG_LAYER];
+    referenceFrame[1] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetLayerOpaque) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3));
+        ASSERT_EQ(NO_ERROR,
+                  mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque,
+                                              layer_state_t::eLayerOpaque));
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    // The former foreground layer is now covered with opaque layer - it should have disappeared
+    std::vector<RenderState> referenceFrame(1);
+    referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, SetLayerStack) {
+    ALOGD("TransactionTest::SetLayerStack");
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1));
+    }
+
+    // Foreground layer should have disappeared.
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+    std::vector<RenderState> refFrame(1);
+    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerShowHide) {
+    ALOGD("TransactionTest::LayerShowHide");
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide());
+    }
+
+    // Foreground layer should have disappeared.
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+    std::vector<RenderState> refFrame(1);
+    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
+    }
+
+    // Foreground layer should be back
+    ASSERT_EQ(3, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetAlpha) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f));
+    }
+
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetFlags) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR,
+                  mFGSurfaceControl->setFlags(layer_state_t::eLayerHidden,
+                                              layer_state_t::eLayerHidden));
+    }
+
+    // Foreground layer should have disappeared.
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+    std::vector<RenderState> refFrame(1);
+    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetMatrix) {
+    struct matrixTestData {
+        float matrix[4];
+        hwc_transform_t expectedTransform;
+        hwc_rect_t expectedDisplayFrame;
+    };
+
+    // The matrix operates on the display frame and is applied before
+    // the position is added. So, the foreground layer rect is (0, 0,
+    // 64, 64) is first transformed, potentially yielding negative
+    // coordinates and then the position (64, 64) is added yielding
+    // the final on-screen rectangles given.
+
+    const matrixTestData MATRIX_TESTS[7] = // clang-format off
+            {{{-1.f, 0.f, 0.f, 1.f},    HWC_TRANSFORM_FLIP_H,           {0, 64, 64, 128}},
+             {{1.f, 0.f, 0.f, -1.f},    HWC_TRANSFORM_FLIP_V,           {64, 0, 128, 64}},
+             {{0.f, 1.f, -1.f, 0.f},    HWC_TRANSFORM_ROT_90,           {0, 64, 64, 128}},
+             {{-1.f, 0.f, 0.f, -1.f},   HWC_TRANSFORM_ROT_180,          {0, 0, 64, 64}},
+             {{0.f, -1.f, 1.f, 0.f},    HWC_TRANSFORM_ROT_270,          {64, 0, 128, 64}},
+             {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_H_ROT_90,    {64, 64, 128, 128}},
+             {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_V_ROT_90,    {64, 64, 128, 128}}};
+    // clang-format on
+    constexpr int TEST_COUNT = sizeof(MATRIX_TESTS)/sizeof(matrixTestData);
+
+    for (int i = 0; i < TEST_COUNT; i++) {
+        // TODO: How to leverage the HWC2 stringifiers?
+        const matrixTestData& xform = MATRIX_TESTS[i];
+        SCOPED_TRACE(i);
+        {
+            GlobalTransactionScope gts(*sFakeComposer);
+            ASSERT_EQ(NO_ERROR,
+                      mFGSurfaceControl->setMatrix(xform.matrix[0], xform.matrix[1],
+                                                   xform.matrix[2], xform.matrix[3]));
+        }
+
+        auto referenceFrame = mBaseFrame;
+        referenceFrame[FG_LAYER].mTransform = xform.expectedTransform;
+        referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame;
+
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+    }
+}
+
+#if 0
+TEST_F(TransactionTest, LayerSetMatrix2) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        // TODO: PLEASE SPEC THE FUNCTION!
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(0.11f, 0.123f,
+                                                         -2.33f, 0.22f));
+    }
+    auto referenceFrame = mBaseFrame;
+    // TODO: Is this correct for sure?
+    //referenceFrame[FG_LAYER].mTransform = HWC_TRANSFORM_FLIP_V & HWC_TRANSFORM_ROT_90;
+
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+#endif
+
+TEST_F(TransactionTest, DeferredTransaction) {
+    // Synchronization surface
+    constexpr static int SYNC_LAYER = 2;
+    auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
+                                                             PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(syncSurfaceControl != nullptr);
+    ASSERT_TRUE(syncSurfaceControl->isValid());
+
+    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, syncSurfaceControl->setLayer(INT32_MAX - 1));
+        ASSERT_EQ(NO_ERROR, syncSurfaceControl->setPosition(mDisplayWidth - 2, mDisplayHeight - 2));
+        ASSERT_EQ(NO_ERROR, syncSurfaceControl->show());
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
+                                            mDisplayWidth - 1, mDisplayHeight - 1));
+    referenceFrame[SYNC_LAYER].mSwapCount = 1;
+    EXPECT_EQ(2, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // set up two deferred transactions on different frames - these should not yield composited
+    // frames
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75));
+        mFGSurfaceControl
+                ->deferTransactionUntil(syncSurfaceControl->getHandle(),
+                                        syncSurfaceControl->getSurface()->getNextFrameNumber());
+    }
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
+        mFGSurfaceControl
+                ->deferTransactionUntil(syncSurfaceControl->getHandle(),
+                                        syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+    }
+    EXPECT_EQ(4, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // should trigger the first deferred transaction, but not the second one
+    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+    sFakeComposer->runVSyncAndWait();
+    EXPECT_EQ(5, sFakeComposer->getFrameCount());
+
+    referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+    referenceFrame[SYNC_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // should show up immediately since it's not deferred
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0));
+    }
+    referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
+    EXPECT_EQ(6, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // trigger the second deferred transaction
+    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+    sFakeComposer->runVSyncAndWait();
+    // TODO: Compute from layer size?
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64};
+    referenceFrame[SYNC_LAYER].mSwapCount++;
+    EXPECT_EQ(7, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, SetRelativeLayer) {
+    constexpr int RELATIVE_LAYER = 2;
+    auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, 64,
+                                                                 PIXEL_FORMAT_RGBA_8888, 0);
+    fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED);
+
+    // Now we stack the surface above the foreground surface and make sure it is visible.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        relativeSurfaceControl->setPosition(64, 64);
+        relativeSurfaceControl->show();
+        relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1);
+    }
+    auto referenceFrame = mBaseFrame;
+    // NOTE: All three layers will be visible as the surfaces are
+    // transparent because of the RGBA format.
+    referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+    referenceFrame[RELATIVE_LAYER].mSwapCount = 1;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // A call to setLayer will override a call to setRelativeLayer
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        relativeSurfaceControl->setLayer(0);
+    }
+
+    // Previous top layer will now appear at the bottom.
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]);
+    EXPECT_EQ(3, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+class ChildLayerTest : public TransactionTest {
+protected:
+    constexpr static int CHILD_LAYER = 2;
+
+    void SetUp() override {
+        TransactionTest::SetUp();
+        mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+                                                PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+        fillSurfaceRGBA8(mChild, LIGHT_GRAY);
+
+        sFakeComposer->runVSyncAndWait();
+        mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+        mBaseFrame[CHILD_LAYER].mSwapCount = 1;
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+        ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+    }
+    void TearDown() override {
+        mChild = 0;
+        TransactionTest::TearDown();
+    }
+
+    sp<SurfaceControl> mChild;
+};
+
+TEST_F(ChildLayerTest, Positioning) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mChild->setPosition(10, 10);
+        // Move to the same position as in the original setup.
+        mFGSurfaceControl->setPosition(64, 64);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0));
+    }
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64};
+    referenceFrame2[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Cropping) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mChild->setPosition(0, 0);
+        mFGSurfaceControl->setPosition(0, 0);
+        mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5));
+    }
+    // NOTE: The foreground surface would be occluded by the child
+    // now, but is included in the stack because the child is
+    // transparent.
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, FinalCropping) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mChild->setPosition(0, 0);
+        mFGSurfaceControl->setPosition(0, 0);
+        mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5));
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Constraints) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mFGSurfaceControl->setPosition(0, 0);
+        mChild->setPosition(63, 63);
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64};
+    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Scaling) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setPosition(0, 0);
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0);
+    }
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+    referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, LayerAlpha) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mChild->setPosition(0, 0);
+        mFGSurfaceControl->setPosition(0, 0);
+        ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5));
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+    referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5));
+    }
+
+    auto referenceFrame2 = referenceFrame;
+    referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
+    referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, ReparentChildren) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mChild->setPosition(10, 10);
+        mFGSurfaceControl->setPosition(64, 64);
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle());
+    }
+
+    auto referenceFrame2 = referenceFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, DetachChildren) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mChild->setPosition(10, 10);
+        mFGSurfaceControl->setPosition(64, 64);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->detachChildren();
+    }
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->hide();
+    }
+
+    // Nothing should have changed. The child control becomes a no-op
+    // zombie on detach. See comments for detachChildren in the
+    // SurfaceControl.h file.
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mChild->setPosition(0, 0);
+        mFGSurfaceControl->setPosition(0, 0);
+    }
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // We cause scaling by 2.
+        mFGSurfaceControl->setSize(128, 128);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+// Regression test for b/37673612
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->show();
+        mChild->setPosition(0, 0);
+        mFGSurfaceControl->setPosition(0, 0);
+    }
+
+    // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
+    // the WM specified state size.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(128, 64);
+    }
+
+    sp<Surface> s = mFGSurfaceControl->getSurface();
+    auto anw = static_cast<ANativeWindow*>(s.get());
+    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+    native_window_set_buffers_dimensions(anw, 64, 128);
+    fillSurfaceRGBA8(mFGSurfaceControl, RED);
+    sFakeComposer->runVSyncAndWait();
+
+    // The child should still be in the same place and not have any strange scaling as in
+    // b/37673612.
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64};
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f};
+    referenceFrame[FG_LAYER].mSwapCount++;
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Bug36858924) {
+    // Destroy the child layer
+    mChild.clear();
+
+    // Now recreate it as hidden
+    mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+                                            PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden,
+                                            mFGSurfaceControl.get());
+
+    // Show the child layer in a deferred transaction
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(),
+                                      mFGSurfaceControl->getSurface()->getNextFrameNumber());
+        mChild->show();
+    }
+
+    // Render the foreground surface a few times
+    //
+    // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
+    // frame because SurfaceFlinger would never process the deferred transaction and would therefore
+    // never acquire/release the first buffer
+    ALOGI("Filling 1");
+    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+    sFakeComposer->runVSyncAndWait();
+    ALOGI("Filling 2");
+    fillSurfaceRGBA8(mFGSurfaceControl, BLUE);
+    sFakeComposer->runVSyncAndWait();
+    ALOGI("Filling 3");
+    fillSurfaceRGBA8(mFGSurfaceControl, RED);
+    sFakeComposer->runVSyncAndWait();
+    ALOGI("Filling 4");
+    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+    sFakeComposer->runVSyncAndWait();
+}
+
+class LatchingTest : public TransactionTest {
+protected:
+    void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); }
+
+    void unlockFGBuffer() {
+        sp<Surface> s = mFGSurfaceControl->getSurface();
+        ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+        sFakeComposer->runVSyncAndWait();
+    }
+
+    void completeFGResize() {
+        fillSurfaceRGBA8(mFGSurfaceControl, RED);
+        sFakeComposer->runVSyncAndWait();
+    }
+    void restoreInitialState() {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(64, 64);
+        mFGSurfaceControl->setPosition(64, 64);
+        mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64));
+        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
+    }
+};
+
+TEST_F(LatchingTest, SurfacePositionLatching) {
+    // By default position can be updated even while
+    // a resize is pending.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(32, 32);
+        mFGSurfaceControl->setPosition(100, 100);
+    }
+
+    // The size should not have updated as we have not provided a new buffer.
+    auto referenceFrame1 = mBaseFrame;
+    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64};
+    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+    restoreInitialState();
+
+    // Now we repeat with setGeometryAppliesWithResize
+    // and verify the position DOESN'T latch.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setGeometryAppliesWithResize();
+        mFGSurfaceControl->setSize(32, 32);
+        mFGSurfaceControl->setPosition(100, 100);
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32};
+    referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
+    referenceFrame2[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, CropLatching) {
+    // Normally the crop applies immediately even while a resize is pending.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(128, 128);
+        mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
+    }
+
+    auto referenceFrame1 = mBaseFrame;
+    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+    referenceFrame1[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+    restoreInitialState();
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(128, 128);
+        mFGSurfaceControl->setGeometryAppliesWithResize();
+        mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+    referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+    referenceFrame2[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, FinalCropLatching) {
+    // Normally the crop applies immediately even while a resize is pending.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(128, 128);
+        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    }
+
+    auto referenceFrame1 = mBaseFrame;
+    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+    referenceFrame1[FG_LAYER].mSourceCrop =
+            hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+    restoreInitialState();
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(128, 128);
+        mFGSurfaceControl->setGeometryAppliesWithResize();
+        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+    referenceFrame2[FG_LAYER].mSourceCrop =
+            hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+    referenceFrame2[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+// In this test we ensure that setGeometryAppliesWithResize actually demands
+// a buffer of the new size, and not just any size.
+TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) {
+    // Normally the crop applies immediately even while a resize is pending.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(128, 128);
+        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    }
+
+    auto referenceFrame1 = mBaseFrame;
+    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+    referenceFrame1[FG_LAYER].mSourceCrop =
+            hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+    restoreInitialState();
+
+    // In order to prepare to submit a buffer at the wrong size, we acquire it prior to
+    // initiating the resize.
+    lockAndFillFGBuffer();
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(128, 128);
+        mFGSurfaceControl->setGeometryAppliesWithResize();
+        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    // We now submit our old buffer, at the old size, and ensure it doesn't
+    // trigger geometry latching.
+    unlockFGBuffer();
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+    auto referenceFrame3 = referenceFrame2;
+    referenceFrame3[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+    referenceFrame3[FG_LAYER].mSourceCrop =
+            hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+    referenceFrame3[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame3, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) {
+    // In this scenario, we attempt to set the final crop a second time while the resize
+    // is still pending, and ensure we are successful. Success meaning the second crop
+    // is the one which eventually latches and not the first.
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setSize(128, 128);
+        mFGSurfaceControl->setGeometryAppliesWithResize();
+        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    }
+
+    {
+        GlobalTransactionScope gts(*sFakeComposer);
+        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    sftest::FakeHwcEnvironment* fakeEnvironment = new sftest::FakeHwcEnvironment;
+    ::testing::AddGlobalTestEnvironment(fakeEnvironment);
+    ::testing::InitGoogleMock(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
index 062485e..4055527 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -382,7 +382,9 @@
         if (outErr) {
             *outErr = err;
         } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set cursor position";
+            ASSERT_TRUE((err == HWC2_ERROR_NONE) ||
+                (err == HWC2_ERROR_BAD_LAYER)) <<
+                "failed to set cursor position";
         }
     }
 
@@ -652,7 +654,7 @@
             hwc2_layer_request_t request = requests.at(i);
 
             EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer),
-                    0) << "get display requests returned an unknown layer";
+                    1) << "get display requests returned an unknown layer";
             EXPECT_NE(request, 0) << "returned empty request for layer "
                     << requestedLayer;
 
@@ -1603,9 +1605,10 @@
         EXPECT_EQ(layers.size(), fences.size());
 
         for (int32_t fence : fences) {
-            EXPECT_GE(sync_wait(fence, msWait), 0);
-            if (fence >= 0)
+            if (fence >= 0) {
+                EXPECT_GE(sync_wait(fence, msWait), 0);
                 close(fence);
+            }
         }
     }
 
@@ -1643,8 +1646,9 @@
                 testLayers->getBlendMode(layer)));
         EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer,
                 testLayers->getColor(layer)));
-        EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, cursor.left,
-                cursor.top));
+        if (composition == HWC2_COMPOSITION_CURSOR)
+            EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer,
+            cursor.left, cursor.top));
         EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer,
                 testLayers->getDataspace(layer)));
         EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer,
@@ -2895,7 +2899,6 @@
     ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
             [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
                     Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
                 const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
                 EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
                         cursorPosition.left, cursorPosition.top, outErr));
@@ -4406,11 +4409,11 @@
 /* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */
 TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter)
 {
-    hwc2_display_t display = HWC_DISPLAY_PRIMARY;
     hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+    for (auto display : mDisplays) {
+        ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
+        EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+    }
 }
 
 /* TESTCASE: Tests that the HWC2 can get the max virtual display count. */
diff --git a/services/thermalservice/Android.bp b/services/thermalservice/Android.bp
new file mode 100644
index 0000000..d754560
--- /dev/null
+++ b/services/thermalservice/Android.bp
@@ -0,0 +1,61 @@
+subdirs = [
+    "libthermalcallback"
+]
+
+cc_library {
+    name: "libthermalservice",
+
+    srcs: [
+        "aidl/android/os/IThermalEventListener.aidl",
+        "aidl/android/os/IThermalService.aidl",
+        "aidl/android/os/Temperature.cpp",
+    ],
+    aidl: {
+      include_dirs: ["frameworks/native/services/thermalservice/aidl"],
+      export_aidl_headers: true,
+    },
+    export_include_dirs: ["aidl"],
+
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
+
+cc_binary {
+    name: "thermalserviced",
+
+    srcs: [
+        "ThermalService.cpp",
+        "thermalserviced.cpp",
+    ],
+
+    include_dirs: ["frameworks/native"],
+
+    shared_libs: [
+        "libthermalservice",
+        "libbinder",
+        "libutils",
+        "libthermalcallback",
+        "android.hardware.thermal@1.1",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+    init_rc: ["thermalservice.rc"],
+}
diff --git a/services/thermalservice/ThermalService.cpp b/services/thermalservice/ThermalService.cpp
new file mode 100644
index 0000000..6e09a83
--- /dev/null
+++ b/services/thermalservice/ThermalService.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 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 "ThermalService.h"
+#include <android/os/IThermalService.h>
+#include <android/os/IThermalEventListener.h>
+#include <android/os/Temperature.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+
+namespace android {
+namespace os {
+
+/**
+ * Notify registered listeners of a thermal throttling start/stop event.
+ * @param temperature the temperature at which the event was generated
+ */
+binder::Status ThermalService::notifyThrottling(
+    const bool isThrottling, const Temperature& temperature) {
+    Mutex::Autolock _l(mListenersLock);
+
+    mThrottled = isThrottling;
+    mThrottleTemperature = temperature;
+
+    for (size_t i = 0; i < mListeners.size(); i++) {
+      mListeners[i]->notifyThrottling(isThrottling, temperature);
+    }
+    return binder::Status::ok();
+}
+
+/**
+ * Query whether the system is currently thermal throttling.
+ * @return true if currently thermal throttling, else false
+ */
+binder::Status ThermalService::isThrottling(bool* _aidl_return) {
+    Mutex::Autolock _l(mListenersLock);
+    *_aidl_return = mThrottled;
+    return binder::Status::ok();
+}
+
+/**
+ * Register a new thermal event listener.
+ * @param listener the client's IThermalEventListener instance to which
+ *                 notifications are to be sent
+ */
+binder::Status ThermalService::registerThermalEventListener(
+    const sp<IThermalEventListener>& listener) {
+    {
+        if (listener == NULL)
+            return binder::Status::ok();
+        Mutex::Autolock _l(mListenersLock);
+        // check whether this is a duplicate
+        for (size_t i = 0; i < mListeners.size(); i++) {
+            if (IInterface::asBinder(mListeners[i]) ==
+                IInterface::asBinder(listener)) {
+                return binder::Status::ok();
+            }
+        }
+
+        mListeners.add(listener);
+        IInterface::asBinder(listener)->linkToDeath(this);
+    }
+
+    return binder::Status::ok();
+}
+
+/**
+ * Unregister a previously-registered thermal event listener.
+ * @param listener the client's IThermalEventListener instance to which
+ *                 notifications are to no longer be sent
+ */
+binder::Status ThermalService::unregisterThermalEventListener(
+    const sp<IThermalEventListener>& listener) {
+    if (listener == NULL)
+        return binder::Status::ok();
+    Mutex::Autolock _l(mListenersLock);
+    for (size_t i = 0; i < mListeners.size(); i++) {
+        if (IInterface::asBinder(mListeners[i]) ==
+            IInterface::asBinder(listener)) {
+            IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
+            mListeners.removeAt(i);
+            break;
+        }
+    }
+
+    return binder::Status::ok();
+}
+
+void ThermalService::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock _l(mListenersLock);
+
+    for (size_t i = 0; i < mListeners.size(); i++) {
+        if (IInterface::asBinder(mListeners[i]) == who) {
+            mListeners.removeAt(i);
+            break;
+        }
+    }
+}
+
+/**
+ * Publish the supplied ThermalService to servicemanager.
+ */
+void ThermalService::publish(
+    const sp<ThermalService>& service) {
+    defaultServiceManager()->addService(String16("thermalservice"),
+                                        service);
+}
+
+}  // namespace os
+}  // namespace android
diff --git a/services/thermalservice/ThermalService.h b/services/thermalservice/ThermalService.h
new file mode 100644
index 0000000..17dfcbc
--- /dev/null
+++ b/services/thermalservice/ThermalService.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 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_THERMALSERVICE_THERMALSERVICE_H
+#define ANDROID_THERMALSERVICE_THERMALSERVICE_H
+
+#include <android/os/BnThermalService.h>
+#include <android/os/IThermalEventListener.h>
+#include <android/os/Temperature.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace os {
+
+class ThermalService : public BnThermalService,
+                       public IBinder::DeathRecipient {
+public:
+  ThermalService() : mThrottled(false) {};
+    void publish(const sp<ThermalService>& service);
+    binder::Status notifyThrottling(
+        const bool isThrottling, const Temperature& temperature);
+
+private:
+    Mutex mListenersLock;
+    Vector<sp<IThermalEventListener> > mListeners;
+    bool mThrottled;
+    Temperature mThrottleTemperature;
+
+    binder::Status registerThermalEventListener(
+        const sp<IThermalEventListener>& listener);
+    binder::Status unregisterThermalEventListener(
+        const sp<IThermalEventListener>& listener);
+    binder::Status isThrottling(bool* _aidl_return);
+    void binderDied(const wp<IBinder>& who);
+};
+
+};  // namespace os
+};  // namespace android
+
+#endif // ANDROID_THERMALSERVICE_THERMALSERVICE_H
diff --git a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
new file mode 100644
index 0000000..050325e
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2017, 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.
+ */
+
+package android.os;
+
+import android.os.Temperature;
+
+/**
+  * Listener for thermal events.
+  * {@hide}
+  */
+oneway interface IThermalEventListener {
+    /**
+     * Called when a thermal throttling start/stop event is received.
+     * @param temperature the temperature at which the event was generated.
+     */
+    void notifyThrottling(
+        in boolean isThrottling, in Temperature temperature);
+}
diff --git a/services/thermalservice/aidl/android/os/IThermalService.aidl b/services/thermalservice/aidl/android/os/IThermalService.aidl
new file mode 100644
index 0000000..e699202
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/IThermalService.aidl
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2017, 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.
+ */
+
+package android.os;
+
+import android.os.IThermalEventListener;
+import android.os.Temperature;
+
+/** {@hide} */
+interface IThermalService {
+    /**
+      * Register a listener for thermal events.
+      * @param listener the IThermalEventListener to be notified.
+      * {@hide}
+      */
+    void registerThermalEventListener(in IThermalEventListener listener);
+    /**
+      * Unregister a previously-registered listener for thermal events.
+      * @param listener the IThermalEventListener to no longer be notified.
+      * {@hide}
+      */
+    void unregisterThermalEventListener(in IThermalEventListener listener);
+    /**
+      * Send a thermal throttling start/stop notification to all listeners.
+      * @param temperature the temperature at which the event was generated.
+      * {@hide}
+      */
+    oneway void notifyThrottling(
+        in boolean isThrottling, in Temperature temperature);
+    /**
+      * Return whether system performance is currently thermal throttling.
+      * {@hide}
+      */
+    boolean isThrottling();
+}
diff --git a/services/thermalservice/aidl/android/os/Temperature.aidl b/services/thermalservice/aidl/android/os/Temperature.aidl
new file mode 100644
index 0000000..0293c39
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/Temperature.aidl
@@ -0,0 +1,5 @@
+package android.os;
+
+/* Encodes a temperature used by ThermalService. */
+
+parcelable Temperature cpp_header "android/os/Temperature.h";
diff --git a/services/thermalservice/aidl/android/os/Temperature.cpp b/services/thermalservice/aidl/android/os/Temperature.cpp
new file mode 100644
index 0000000..df207b7
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/Temperature.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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 "android/os/Temperature.h"
+
+#include <math.h>
+#include <stdint.h>
+#include <binder/Parcel.h>
+#include <hardware/thermal.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace os {
+
+Temperature::Temperature() : value_(NAN), type_(DEVICE_TEMPERATURE_UNKNOWN) {}
+
+Temperature::Temperature(const float value, const int type) :
+    value_(value), type_(type)  {}
+
+Temperature::~Temperature() {}
+
+/*
+ * Parcel read/write code must be kept in sync with
+ * frameworks/base/core/java/android/os/Temperature.java
+ */
+
+status_t Temperature::readFromParcel(const Parcel* p) {
+    value_ = p->readFloat();
+    type_ = p->readInt32();
+    return OK;
+}
+
+status_t Temperature::writeToParcel(Parcel* p) const {
+    p->writeFloat(value_);
+    p->writeInt32(type_);
+    return OK;
+}
+
+}  // namespace os
+}  // namespace android
diff --git a/services/thermalservice/aidl/android/os/Temperature.h b/services/thermalservice/aidl/android/os/Temperature.h
new file mode 100644
index 0000000..bbc5607
--- /dev/null
+++ b/services/thermalservice/aidl/android/os/Temperature.h
@@ -0,0 +1,33 @@
+#ifndef ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
+#define ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
+
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace os {
+
+class Temperature : public Parcelable {
+ public:
+
+  Temperature();
+  Temperature(const float value, const int type);
+  ~Temperature() override;
+
+  float getValue() const {return value_;};
+  float getType() const {return type_;};
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  // The value of the temperature as a float, or NAN if unknown.
+  float value_;
+  // The type of the temperature, an enum temperature_type from
+  // hardware/thermal.h
+  int type_;
+};
+
+}  // namespace os
+}  // namespace android
+
+#endif   // ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
diff --git a/services/thermalservice/libthermalcallback/Android.bp b/services/thermalservice/libthermalcallback/Android.bp
new file mode 100644
index 0000000..e98506e
--- /dev/null
+++ b/services/thermalservice/libthermalcallback/Android.bp
@@ -0,0 +1,19 @@
+cc_library_shared {
+    name: "libthermalcallback",
+    srcs: [
+        "ThermalCallback.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    include_dirs: ["frameworks/native"],
+    shared_libs: [
+        "android.hardware.thermal@1.1",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libthermalservice",
+        "libutils",
+    ],
+}
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.cpp b/services/thermalservice/libthermalcallback/ThermalCallback.cpp
new file mode 100644
index 0000000..5e094fa
--- /dev/null
+++ b/services/thermalservice/libthermalcallback/ThermalCallback.cpp
@@ -0,0 +1,69 @@
+#define LOG_TAG "android.hardware.thermal.thermalcallback@1.1-impl"
+#include <log/log.h>
+
+#include "ThermalCallback.h"
+#include "services/thermalservice/ThermalService.h"
+#include <math.h>
+#include <android/os/Temperature.h>
+#include <hardware/thermal.h>
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::os::ThermalService;
+using ::android::hardware::thermal::V1_0::TemperatureType;
+
+// Register a binder ThermalService object for sending events
+void ThermalCallback::registerThermalService(sp<ThermalService> thermalService)
+{
+    mThermalService = thermalService;
+}
+
+// Methods from IThermalCallback::V1_1 follow.
+Return<void> ThermalCallback::notifyThrottling(
+      bool isThrottling,
+      const android::hardware::thermal::V1_0::Temperature& temperature) {
+
+    // Convert HIDL IThermal Temperature to binder IThermalService Temperature.
+    if (mThermalService != nullptr) {
+        float value = NAN;
+        int type = DEVICE_TEMPERATURE_UNKNOWN;
+
+        switch(temperature.type) {
+          case TemperatureType::CPU:
+            type = DEVICE_TEMPERATURE_CPU;
+            break;
+          case TemperatureType::GPU:
+            type = DEVICE_TEMPERATURE_GPU;
+            break;
+          case TemperatureType::BATTERY:
+            type = DEVICE_TEMPERATURE_BATTERY;
+            break;
+          case TemperatureType::SKIN:
+            type = DEVICE_TEMPERATURE_SKIN;
+            break;
+          case TemperatureType::UNKNOWN:
+          default:
+            type = DEVICE_TEMPERATURE_UNKNOWN;
+            break;
+        }
+
+        value = temperature.currentValue == UNKNOWN_TEMPERATURE ? NAN :
+            temperature.currentValue;
+
+        android::os::Temperature thermal_svc_temp(value, type);
+        mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
+    } else {
+        ALOGE("IThermalService binder service not created, drop throttling event");
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace thermal
+}  // namespace hardware
+}  // namespace android
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.h b/services/thermalservice/libthermalcallback/ThermalCallback.h
new file mode 100644
index 0000000..3d72c68
--- /dev/null
+++ b/services/thermalservice/libthermalcallback/ThermalCallback.h
@@ -0,0 +1,43 @@
+#ifndef ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
+#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
+
+#include <android/hardware/thermal/1.1/IThermalCallback.h>
+#include <android/hardware/thermal/1.0/types.h>
+#include <android/os/Temperature.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "services/thermalservice/ThermalService.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::os::ThermalService;
+
+class ThermalCallback : public IThermalCallback {
+ public:
+    // Register a binder ThermalService object for sending events
+    void registerThermalService(sp<ThermalService> thermalService);
+
+    // Methods from IThermalCallback::V1_1 follow.
+    Return<void> notifyThrottling(
+        bool isThrottling,
+        const android::hardware::thermal::V1_0::Temperature& temperature)
+        override;
+
+ private:
+    // Our registered binder ThermalService object to use for sending events
+    sp<android::os::ThermalService> mThermalService;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace thermal
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc
new file mode 100644
index 0000000..b9836ce
--- /dev/null
+++ b/services/thermalservice/thermalservice.rc
@@ -0,0 +1,2 @@
+service thermalservice /system/bin/thermalserviced
+    class core
diff --git a/services/thermalservice/thermalserviced.cpp b/services/thermalservice/thermalserviced.cpp
new file mode 100644
index 0000000..8e27266
--- /dev/null
+++ b/services/thermalservice/thermalserviced.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 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 "thermalserviced"
+#include <log/log.h>
+
+#include "thermalserviced.h"
+#include "ThermalService.h"
+#include "libthermalcallback/ThermalCallback.h"
+
+#include <android/hardware/thermal/1.1/IThermal.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <hidl/HidlTransportSupport.h>
+
+using namespace android;
+using ::android::hardware::thermal::V1_1::IThermal;
+using ::android::hardware::thermal::V1_0::Temperature;
+using ::android::hardware::thermal::V1_1::IThermalCallback;
+using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::os::ThermalService;
+
+template<typename T>
+using Return = hardware::Return<T>;
+
+namespace {
+
+// Our thermalserviced main object
+ThermalServiceDaemon* gThermalServiceDaemon;
+
+// Thermal HAL client
+sp<IThermal> gThermalHal = nullptr;
+
+// Binder death notifier informing of Thermal HAL death.
+struct ThermalServiceDeathRecipient : hidl_death_recipient {
+    virtual void serviceDied(
+        uint64_t cookie __unused, const wp<IBase>& who __unused) {
+        gThermalHal = nullptr;
+        ALOGE("IThermal HAL died");
+        gThermalServiceDaemon->getThermalHal();
+    }
+};
+
+sp<ThermalServiceDeathRecipient> gThermalHalDied = nullptr;
+
+}  // anonymous namespace
+
+void ThermalServiceDaemon::thermalServiceStartup() {
+    // Binder IThermalService startup
+    mThermalService = new android::os::ThermalService;
+    mThermalService->publish(mThermalService);
+    // Register IThermalService object with IThermalCallback
+    if (mThermalCallback != nullptr)
+        mThermalCallback->registerThermalService(mThermalService);
+    IPCThreadState::self()->joinThreadPool();
+}
+
+// Lookup Thermal HAL, register death notifier, register our
+// ThermalCallback with the Thermal HAL.
+void ThermalServiceDaemon::getThermalHal() {
+    gThermalHal = IThermal::getService();
+    if (gThermalHal == nullptr) {
+        ALOGW("Unable to get Thermal HAL V1.1, vendor thermal event notification not available");
+        return;
+    }
+
+    // Binder death notifier for Thermal HAL
+    if (gThermalHalDied == nullptr)
+        gThermalHalDied = new ThermalServiceDeathRecipient();
+
+    if (gThermalHalDied != nullptr)
+        gThermalHal->linkToDeath(gThermalHalDied, 0x451F /* cookie */);
+
+    if (mThermalCallback != nullptr) {
+        Return<void> ret = gThermalHal->registerThermalCallback(
+            mThermalCallback);
+        if (!ret.isOk())
+            ALOGE("registerThermalCallback failed, status: %s",
+                  ret.description().c_str());
+    }
+}
+
+void ThermalServiceDaemon::thermalCallbackStartup() {
+    // HIDL IThermalCallback startup
+    // Need at least 2 threads in thread pool since we wait for dead HAL
+    // to come back on the binder death notification thread and we need
+    // another thread for the incoming service now available call.
+    configureRpcThreadpool(2, false /* callerWillJoin */);
+    mThermalCallback = new ThermalCallback();
+    // Lookup Thermal HAL and register our ThermalCallback.
+    getThermalHal();
+}
+
+int main(int /*argc*/, char** /*argv*/) {
+    gThermalServiceDaemon = new ThermalServiceDaemon();
+    gThermalServiceDaemon->thermalCallbackStartup();
+    gThermalServiceDaemon->thermalServiceStartup();
+    /* NOTREACHED */
+}
diff --git a/services/thermalservice/thermalserviced.h b/services/thermalservice/thermalserviced.h
new file mode 100644
index 0000000..309e2fe
--- /dev/null
+++ b/services/thermalservice/thermalserviced.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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_THERMALSERVICE_THERMALSERVICED_H
+#define ANDROID_THERMALSERVICE_THERMALSERVICED_H
+
+#include "ThermalService.h"
+#include "libthermalcallback/ThermalCallback.h"
+
+using namespace android;
+using ::android::hardware::thermal::V1_0::Temperature;
+using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
+using ::android::os::ThermalService;
+
+class ThermalServiceDaemon {
+ public:
+    void thermalServiceStartup();
+    void thermalCallbackStartup();
+    void getThermalHal();
+    ThermalServiceDaemon() {};
+
+ private:
+    sp<ThermalService> mThermalService;
+    sp<ThermalCallback> mThermalCallback;
+};
+
+#endif  // ANDROID_THERMALSERVICE_THERMALSERVICED_H
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp
index d4fc540..1613821 100644
--- a/services/vr/bufferhubd/bufferhubd.cpp
+++ b/services/vr/bufferhubd/bufferhubd.cpp
@@ -4,7 +4,7 @@
 #include <log/log.h>
 
 #include <dvr/performance_client_api.h>
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
 
 #include "buffer_hub.h"
 
@@ -16,7 +16,7 @@
   // We need to be able to create endpoints with full perms.
   umask(0000);
 
-  dispatcher = android::pdx::default_transport::ServiceDispatcher::Create();
+  dispatcher = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n");
 
   service = android::dvr::BufferHubService::Create();
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index c31417b..abe571a 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -161,6 +161,10 @@
   client_->onHotplug(display, connected);
 }
 
+void VrComposerClient::onRefresh(Display display) {
+  client_->onRefresh(display);
+}
+
 Return<void> VrComposerClient::registerCallback(
     const sp<IComposerCallback>& callback) {
   return client_->registerCallback(callback);
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index f492230..dfc656a 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -35,6 +35,7 @@
   virtual ~VrComposerClient();
 
   void onHotplug(Display display, IComposerCallback::Connection connected);
+  void onRefresh(Display display);
 
   // IComposerClient
   Return<void> registerCallback(const sp<IComposerCallback>& callback) override;
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 861114d..fd271d0 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -133,13 +133,14 @@
               return lhs.info.z_order < rhs.info.z_order;
             });
 
-  int first_client_layer = -1, last_client_layer = -1;
+  const size_t no_layer = std::numeric_limits<size_t>::max();
+  size_t first_client_layer = no_layer, last_client_layer = no_layer;
   for (size_t i = 0; i < layers_.size(); ++i) {
     switch (layers_[i].composition_type) {
       case IComposerClient::Composition::SOLID_COLOR:
       case IComposerClient::Composition::CURSOR:
       case IComposerClient::Composition::SIDEBAND:
-        if (first_client_layer < 0)
+        if (first_client_layer == no_layer)
           first_client_layer = i;
 
         last_client_layer = i;
@@ -231,7 +232,7 @@
 
 VrHwc::~VrHwc() {}
 
-bool VrHwc::hasCapability(Capability capability) const { return false; }
+bool VrHwc::hasCapability(Capability /* capability */) const { return false; }
 
 void VrHwc::removeClient() {
   std::lock_guard<std::mutex> guard(mutex_);
@@ -305,13 +306,15 @@
   return Error::NONE;
 }
 
-Error VrHwc::getClientTargetSupport(Display display, uint32_t width,
-                                    uint32_t height, PixelFormat format,
-                                    Dataspace dataspace) {
+Error VrHwc::getClientTargetSupport(Display /* display */, uint32_t /* width */,
+                                    uint32_t /* height */,
+                                    PixelFormat /* format */,
+                                    Dataspace /* dataspace */) {
   return Error::NONE;
 }
 
-Error VrHwc::getColorModes(Display display, hidl_vec<ColorMode>* outModes) {
+Error VrHwc::getColorModes(Display /* display */,
+                           hidl_vec<ColorMode>* outModes) {
   std::vector<ColorMode> color_modes(1, ColorMode::NATIVE);
   *outModes = hidl_vec<ColorMode>(color_modes);
   return Error::NONE;
@@ -378,7 +381,7 @@
   return Error::NONE;
 }
 
-Error VrHwc::getDisplayName(Display display, hidl_string* outName) {
+Error VrHwc::getDisplayName(Display /* display */, hidl_string* outName) {
   *outName = hidl_string();
   return Error::NONE;
 }
@@ -408,7 +411,8 @@
   return Error::NONE;
 }
 
-Error VrHwc::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
+Error VrHwc::getHdrCapabilities(Display /* display */,
+                                hidl_vec<Hdr>* /* outTypes */,
                                 float* outMaxLuminance,
                                 float* outMaxAverageLuminance,
                                 float* outMinLuminance) {
@@ -472,8 +476,8 @@
 }
 
 Error VrHwc::setClientTarget(Display display, buffer_handle_t target,
-                             int32_t acquireFence, int32_t dataspace,
-                             const std::vector<hwc_rect_t>& damage) {
+                             int32_t acquireFence, int32_t /* dataspace */,
+                             const std::vector<hwc_rect_t>& /* damage */) {
   base::unique_fd fence(acquireFence);
   std::lock_guard<std::mutex> guard(mutex_);
   auto display_ptr = FindDisplay(display);
@@ -489,7 +493,7 @@
   return Error::NONE;
 }
 
-Error VrHwc::setOutputBuffer(Display display, buffer_handle_t buffer,
+Error VrHwc::setOutputBuffer(Display display, buffer_handle_t /* buffer */,
                              int32_t releaseFence) {
   base::unique_fd fence(releaseFence);
   std::lock_guard<std::mutex> guard(mutex_);
@@ -504,8 +508,9 @@
 Error VrHwc::validateDisplay(
     Display display, std::vector<Layer>* outChangedLayers,
     std::vector<IComposerClient::Composition>* outCompositionTypes,
-    uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
-    std::vector<uint32_t>* outRequestMasks) {
+    uint32_t* /* outDisplayRequestMask */,
+    std::vector<Layer>* /* outRequestedLayers */,
+    std::vector<uint32_t>* /* outRequestMasks */) {
   std::lock_guard<std::mutex> guard(mutex_);
   auto display_ptr = FindDisplay(display);
   if (!display_ptr)
@@ -516,7 +521,7 @@
   return Error::NONE;
 }
 
-Error VrHwc::acceptDisplayChanges(Display display) { return Error::NONE; }
+Error VrHwc::acceptDisplayChanges(Display /* display */) { return Error::NONE; }
 
 Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence,
                             std::vector<Layer>* outLayers,
@@ -708,8 +713,8 @@
   return Error::NONE;
 }
 
-Error VrHwc::setLayerSidebandStream(Display display, Layer layer,
-                                    buffer_handle_t stream) {
+Error VrHwc::setLayerSidebandStream(Display display, Layer /* layer */,
+                                    buffer_handle_t /* stream */) {
   std::lock_guard<std::mutex> guard(mutex_);
   if (!FindDisplay(display))
     return Error::BAD_DISPLAY;
@@ -850,6 +855,14 @@
   return Void();
 }
 
+void VrHwc::ForceDisplaysRefresh() {
+  std::lock_guard<std::mutex> guard(mutex_);
+  if (client_ != nullptr) {
+    for (const auto& pair : displays_)
+      client_.promote()->onRefresh(pair.first);
+  }
+}
+
 void VrHwc::RegisterObserver(Observer* observer) {
   std::lock_guard<std::mutex> guard(mutex_);
   if (observer_)
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index 523cda3..fce9a06 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -103,6 +103,7 @@
 
   virtual ~ComposerView() {}
 
+  virtual void ForceDisplaysRefresh() = 0;
   virtual void RegisterObserver(Observer* observer) = 0;
   virtual void UnregisterObserver(Observer* observer) = 0;
 };
@@ -288,6 +289,7 @@
   Return<void> createClient(createClient_cb hidl_cb) override;
 
   // ComposerView:
+  void ForceDisplaysRefresh() override;
   void RegisterObserver(Observer* observer) override;
   void UnregisterObserver(Observer* observer) override;
 
@@ -295,7 +297,6 @@
   HwcDisplay* FindDisplay(Display display);
 
   wp<VrComposerClient> client_;
-  sp<IComposerCallback> callbacks_;
 
   // Guard access to internal state from binder threads.
   std::mutex mutex_;
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
index d082f4b..2e70928 100644
--- a/services/vr/hardware_composer/tests/vr_composer_test.cpp
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -10,6 +10,24 @@
 
 const char kVrDisplayName[] = "VrDisplay_Test";
 
+class TestComposerView : public ComposerView {
+ public:
+  TestComposerView() {}
+  ~TestComposerView() override = default;
+
+  size_t display_refresh_count() const { return display_refresh_count_; }
+
+  void ForceDisplaysRefresh() override { display_refresh_count_++; }
+  void RegisterObserver(Observer* observer) override {}
+  void UnregisterObserver(Observer* observer) override {}
+
+  TestComposerView(const TestComposerView&) = delete;
+  void operator=(const TestComposerView&) = delete;
+
+ private:
+  size_t display_refresh_count_ = 0;
+};
+
 class TestComposerCallback : public BnVrComposerCallback {
  public:
   TestComposerCallback() {}
@@ -57,7 +75,7 @@
 
 class VrComposerTest : public testing::Test {
  public:
-  VrComposerTest() : composer_(new VrComposer()) {}
+  VrComposerTest() : composer_(new VrComposer(&composer_view_)) {}
   ~VrComposerTest() override = default;
 
   sp<IVrComposer> GetComposerProxy() const {
@@ -72,6 +90,7 @@
   }
 
  protected:
+  TestComposerView composer_view_;
   sp<VrComposer> composer_;
 
   VrComposerTest(const VrComposerTest&) = delete;
@@ -89,7 +108,9 @@
 TEST_F(VrComposerTest, TestWithObserver) {
   sp<IVrComposer> composer = GetComposerProxy();
   sp<TestComposerCallback> callback = new TestComposerCallback();
+  ASSERT_EQ(0, composer_view_.display_refresh_count());
   ASSERT_TRUE(composer->registerObserver(callback).isOk());
+  ASSERT_EQ(1, composer_view_.display_refresh_count());
 
   ComposerView::Frame frame;
   base::unique_fd fence = composer_->OnNewFrame(frame);
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
index 36a313a..d93f370 100644
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -21,24 +21,36 @@
 
 }  // namespace
 
-VrComposer::VrComposer() {}
+VrComposer::VrComposer(ComposerView* composer_view)
+  : composer_view_(composer_view) {
+  composer_view_->RegisterObserver(this);
+}
 
-VrComposer::~VrComposer() {}
+VrComposer::~VrComposer() {
+  composer_view_->UnregisterObserver(this);
+}
 
 binder::Status VrComposer::registerObserver(
     const sp<IVrComposerCallback>& callback) {
-  std::lock_guard<std::mutex> guard(mutex_);
+  {
+    std::lock_guard<std::mutex> guard(mutex_);
 
-  if (!CheckPermission())
-    return binder::Status::fromStatusT(PERMISSION_DENIED);
+    if (!CheckPermission())
+      return binder::Status::fromStatusT(PERMISSION_DENIED);
 
-  if (callback_.get()) {
-    ALOGE("Failed to register callback, already registered");
-    return binder::Status::fromStatusT(ALREADY_EXISTS);
+    if (callback_.get()) {
+      ALOGE("Failed to register callback, already registered");
+      return binder::Status::fromStatusT(ALREADY_EXISTS);
+    }
+
+    callback_ = callback;
+    IInterface::asBinder(callback_)->linkToDeath(this);
   }
 
-  callback_ = callback;
-  IInterface::asBinder(callback_)->linkToDeath(this);
+  // Don't take the lock to force display refresh otherwise it could end in a
+  // deadlock since HWC calls this with new frames and it has a lock of its own
+  // to serialize access to the display information.
+  composer_view_->ForceDisplaysRefresh();
   return binder::Status::ok();
 }
 
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
index 7b580c6..1273352 100644
--- a/services/vr/hardware_composer/vr_composer.h
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -20,7 +20,7 @@
       public ComposerView::Observer,
       public IBinder::DeathRecipient {
  public:
-  VrComposer();
+  explicit VrComposer(ComposerView* composer_view);
   ~VrComposer() override;
 
   // BnVrComposer:
@@ -40,6 +40,8 @@
 
   sp<IVrComposerCallback> callback_;
 
+  ComposerView* composer_view_;  // Not owned.
+
   VrComposer(const VrComposer&) = delete;
   void operator=(const VrComposer&) = delete;
 };
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
index e36b0ae..7701847 100644
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -36,8 +36,7 @@
                       "Failed to register service");
 
   android::sp<android::dvr::VrComposer> composer =
-      new android::dvr::VrComposer();
-  service->RegisterObserver(composer.get());
+      new android::dvr::VrComposer(service.get());
 
   android::sp<android::IServiceManager> sm(android::defaultServiceManager());
 
@@ -52,7 +51,5 @@
   android::hardware::ProcessState::self()->startThreadPool();
   android::hardware::IPCThreadState::self()->joinThreadPool();
 
-  service->UnregisterObserver(composer.get());
-
   return 0;
 }
diff --git a/services/vr/performanced/main.cpp b/services/vr/performanced/main.cpp
index ca66c71..d7dc8f6 100644
--- a/services/vr/performanced/main.cpp
+++ b/services/vr/performanced/main.cpp
@@ -9,7 +9,7 @@
 #include <sys/resource.h>
 #include <utils/threads.h>
 
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
 #include <private/android_filesystem_config.h>
 
 #include "performance_service.h"
@@ -58,7 +58,7 @@
   CHECK_ERROR(ret < 0, error, "Could not set capabilities: %s",
               strerror(errno));
 
-  dispatcher = android::pdx::default_transport::ServiceDispatcher::Create();
+  dispatcher = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher.");
 
   service = android::dvr::PerformanceService::Create();
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 4b9fbe0..4c26671 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -22,13 +22,15 @@
 using android::pdx::ErrorStatus;
 using android::pdx::Message;
 using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
 using android::pdx::default_transport::Endpoint;
+using android::pdx::rpc::DispatchRemoteMethod;
 
 namespace {
 
 const char kCpuSetBasePath[] = "/dev/cpuset";
 
+const char kRootCpuSet[] = "/";
+
 constexpr unsigned long kTimerSlackForegroundNs = 50000;
 constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
 
@@ -123,22 +125,22 @@
   // hack for now to put some form of permission logic in place while a longer
   // term solution is developed.
   using AllowRootSystem =
-      CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>,
-                                    GroupId<AID_SYSTEM>>>;
+      CheckAnd<SameProcess,
+               CheckOr<UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>>;
   using AllowRootSystemGraphics =
       CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
                                     GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
   using AllowRootSystemAudio =
       CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>,
                                     GroupId<AID_SYSTEM, AID_AUDIO>>>;
-  using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>,
-                                        GroupId<AID_SYSTEM>>;
+  using AllowRootSystemTrusted =
+      CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>;
 
   partition_permission_check_ = AllowRootSystemTrusted::Check;
 
   // Setup the scheduler classes.
   // TODO(eieio): Replace this with a device-specific config file.
-  scheduler_classes_ = {
+  scheduler_policies_ = {
       {"audio:low",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
@@ -183,12 +185,14 @@
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
         .priority = fifo_medium + 2,
-        .permission_check = AllowRootSystemTrusted::Check}},
+        .permission_check = AllowRootSystemTrusted::Check,
+        "/system/performance"}},
       {"vr:app:render",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
         .priority = fifo_medium + 1,
-        .permission_check = AllowRootSystemTrusted::Check}},
+        .permission_check = AllowRootSystemTrusted::Check,
+        "/application/performance"}},
       {"normal",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_NORMAL,
@@ -219,14 +223,80 @@
 
 Status<void> PerformanceService::OnSetSchedulerPolicy(
     Message& message, pid_t task_id, const std::string& scheduler_policy) {
-  // Forward to scheduler class handler for now. In the future this method will
-  // subsume the others by unifying both scheduler class and cpu partiton into a
-  // single policy concept.
   ALOGI(
       "PerformanceService::OnSetSchedulerPolicy: task_id=%d "
       "scheduler_policy=%s",
       task_id, scheduler_policy.c_str());
-  return OnSetSchedulerClass(message, task_id, scheduler_policy);
+
+  Task task(task_id);
+  if (!task) {
+    ALOGE(
+        "PerformanceService::OnSetSchedulerPolicy: Unable to access /proc/%d "
+        "to gather task information.",
+        task_id);
+    return ErrorStatus(EINVAL);
+  }
+
+  auto search = scheduler_policies_.find(scheduler_policy);
+  if (search != scheduler_policies_.end()) {
+    auto config = search->second;
+
+    // Make sure the sending process is allowed to make the requested change to
+    // this task.
+    if (!config.IsAllowed(message, task))
+      return ErrorStatus(EINVAL);
+
+    // Get the thread group's cpu set. Policies that do not specify a cpuset
+    // should default to this cpuset.
+    std::string thread_group_cpuset;
+    Task thread_group{task.thread_group_id()};
+    if (thread_group) {
+      thread_group_cpuset = thread_group.GetCpuSetPath();
+    } else {
+      ALOGE(
+          "PerformanceService::OnSetSchedulerPolicy: Failed to get thread "
+          "group tgid=%d for task_id=%d",
+          task.thread_group_id(), task_id);
+      thread_group_cpuset = kRootCpuSet;
+    }
+
+    std::string target_cpuset;
+    if (config.cpuset.empty()) {
+      target_cpuset = thread_group_cpuset;
+    } else {
+      target_cpuset = config.cpuset;
+    }
+    ALOGI("PerformanceService::OnSetSchedulerPolicy: Using cpuset=%s",
+          target_cpuset.c_str());
+
+    auto target_set = cpuset_.Lookup(target_cpuset);
+    if (target_set) {
+      auto attach_status = target_set->AttachTask(task_id);
+      ALOGW_IF(!attach_status,
+               "PerformanceService::OnSetSchedulerPolicy: Failed to attach "
+               "task=%d to cpuset=%s: %s",
+               task_id, target_cpuset.c_str(),
+               attach_status.GetErrorMessage().c_str());
+    } else {
+      ALOGW(
+          "PerformanceService::OnSetSchedulerPolicy: Failed to lookup "
+          "cpuset=%s",
+          target_cpuset.c_str());
+    }
+
+    struct sched_param param;
+    param.sched_priority = config.priority;
+
+    sched_setscheduler(task_id, config.scheduler_policy, &param);
+    prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
+    return {};
+  } else {
+    ALOGE(
+        "PerformanceService::OnSetSchedulerPolicy: Invalid scheduler_policy=%s "
+        "requested by task=%d.",
+        scheduler_policy.c_str(), task_id);
+    return ErrorStatus(EINVAL);
+  }
 }
 
 Status<void> PerformanceService::OnSetCpuPartition(
@@ -259,8 +329,8 @@
   if (!task)
     return ErrorStatus(EINVAL);
 
-  auto search = scheduler_classes_.find(scheduler_class);
-  if (search != scheduler_classes_.end()) {
+  auto search = scheduler_policies_.find(scheduler_class);
+  if (search != scheduler_policies_.end()) {
     auto config = search->second;
 
     // Make sure the sending process is allowed to make the requested change to
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index b28d94a..6b519ab 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -44,13 +44,13 @@
   int sched_fifo_min_priority_;
   int sched_fifo_max_priority_;
 
-  // Scheduler class config type.
-  struct SchedulerClassConfig {
+  struct SchedulerPolicyConfig {
     unsigned long timer_slack;
     int scheduler_policy;
     int priority;
     std::function<bool(const pdx::Message& message, const Task& task)>
         permission_check;
+    std::string cpuset;
 
     // Check the permisison of the given task to use this scheduler class. If a
     // permission check function is not set then operations are only allowed on
@@ -65,7 +65,7 @@
     }
   };
 
-  std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_;
+  std::unordered_map<std::string, SchedulerPolicyConfig> scheduler_policies_;
 
   std::function<bool(const pdx::Message& message, const Task& task)>
       partition_permission_check_;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 274a1b3..4065785 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -1,24 +1,65 @@
 #include <errno.h>
 #include <sched.h>
+#include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <condition_variable>
 #include <cstdlib>
+#include <iostream>
 #include <mutex>
+#include <sstream>
 #include <thread>
+#include <utility>
 
+#include <android-base/unique_fd.h>
 #include <dvr/performance_client_api.h>
 #include <gtest/gtest.h>
 #include <private/android_filesystem_config.h>
 
+#include "stdio_filebuf.h"
+#include "string_trim.h"
+#include "unique_file.h"
+
+using android::dvr::Trim;
+using android::dvr::UniqueFile;
+using android::dvr::stdio_filebuf;
+
 namespace {
 
 const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
 
+const char kProcBase[] = "/proc";
+
+std::pair<UniqueFile, int> OpenTaskFile(pid_t task_id,
+                                        const std::string& name) {
+  std::ostringstream stream;
+  stream << kProcBase << "/" << task_id << "/" << name;
+
+  UniqueFile file{fopen(stream.str().c_str(), "r")};
+  const int error = file ? 0 : errno;
+  return {std::move(file), error};
+}
+
+std::string GetTaskCpuSet(pid_t task_id) {
+  int error;
+  UniqueFile file;
+
+  std::tie(file, error) = OpenTaskFile(task_id, "cpuset");
+  if (!file)
+    return std::string("errno:") + strerror(error);
+
+  stdio_filebuf<char> filebuf(file.get());
+  std::istream file_stream(&filebuf);
+
+  std::string line;
+  std::getline(file_stream, line);
+  return Trim(line);
+}
+
 }  // anonymous namespace
 
-TEST(DISABLED_PerformanceTest, SetCpuPartition) {
+TEST(PerformanceTest, SetCpuPartition) {
   int error;
 
   // Test setting the the partition for the current task.
@@ -59,13 +100,6 @@
   }
   thread.join();
 
-  // Test setting the partition for a task that isn't valid using
-  // the task id of the thread that we just joined. Technically the
-  // id could wrap around by the time we get here, but this is
-  // extremely unlikely.
-  error = dvrSetCpuPartition(task_id, "/application");
-  EXPECT_EQ(-EINVAL, error);
-
   // Test setting the partition for a task that doesn't belong to us.
   error = dvrSetCpuPartition(1, "/application");
   EXPECT_EQ(-EINVAL, error);
@@ -73,6 +107,10 @@
   // Test setting the partition to one that doesn't exist.
   error = dvrSetCpuPartition(0, "/foobar");
   EXPECT_EQ(-ENOENT, error);
+
+  // Set the test back to the root partition.
+  error = dvrSetCpuPartition(0, "/");
+  EXPECT_EQ(0, error);
 }
 
 TEST(PerformanceTest, SetSchedulerClass) {
@@ -96,8 +134,6 @@
   EXPECT_EQ(-EINVAL, error);
 }
 
-// This API mirrors SetSchedulerClass for now. Replace with with a more specific
-// test once the policy API is fully implemented.
 TEST(PerformanceTest, SetSchedulerPolicy) {
   int error;
 
@@ -115,6 +151,50 @@
 
   error = dvrSetSchedulerPolicy(0, "foobar");
   EXPECT_EQ(-EINVAL, error);
+
+  // Set the test back to the root partition.
+  error = dvrSetCpuPartition(0, "/");
+  EXPECT_EQ(0, error);
+
+  const std::string original_cpuset = GetTaskCpuSet(gettid());
+  EXPECT_EQ("/", original_cpuset);
+
+  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+  EXPECT_EQ(0, error);
+  EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
+
+  const std::string new_cpuset = GetTaskCpuSet(gettid());
+  EXPECT_NE(original_cpuset, new_cpuset);
+
+  // The cpuset for the thread group is now new_cpuset. Scheduler profiles that
+  // do not specify a cpuset should not change the cpuset of a thread, except to
+  // restore it to the thread group cpuset.
+  std::string thread_original_cpuset;
+  std::string thread_new_cpuset;
+  std::string thread_final_cpuset;
+
+  std::thread thread{
+      [&thread_original_cpuset, &thread_new_cpuset, &thread_final_cpuset]() {
+        thread_original_cpuset = GetTaskCpuSet(gettid());
+
+        int error = dvrSetSchedulerPolicy(0, "vr:app:render");
+        EXPECT_EQ(0, error);
+
+        thread_new_cpuset = GetTaskCpuSet(gettid());
+
+        error = dvrSetSchedulerPolicy(0, "normal");
+        EXPECT_EQ(0, error);
+
+        thread_final_cpuset = GetTaskCpuSet(gettid());
+      }};
+  thread.join();
+
+  EXPECT_EQ(new_cpuset, thread_original_cpuset);
+  EXPECT_NE(new_cpuset, thread_new_cpuset);
+  EXPECT_EQ(new_cpuset, thread_final_cpuset);
+
+  error = dvrSetCpuPartition(0, original_cpuset.c_str());
+  EXPECT_EQ(0, error);
 }
 
 TEST(PerformanceTest, SchedulerClassResetOnFork) {
@@ -424,11 +504,11 @@
     error = dvrSetSchedulerPolicy(0, "audio:high");
     EXPECT_EQ(-EINVAL, error);
     error = dvrSetSchedulerPolicy(0, "graphics");
-    EXPECT_EQ(0, error);
+    EXPECT_EQ(-EINVAL, error);
     error = dvrSetSchedulerPolicy(0, "graphics:low");
-    EXPECT_EQ(0, error);
+    EXPECT_EQ(-EINVAL, error);
     error = dvrSetSchedulerPolicy(0, "graphics:high");
-    EXPECT_EQ(0, error);
+    EXPECT_EQ(-EINVAL, error);
     error = dvrSetSchedulerPolicy(0, "sensors");
     EXPECT_EQ(-EINVAL, error);
     error = dvrSetSchedulerPolicy(0, "sensors:low");
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index 1175a7b..c2f078e 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -48,15 +48,18 @@
       thread_count_(0),
       cpus_allowed_mask_(0) {
   task_fd_ = OpenTaskDirectory(task_id_);
-  ALOGE_IF(task_fd_.get() < 0,
+  const int error = errno;
+  ALOGE_IF(task_fd_.get() < 0 && error != EACCES,
            "Task::Task: Failed to open task directory for task_id=%d: %s",
-           task_id, strerror(errno));
+           task_id, strerror(error));
 
-  ReadStatusFields();
-
-  ALOGD_IF(TRACE, "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
-           task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
-           cpus_allowed_mask_);
+  if (IsValid()) {
+    ReadStatusFields();
+    ALOGD_IF(TRACE,
+             "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
+             task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
+             cpus_allowed_mask_);
+  }
 }
 
 base::unique_fd Task::OpenTaskFile(const std::string& name) const {
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 91c270e..6107088 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -25,8 +25,22 @@
 
 cc_library_headers {
     name: "vulkan_headers",
-    export_include_dirs: ["include"],
     vendor_available: true,
+    header_libs: [
+        "libcutils_headers",
+        "libhardware_headers",
+    ],
+    export_header_lib_headers: [
+        "libcutils_headers",
+        "libhardware_headers",
+    ],
+    export_include_dirs: ["include"],
+}
+
+cc_library_headers {
+    name: "vulkan_headers_ndk",
+    export_include_dirs: ["include"],
+    sdk_version: "24",
 }
 
 subdirs = [
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a346c0a..665a32b 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -640,11 +640,9 @@
         instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
 
     const VkSurfaceFormatKHR kWideColorFormats[] = {
-        {VK_FORMAT_R16G16B16A16_SFLOAT,
-         VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
-        {VK_FORMAT_R16G16B16A16_SFLOAT,
-         VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
-        {VK_FORMAT_A2R10G10B10_UNORM_PACK32,
+        {VK_FORMAT_R8G8B8A8_UNORM,
+         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
+        {VK_FORMAT_R8G8B8A8_SRGB,
          VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
     };
     const uint32_t kNumWideColorFormats =
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 6714779..a3da651 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -19,12 +19,12 @@
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <algorithm>
 #include <array>
 
 #include <log/log.h>
-#include <utils/Errors.h>
 
 #include "null_driver_gen.h"