Merge "Implement Parcelling functions for InputWindowInfo"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2d780f5..cd0fbd4 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,15 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+# Only turn on clang-format check for the following subfolders.
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+               libs/gui/
+               libs/ui/
+               libs/vr/
+               services/surfaceflinger/
+               services/vr/
+
 [Hook Scripts]
 owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
 installd_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/installd/"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index d294d1e..17bb7c3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1376,6 +1376,54 @@
     printf("========================================================\n");
 }
 
+/* Dumps state for the default case. Returns true if everything went fine. */
+static bool DumpstateDefault() {
+    // Dumps systrace right away, otherwise it will be filled with unnecessary events.
+    // First try to dump anrd trace if the daemon is running. Otherwise, dump
+    // the raw trace.
+    if (!dump_anrd_trace()) {
+        dump_systrace();
+    }
+
+    // Invoking the following dumpsys calls before dump_traces() to try and
+    // keep the system stats as close to its initial state as possible.
+    RunDumpsysCritical();
+
+    /* collect stack traces from Dalvik and native processes (needs root) */
+    dump_traces_path = dump_traces();
+
+    /* Run some operations that require root. */
+    ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
+    ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+
+    ds.AddDir(RECOVERY_DIR, true);
+    ds.AddDir(RECOVERY_DATA_DIR, true);
+    ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
+    ds.AddDir(LOGPERSIST_DATA_DIR, false);
+    if (!PropertiesHelper::IsUserBuild()) {
+        ds.AddDir(PROFILE_DATA_DIR_CUR, true);
+        ds.AddDir(PROFILE_DATA_DIR_REF, true);
+    }
+    add_mountinfo();
+    DumpIpTablesAsRoot();
+
+    // Capture any IPSec policies in play.  No keys are exposed here.
+    RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
+
+    // Run ss as root so we can see socket marks.
+    RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
+
+    // Run iotop as root to show top 100 IO threads
+    RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
+
+    if (!DropRootUser()) {
+        return false;
+    }
+
+    dumpstate();
+    return true;
+}
+
 // This method collects common dumpsys for telephony and wifi
 static void DumpstateRadioCommon() {
     DumpIpTablesAsRoot();
@@ -1716,6 +1764,178 @@
     // clang-format on
 }
 
+/*
+ * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
+ * if we are writing zip files and adds the version file.
+ */
+static void PrepareToWriteToFile() {
+    const Dumpstate::DumpOptions& options = ds.options_;
+    ds.bugreport_dir_ = dirname(options.use_outfile.c_str());
+    std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
+    std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
+    ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(options.use_outfile.c_str()),
+                                                device_name.c_str(), build_id.c_str());
+    if (options.do_add_date) {
+        char date[80];
+        strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
+        ds.name_ = date;
+    } else {
+        ds.name_ = "undated";
+    }
+
+    if (options.telephony_only) {
+        ds.base_name_ += "-telephony";
+    } else if (options.wifi_only) {
+        ds.base_name_ += "-wifi";
+    }
+
+    if (options.do_fb) {
+        ds.screenshot_path_ = ds.GetPath(".png");
+    }
+    ds.tmp_path_ = ds.GetPath(".tmp");
+    ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
+
+    MYLOGD(
+        "Bugreport dir: %s\n"
+        "Base name: %s\n"
+        "Suffix: %s\n"
+        "Log path: %s\n"
+        "Temporary path: %s\n"
+        "Screenshot path: %s\n",
+        ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
+        ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
+
+    if (options.do_zip_file) {
+        ds.path_ = ds.GetPath(".zip");
+        MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
+        create_parent_dirs(ds.path_.c_str());
+        ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
+        if (ds.zip_file == nullptr) {
+            MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
+        } else {
+            ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
+        }
+        ds.AddTextZipEntry("version.txt", ds.version_);
+    }
+}
+
+/*
+ * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
+ * printing zipped file status, etc.
+ */
+static void FinalizeFile() {
+    const Dumpstate::DumpOptions& options = ds.options_;
+    /* check if user changed the suffix using system properties */
+    std::string name =
+        android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
+    bool change_suffix = false;
+    if (!name.empty()) {
+        /* must whitelist which characters are allowed, otherwise it could cross directories */
+        std::regex valid_regex("^[-_a-zA-Z0-9]+$");
+        if (std::regex_match(name.c_str(), valid_regex)) {
+            change_suffix = true;
+        } else {
+            MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
+        }
+    }
+    if (change_suffix) {
+        MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
+        ds.name_ = name;
+        if (!ds.screenshot_path_.empty()) {
+            std::string new_screenshot_path = ds.GetPath(".png");
+            if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
+                MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
+                       new_screenshot_path.c_str(), strerror(errno));
+            } else {
+                ds.screenshot_path_ = new_screenshot_path;
+            }
+        }
+    }
+
+    bool do_text_file = true;
+    if (options.do_zip_file) {
+        if (!ds.FinishZipFile()) {
+            MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
+            do_text_file = true;
+        } else {
+            do_text_file = false;
+            // Since zip file is already created, it needs to be renamed.
+            std::string new_path = ds.GetPath(".zip");
+            if (ds.path_ != new_path) {
+                MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
+                if (rename(ds.path_.c_str(), new_path.c_str())) {
+                    MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
+                           strerror(errno));
+                } else {
+                    ds.path_ = new_path;
+                }
+            }
+        }
+    }
+    if (do_text_file) {
+        ds.path_ = ds.GetPath(".txt");
+        MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
+        if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
+            MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
+            ds.path_.clear();
+        }
+    }
+    if (options.use_control_socket) {
+        if (do_text_file) {
+            dprintf(ds.control_socket_fd_,
+                    "FAIL:could not create zip file, check %s "
+                    "for more details\n",
+                    ds.log_path_.c_str());
+        } else {
+            dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
+        }
+    }
+}
+
+/* Broadcasts that we are done with the bugreport */
+static void SendBugreportFinishedBroadcast() {
+    const Dumpstate::DumpOptions& options = ds.options_;
+    if (!ds.path_.empty()) {
+        MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
+        // clang-format off
+
+        std::vector<std::string> am_args = {
+             "--receiver-permission", "android.permission.DUMP",
+             "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
+             "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
+             "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
+             "--es", "android.intent.extra.BUGREPORT", ds.path_,
+             "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
+        };
+        // clang-format on
+        if (options.do_fb) {
+            am_args.push_back("--es");
+            am_args.push_back("android.intent.extra.SCREENSHOT");
+            am_args.push_back(ds.screenshot_path_);
+        }
+        if (!ds.notification_title.empty()) {
+            am_args.push_back("--es");
+            am_args.push_back("android.intent.extra.TITLE");
+            am_args.push_back(ds.notification_title);
+            if (!ds.notification_description.empty()) {
+                am_args.push_back("--es");
+                am_args.push_back("android.intent.extra.DESCRIPTION");
+                am_args.push_back(ds.notification_description);
+            }
+        }
+        if (options.is_remote_mode) {
+            am_args.push_back("--es");
+            am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
+            am_args.push_back(SHA256_file_hash(ds.path_));
+            SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
+        } else {
+            SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
+        }
+    } else {
+        MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
+    }
+}
+
 int Dumpstate::ParseCommandlineOptions(int argc, char* argv[]) {
     int ret = -1;  // success
     int c;
@@ -1864,8 +2084,7 @@
         exit(1);
     }
 
-    // TODO: make const reference, but first avoid setting do_zip_file below.
-    Dumpstate::DumpOptions& options = ds.options_;
+    const Dumpstate::DumpOptions& options = ds.options_;
     if (options.show_header_only) {
         ds.PrintHeader();
         exit(0);
@@ -1922,60 +2141,11 @@
     }
 
     if (is_redirecting) {
-        ds.bugreport_dir_ = dirname(options.use_outfile.c_str());
-        std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
-        std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
-        ds.base_name_ =
-            android::base::StringPrintf("%s-%s-%s", basename(options.use_outfile.c_str()),
-                                        device_name.c_str(), build_id.c_str());
-        if (options.do_add_date) {
-            char date[80];
-            strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
-            ds.name_ = date;
-        } else {
-            ds.name_ = "undated";
-        }
-
-        if (options.telephony_only) {
-            ds.base_name_ += "-telephony";
-        } else if (options.wifi_only) {
-            ds.base_name_ += "-wifi";
-        }
-
-        if (options.do_fb) {
-            ds.screenshot_path_ = ds.GetPath(".png");
-        }
-        ds.tmp_path_ = ds.GetPath(".tmp");
-        ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
-
-        MYLOGD(
-            "Bugreport dir: %s\n"
-            "Base name: %s\n"
-            "Suffix: %s\n"
-            "Log path: %s\n"
-            "Temporary path: %s\n"
-            "Screenshot path: %s\n",
-            ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(),
-            ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
-
-        if (options.do_zip_file) {
-            ds.path_ = ds.GetPath(".zip");
-            MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
-            create_parent_dirs(ds.path_.c_str());
-            ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
-            if (ds.zip_file == nullptr) {
-                MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
-                options.do_zip_file = false;
-            } else {
-                ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
-            }
-            ds.AddTextZipEntry("version.txt", ds.version_);
-        }
+        PrepareToWriteToFile();
 
         if (ds.update_progress_) {
             if (options.do_broadcast) {
                 // clang-format off
-
                 std::vector<std::string> am_args = {
                      "--receiver-permission", "android.permission.DUMP",
                      "--es", "android.intent.extra.NAME", ds.name_,
@@ -2013,7 +2183,7 @@
         }
     }
 
-    if (options.do_zip_file) {
+    if (options.do_zip_file && ds.zip_file != nullptr) {
         if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
                    strerror(errno));
@@ -2054,51 +2224,11 @@
     } else if (options.wifi_only) {
         DumpstateWifiOnly();
     } else {
-        // Dumps systrace right away, otherwise it will be filled with unnecessary events.
-        // First try to dump anrd trace if the daemon is running. Otherwise, dump
-        // the raw trace.
-        if (!dump_anrd_trace()) {
-            dump_systrace();
-        }
-
-        // Invoking the following dumpsys calls before dump_traces() to try and
-        // keep the system stats as close to its initial state as possible.
-        RunDumpsysCritical();
-
-        /* collect stack traces from Dalvik and native processes (needs root) */
-        dump_traces_path = dump_traces();
-
-        /* Run some operations that require root. */
-        ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
-        ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
-
-        ds.AddDir(RECOVERY_DIR, true);
-        ds.AddDir(RECOVERY_DATA_DIR, true);
-        ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
-        ds.AddDir(LOGPERSIST_DATA_DIR, false);
-        if (!PropertiesHelper::IsUserBuild()) {
-            ds.AddDir(PROFILE_DATA_DIR_CUR, true);
-            ds.AddDir(PROFILE_DATA_DIR_REF, true);
-        }
-        add_mountinfo();
-        DumpIpTablesAsRoot();
-
-        // Capture any IPSec policies in play.  No keys are exposed here.
-        RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
-                   CommandOptions::WithTimeout(10).Build());
-
-        // Run ss as root so we can see socket marks.
-        RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"},
-                   CommandOptions::WithTimeout(10).Build());
-
-        // Run iotop as root to show top 100 IO threads
-        RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
-
-        if (!DropRootUser()) {
+        // Dump state for the default case. This also drops root.
+        if (!DumpstateDefault()) {
+            // Something went wrong.
             return -1;
         }
-
-        dumpstate();
     }
 
     /* close output if needed */
@@ -2108,73 +2238,7 @@
 
     /* rename or zip the (now complete) .tmp file to its final location */
     if (!options.use_outfile.empty()) {
-        /* check if user changed the suffix using system properties */
-        std::string name = android::base::GetProperty(
-            android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
-        bool change_suffix = false;
-        if (!name.empty()) {
-            /* must whitelist which characters are allowed, otherwise it could cross directories */
-            std::regex valid_regex("^[-_a-zA-Z0-9]+$");
-            if (std::regex_match(name.c_str(), valid_regex)) {
-                change_suffix = true;
-            } else {
-                MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
-            }
-        }
-        if (change_suffix) {
-            MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
-            ds.name_ = name;
-            if (!ds.screenshot_path_.empty()) {
-                std::string new_screenshot_path = ds.GetPath(".png");
-                if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
-                    MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
-                           new_screenshot_path.c_str(), strerror(errno));
-                } else {
-                    ds.screenshot_path_ = new_screenshot_path;
-                }
-            }
-        }
-
-        bool do_text_file = true;
-        if (options.do_zip_file) {
-            if (!ds.FinishZipFile()) {
-                MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
-                do_text_file = true;
-            } else {
-                do_text_file = false;
-                // Since zip file is already created, it needs to be renamed.
-                std::string new_path = ds.GetPath(".zip");
-                if (ds.path_ != new_path) {
-                    MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
-                    if (rename(ds.path_.c_str(), new_path.c_str())) {
-                        MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
-                               strerror(errno));
-                    } else {
-                        ds.path_ = new_path;
-                    }
-                }
-            }
-        }
-        if (do_text_file) {
-            ds.path_ = ds.GetPath(".txt");
-            MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(),
-                   ds.tmp_path_.c_str());
-            if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
-                MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(),
-                       strerror(errno));
-                ds.path_.clear();
-            }
-        }
-        if (options.use_control_socket) {
-            if (do_text_file) {
-                dprintf(ds.control_socket_fd_,
-                        "FAIL:could not create zip file, check %s "
-                        "for more details\n",
-                        ds.log_path_.c_str());
-            } else {
-                dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
-            }
-        }
+        FinalizeFile();
     }
 
     /* vibrate a few but shortly times to let user know it's finished */
@@ -2187,46 +2251,7 @@
 
     /* tell activity manager we're done */
     if (options.do_broadcast) {
-        if (!ds.path_.empty()) {
-            MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
-            // clang-format off
-
-            std::vector<std::string> am_args = {
-                 "--receiver-permission", "android.permission.DUMP",
-                 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
-                 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
-                 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
-                 "--es", "android.intent.extra.BUGREPORT", ds.path_,
-                 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
-            };
-            // clang-format on
-            if (options.do_fb) {
-                am_args.push_back("--es");
-                am_args.push_back("android.intent.extra.SCREENSHOT");
-                am_args.push_back(ds.screenshot_path_);
-            }
-            if (!ds.notification_title.empty()) {
-                am_args.push_back("--es");
-                am_args.push_back("android.intent.extra.TITLE");
-                am_args.push_back(ds.notification_title);
-                if (!ds.notification_description.empty()) {
-                    am_args.push_back("--es");
-                    am_args.push_back("android.intent.extra.DESCRIPTION");
-                    am_args.push_back(ds.notification_description);
-                }
-            }
-            if (options.is_remote_mode) {
-                am_args.push_back("--es");
-                am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
-                am_args.push_back(SHA256_file_hash(ds.path_));
-                SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED",
-                              am_args);
-            } else {
-                SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
-            }
-        } else {
-            MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
-        }
+        SendBugreportFinishedBroadcast();
     }
 
     MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
diff --git a/cmds/installd/MatchExtensionGen.h b/cmds/installd/MatchExtensionGen.h
index fded6b7..35c3889 100644
--- a/cmds/installd/MatchExtensionGen.h
+++ b/cmds/installd/MatchExtensionGen.h
@@ -31,6 +31,7 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'p': case 'P':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
@@ -41,10 +42,15 @@
                         switch (ext[5]) {
                         case '\0': return AID_MEDIA_VIDEO;
                         }
+                        break;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'a': case 'A':
         switch (ext[1]) {
         case 'a': case 'A':
@@ -53,7 +59,9 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'i': case 'I':
             switch (ext[2]) {
             case 'f': case 'F':
@@ -63,56 +71,73 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_AUDIO;
                     }
+                    break;
                 case 'f': case 'F':
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_AUDIO;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'm': case 'M':
             switch (ext[2]) {
             case 'r': case 'R':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 't': case 'T':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             case 'w': case 'W':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 's': case 'S':
             switch (ext[2]) {
             case 'f': case 'F':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'v': case 'V':
             switch (ext[2]) {
             case 'i': case 'I':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'w': case 'W':
             switch (ext[2]) {
             case 'b': case 'B':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'b': case 'B':
         switch (ext[1]) {
         case 'm': case 'M':
@@ -121,8 +146,11 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'c': case 'C':
         switch (ext[1]) {
         case 'r': case 'R':
@@ -131,8 +159,11 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'd': case 'D':
         switch (ext[1]) {
         case 'i': case 'I':
@@ -141,23 +172,30 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'l': case 'L':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
             }
+            break;
         case 'n': case 'N':
             switch (ext[2]) {
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'v': case 'V':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
             }
+            break;
         }
+        break;
     case 'f': case 'F':
         switch (ext[1]) {
         case 'l': case 'L':
@@ -168,13 +206,18 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_AUDIO;
                     }
+                    break;
                 }
+                break;
             case 'i': case 'I':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'g': case 'G':
         switch (ext[1]) {
         case 'i': case 'I':
@@ -183,15 +226,20 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 's': case 'S':
             switch (ext[2]) {
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'j': case 'J':
         switch (ext[1]) {
         case 'n': case 'N':
@@ -200,7 +248,9 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'p': case 'P':
             switch (ext[2]) {
             case 'e': case 'E':
@@ -210,13 +260,18 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'l': case 'L':
         switch (ext[1]) {
         case 's': case 'S':
@@ -225,12 +280,16 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'm': case 'M':
         switch (ext[1]) {
         case '3':
@@ -239,36 +298,46 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case '4':
             switch (ext[2]) {
             case 'a': case 'A':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'v': case 'V':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'k': case 'K':
             switch (ext[2]) {
             case 'a': case 'A':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'v': case 'V':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'n': case 'N':
             switch (ext[2]) {
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'o': case 'O':
             switch (ext[2]) {
             case 'v': case 'V':
@@ -280,23 +349,30 @@
                         switch (ext[5]) {
                         case '\0': return AID_MEDIA_VIDEO;
                         }
+                        break;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'p': case 'P':
             switch (ext[2]) {
             case '2':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case '3':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case '4':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'e': case 'E':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
@@ -307,8 +383,11 @@
                         switch (ext[5]) {
                         case '\0': return AID_MEDIA_AUDIO;
                         }
+                        break;
                     }
+                    break;
                 }
+                break;
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
@@ -316,16 +395,22 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_AUDIO;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'x': case 'X':
             switch (ext[2]) {
             case 'u': case 'U':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'n': case 'N':
         switch (ext[1]) {
         case 'e': case 'E':
@@ -334,15 +419,20 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 'w': case 'W':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'o': case 'O':
         switch (ext[1]) {
         case 'g': case 'G':
@@ -351,19 +441,25 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 'f': case 'F':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'p': case 'P':
         switch (ext[1]) {
         case 'b': case 'B':
@@ -372,68 +468,88 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'c': case 'C':
             switch (ext[2]) {
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'e': case 'E':
             switch (ext[2]) {
             case 'f': case 'F':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'g': case 'G':
             switch (ext[2]) {
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'l': case 'L':
             switch (ext[2]) {
             case 's': case 'S':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'n': case 'N':
             switch (ext[2]) {
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'p': case 'P':
             switch (ext[2]) {
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 's': case 'S':
             switch (ext[2]) {
             case 'd': case 'D':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'q': case 'Q':
         switch (ext[1]) {
         case 't': case 'T':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
             }
+            break;
         }
+        break;
     case 'r': case 'R':
         switch (ext[1]) {
         case 'a': case 'A':
@@ -443,30 +559,39 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 's': case 'S':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'g': case 'G':
             switch (ext[2]) {
             case 'b': case 'B':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'm': case 'M':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_AUDIO;
             }
+            break;
         case 'w': case 'W':
             switch (ext[2]) {
             case '2':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 's': case 'S':
         switch (ext[1]) {
         case 'd': case 'D':
@@ -475,21 +600,27 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'n': case 'N':
             switch (ext[2]) {
             case 'd': case 'D':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 'w': case 'W':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'v': case 'V':
             switch (ext[2]) {
             case 'g': case 'G':
@@ -499,9 +630,13 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 't': case 'T':
         switch (ext[1]) {
         case 'i': case 'I':
@@ -513,13 +648,18 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 's': case 'S':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
             }
+            break;
         }
+        break;
     case 'v': case 'V':
         switch (ext[1]) {
         case 'o': case 'O':
@@ -528,8 +668,11 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'w': case 'W':
         switch (ext[1]) {
         case 'a': case 'A':
@@ -538,11 +681,14 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'b': case 'B':
             switch (ext[2]) {
             case 'm': case 'M':
@@ -551,8 +697,11 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'e': case 'E':
             switch (ext[2]) {
             case 'b': case 'B':
@@ -561,12 +710,16 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_VIDEO;
                     }
+                    break;
                 case 'p': case 'P':
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'm': case 'M':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
@@ -574,30 +727,39 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'v': case 'V':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 'f': case 'F':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'v': case 'V':
             switch (ext[2]) {
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'x': case 'X':
         switch (ext[1]) {
         case 'b': case 'B':
@@ -606,22 +768,29 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'p': case 'P':
             switch (ext[2]) {
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'w': case 'W':
             switch (ext[2]) {
             case 'd': case 'D':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     }
 
     return 0;
diff --git a/cmds/installd/matchgen.py b/cmds/installd/matchgen.py
index 131487d..42ce82b 100644
--- a/cmds/installd/matchgen.py
+++ b/cmds/installd/matchgen.py
@@ -84,6 +84,8 @@
                 print "%scase '%s':" % (prefix, k)
             dump(target[k], index + 1)
     print "%s}" % (prefix)
+    if index > 0:
+        print "%sbreak;" % (prefix)
 
 dump(trie, 0)
 
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index bcdd03e..ad7a5ae 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
+#include "MatchExtensionGen.h"
 #include "globals.h"
 #include "utils.h"
 
@@ -529,5 +530,19 @@
     EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file"));
 }
 
+TEST_F(UtilsTest, MatchExtension_Valid) {
+    EXPECT_EQ(AID_MEDIA_VIDEO, MatchExtension("mpg"));
+    EXPECT_EQ(AID_MEDIA_VIDEO, MatchExtension("mpeg"));
+    EXPECT_EQ(AID_MEDIA_VIDEO, MatchExtension("mPeG"));
+    EXPECT_EQ(AID_MEDIA_VIDEO, MatchExtension("MPEG"));
+}
+
+TEST_F(UtilsTest, MatchExtension_Invalid) {
+    EXPECT_EQ(0, MatchExtension("log"));
+    EXPECT_EQ(0, MatchExtension("3amp"));
+    EXPECT_EQ(0, MatchExtension("fpe"));
+    EXPECT_EQ(0, MatchExtension("docx"));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 0f336dd..0de3bb7 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -17,11 +17,37 @@
 #ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
 #define _LIBINPUT_DISPLAY_VIEWPORT_H
 
+#include <android-base/stringprintf.h>
 #include <ui/DisplayInfo.h>
 #include <input/Input.h>
 
+using android::base::StringPrintf;
+
 namespace android {
 
+/**
+ * Describes the different type of viewports supported by input flinger.
+ * Keep in sync with values in InputManagerService.java.
+ */
+enum class ViewportType : int32_t {
+    VIEWPORT_INTERNAL = 1,
+    VIEWPORT_EXTERNAL = 2,
+    VIEWPORT_VIRTUAL = 3,
+};
+
+static const char* viewportTypeToString(ViewportType type) {
+    switch(type) {
+        case ViewportType::VIEWPORT_INTERNAL:
+            return "INTERNAL";
+        case ViewportType::VIEWPORT_EXTERNAL:
+            return "EXTERNAL";
+        case ViewportType::VIEWPORT_VIRTUAL:
+            return "VIRTUAL";
+        default:
+            return "UNKNOWN";
+    }
+}
+
 /*
  * Describes how coordinates are mapped on a physical display.
  * See com.android.server.display.DisplayViewport.
@@ -40,12 +66,13 @@
     int32_t deviceWidth;
     int32_t deviceHeight;
     std::string uniqueId;
+    ViewportType type;
 
     DisplayViewport() :
             displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
             logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
             physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
-            deviceWidth(0), deviceHeight(0), uniqueId() {
+            deviceWidth(0), deviceHeight(0), uniqueId(), type(ViewportType::VIEWPORT_INTERNAL) {
     }
 
     bool operator==(const DisplayViewport& other) const {
@@ -61,7 +88,8 @@
                 && physicalBottom == other.physicalBottom
                 && deviceWidth == other.deviceWidth
                 && deviceHeight == other.deviceHeight
-                && uniqueId == other.uniqueId;
+                && uniqueId == other.uniqueId
+                && type == other.type;
     }
 
     bool operator!=(const DisplayViewport& other) const {
@@ -86,17 +114,22 @@
         deviceWidth = width;
         deviceHeight = height;
         uniqueId.clear();
+        type = ViewportType::VIEWPORT_INTERNAL;
     }
-};
 
-/**
- * Describes the different type of viewports supported by input flinger.
- * Keep in sync with values in InputManagerService.java.
- */
-enum class ViewportType : int32_t {
-    VIEWPORT_INTERNAL = 1,
-    VIEWPORT_EXTERNAL = 2,
-    VIEWPORT_VIRTUAL = 3,
+    std::string toString() const {
+        return StringPrintf("Viewport %s: displayId=%d, orientation=%d, "
+            "logicalFrame=[%d, %d, %d, %d], "
+            "physicalFrame=[%d, %d, %d, %d], "
+            "deviceSize=[%d, %d]",
+            viewportTypeToString(type),
+            displayId, orientation,
+            logicalLeft, logicalTop,
+            logicalRight, logicalBottom,
+            physicalLeft, physicalTop,
+            physicalRight, physicalBottom,
+            deviceWidth, deviceHeight);
+    }
 };
 
 } // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b2a304a..aedf6b0 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -120,6 +120,7 @@
         "liblog",
         "libcutils",
         "libutils",
+        "libbinderthreadstate",
     ],
 
     header_libs: [
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index b2217b5..f052bcb 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "IPCThreadState"
 
 #include <binder/IPCThreadState.h>
+#include <binderthreadstate/IPCThreadStateBase.h>
 
 #include <binder/Binder.h>
 #include <binder/BpBinder.h>
@@ -742,6 +743,7 @@
     clearCaller();
     mIn.setDataCapacity(256);
     mOut.setDataCapacity(256);
+    mIPCThreadStateBase = IPCThreadStateBase::self();
 }
 
 IPCThreadState::~IPCThreadState()
@@ -1082,6 +1084,9 @@
                 "Not enough command data for brTRANSACTION");
             if (result != NO_ERROR) break;
 
+            //Record the fact that we're in a binder call.
+            mIPCThreadStateBase->pushCurrentState(
+                IPCThreadStateBase::CallState::BINDER);
             Parcel buffer;
             buffer.ipcSetDataReference(
                 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
@@ -1129,6 +1134,7 @@
                 error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
             }
 
+            mIPCThreadStateBase->popCurrentState();
             //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
             //     mCallingPid, origPid, origUid);
 
@@ -1192,6 +1198,10 @@
     return result;
 }
 
+bool IPCThreadState::isServingCall() const {
+    return mIPCThreadStateBase->getCurrentBinderCallState() == IPCThreadStateBase::CallState::BINDER;
+}
+
 void IPCThreadState::threadDestructor(void *st)
 {
         IPCThreadState* const self = static_cast<IPCThreadState*>(st);
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index dce3f38..40b51ad 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -29,6 +29,8 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+class IPCThreadStateBase;
+
 class IPCThreadState
 {
 public:
@@ -89,6 +91,33 @@
             // the maximum number of binder threads threads allowed for this process.
             void                blockUntilThreadAvailable();
 
+
+            // Is this thread currently serving a binder call. This method
+            // returns true if while traversing backwards from the function call
+            // stack for this thread, we encounter a function serving a binder
+            // call before encountering a hwbinder call / hitting the end of the
+            // call stack.
+            // Eg: If thread T1 went through the following call pattern
+            //     1) T1 receives and executes hwbinder call H1.
+            //     2) While handling H1, T1 makes binder call B1.
+            //     3) The handler of B1, calls into T1 with a callback B2.
+            // If isServingCall() is called during H1 before 3), this method
+            // will return false, else true.
+            //
+            //  ----
+            // | B2 | ---> While callback B2 is being handled, during 3).
+            //  ----
+            // | H1 | ---> While H1 is being handled.
+            //  ----
+            // Fig: Thread Call stack while handling B2
+            //
+            // This is since after 3), while traversing the thread call stack,
+            // we hit a binder call before a hwbinder call / end of stack. This
+            // method may be typically used to determine whether to use
+            // hardware::IPCThreadState methods or IPCThreadState methods to
+            // infer information about thread state.
+            bool                isServingCall() const;
+
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
@@ -128,6 +157,7 @@
             uid_t               mCallingUid;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
+            IPCThreadStateBase  *mIPCThreadStateBase;
 };
 
 }; // namespace android
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
new file mode 100644
index 0000000..7106cbb
--- /dev/null
+++ b/libs/binderthreadstate/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "libbinderthreadstate",
+    recovery_available: true,
+    vendor_available: false,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "IPCThreadStateBase.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libutils",
+    ],
+
+    export_include_dirs: ["include"],
+
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/libs/binderthreadstate/IPCThreadStateBase.cpp b/libs/binderthreadstate/IPCThreadStateBase.cpp
new file mode 100644
index 0000000..fede151
--- /dev/null
+++ b/libs/binderthreadstate/IPCThreadStateBase.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IPCThreadStateBase"
+
+#include <binderthreadstate/IPCThreadStateBase.h>
+#include <android-base/macros.h>
+
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+
+namespace android {
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
+IPCThreadStateBase::IPCThreadStateBase() {
+    pthread_setspecific(gTLS, this);
+}
+
+IPCThreadStateBase* IPCThreadStateBase::self()
+{
+    if (gHaveTLS) {
+restart:
+        const pthread_key_t k = gTLS;
+        IPCThreadStateBase* st = (IPCThreadStateBase*)pthread_getspecific(k);
+        if (st) return st;
+        return new IPCThreadStateBase;
+    }
+
+    pthread_mutex_lock(&gTLSMutex);
+    if (!gHaveTLS) {
+        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
+        if (key_create_value != 0) {
+            pthread_mutex_unlock(&gTLSMutex);
+            ALOGW("IPCThreadStateBase::self() unable to create TLS key, expect a crash: %s\n",
+                    strerror(key_create_value));
+            return nullptr;
+        }
+        gHaveTLS = true;
+    }
+    pthread_mutex_unlock(&gTLSMutex);
+    goto restart;
+}
+
+void IPCThreadStateBase::pushCurrentState(CallState callState) {
+    mCallStateStack.emplace(callState);
+}
+
+IPCThreadStateBase::CallState IPCThreadStateBase::popCurrentState() {
+    ALOG_ASSERT(mCallStateStack.size > 0);
+    CallState val = mCallStateStack.top();
+    mCallStateStack.pop();
+    return val;
+}
+
+IPCThreadStateBase::CallState IPCThreadStateBase::getCurrentBinderCallState() {
+    if (mCallStateStack.size() > 0) {
+        return mCallStateStack.top();
+    }
+    return CallState::NONE;
+}
+
+void IPCThreadStateBase::threadDestructor(void *st)
+{
+    IPCThreadStateBase* const self = static_cast<IPCThreadStateBase*>(st);
+    if (self) {
+        delete self;
+    }
+}
+
+}; // namespace android
diff --git a/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
new file mode 100644
index 0000000..6fdcc84
--- /dev/null
+++ b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
+#define BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
+
+#include <stack>
+namespace android {
+
+class IPCThreadStateBase {
+public:
+    enum CallState {
+        HWBINDER,
+        BINDER,
+        NONE,
+    };
+    static IPCThreadStateBase* self();
+    void pushCurrentState(CallState callState);
+    CallState popCurrentState();
+    CallState getCurrentBinderCallState();
+
+private:
+    IPCThreadStateBase();
+    static void threadDestructor(void *st);
+
+    std::stack<CallState> mCallStateStack;
+};
+
+}; // namespace android
+
+#endif // BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index a8ef7a0..2a7d76e 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -56,6 +56,35 @@
     mDriverPath = path;
 }
 
+void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
+                               const std::string appPref, bool developerOptIn) {
+    if (!mAnglePath.empty()) {
+        ALOGV("ignoring attempt to change ANGLE path from '%s' to '%s'", mAnglePath.c_str(),
+              path.c_str());
+    } else {
+        ALOGV("setting ANGLE path to '%s'", path.c_str());
+        mAnglePath = path;
+    }
+
+    if (!mAngleAppName.empty()) {
+        ALOGV("ignoring attempt to change ANGLE app name from '%s' to '%s'", mAngleAppName.c_str(),
+              appName.c_str());
+    } else {
+        ALOGV("setting ANGLE app name to '%s'", appName.c_str());
+        mAngleAppName = appName;
+    }
+
+    if (!mAngleAppPref.empty()) {
+        ALOGV("ignoring attempt to change ANGLE application opt-in from '%s' to '%s'",
+              mAngleAppPref.c_str(), appPref.c_str());
+    } else {
+        ALOGV("setting ANGLE application opt-in to '%s'", appPref.c_str());
+        mAngleAppPref = appPref;
+    }
+
+    mAngleDeveloperOptIn = developerOptIn;
+}
+
 void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
     if (mLayerPaths.empty()) {
         mLayerPaths = layerPaths;
@@ -70,6 +99,20 @@
     return mAppNamespace;
 }
 
+const char* GraphicsEnv::getAngleAppName() {
+    if (mAngleAppName.empty()) return nullptr;
+    return mAngleAppName.c_str();
+}
+
+bool GraphicsEnv::getAngleDeveloperOptIn() {
+    return mAngleDeveloperOptIn;
+}
+
+const char* GraphicsEnv::getAngleAppPref() {
+    if (mAngleAppPref.empty()) return nullptr;
+    return mAngleAppPref.c_str();
+}
+
 const std::string GraphicsEnv::getLayerPaths(){
     return mLayerPaths;
 }
@@ -102,8 +145,40 @@
     return mDriverNamespace;
 }
 
+android_namespace_t* GraphicsEnv::getAngleNamespace() {
+    static std::once_flag once;
+    std::call_once(once, [this]() {
+        if (mAnglePath.empty()) return;
+
+        mAngleNamespace = android_create_namespace("ANGLE",
+                                                   nullptr,            // ld_library_path
+                                                   mAnglePath.c_str(), // default_library_path
+                                                   ANDROID_NAMESPACE_TYPE_SHARED |
+                                                           ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                                   nullptr, // permitted_when_isolated_path
+                                                   nullptr);
+        if (!mAngleNamespace) ALOGD("Could not create ANGLE namespace from default");
+    });
+
+    return mAngleNamespace;
+}
+
 } // namespace android
 
-extern "C" android_namespace_t* android_getDriverNamespace() {
+extern "C" {
+android_namespace_t* android_getDriverNamespace() {
     return android::GraphicsEnv::getInstance().getDriverNamespace();
 }
+android_namespace_t* android_getAngleNamespace() {
+    return android::GraphicsEnv::getInstance().getAngleNamespace();
+}
+const char* android_getAngleAppName() {
+    return android::GraphicsEnv::getInstance().getAngleAppName();
+}
+bool android_getAngleDeveloperOptIn() {
+    return android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
+}
+const char* android_getAngleAppPref() {
+    return android::GraphicsEnv::getInstance().getAngleAppPref();
+}
+}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 17e8f6b..00e8fc0 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -37,8 +37,21 @@
     void setDriverPath(const std::string path);
     android_namespace_t* getDriverNamespace();
 
+    // Set a search path for loading ANGLE libraries. The path is a list of
+    // directories separated by ':'. A directory can be contained in a zip file
+    // (libraries must be stored uncompressed and page aligned); such elements
+    // in the search path must have a '!' after the zip filename, e.g.
+    //     /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
+    void setAngleInfo(const std::string path, const std::string appName, const std::string appPref,
+                      bool devOptIn);
+    android_namespace_t* getAngleNamespace();
+    const char* getAngleAppName();
+    const char* getAngleAppPref();
+    bool getAngleDeveloperOptIn();
+
     void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
     NativeLoaderNamespace* getAppNamespace();
+
     const std::string getLayerPaths();
 
     void setDebugLayers(const std::string layers);
@@ -47,9 +60,14 @@
 private:
     GraphicsEnv() = default;
     std::string mDriverPath;
+    std::string mAnglePath;
+    std::string mAngleAppName;
+    std::string mAngleAppPref;
+    bool mAngleDeveloperOptIn;
     std::string mDebugLayers;
     std::string mLayerPaths;
     android_namespace_t* mDriverNamespace = nullptr;
+    android_namespace_t* mAngleNamespace = nullptr;
     NativeLoaderNamespace* mAppNamespace = nullptr;
 };
 
@@ -66,6 +84,12 @@
  *  - the EGLsyncKHR synchronization in BufferQueue, which is deprecated and
  *    will be removed soon.
  */
-extern "C" android_namespace_t* android_getDriverNamespace();
+extern "C" {
+android_namespace_t* android_getDriverNamespace();
+android_namespace_t* android_getAngleNamespace();
+const char* android_getAngleAppName();
+const char* android_getAngleAppPref();
+bool android_getAngleDeveloperOptIn();
+}
 
 #endif // ANDROID_UI_GRAPHICS_ENV_H
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index a379ad6..85ae433 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -621,7 +621,7 @@
 // ============================================================================
 
 FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
-        FrameEventHistoryDelta&& src) {
+        FrameEventHistoryDelta&& src) noexcept {
     mCompositorTiming = src.mCompositorTiming;
 
     if (CC_UNLIKELY(!mDeltas.empty())) {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 5a8d8db..2b0a461 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -77,6 +77,9 @@
         output.writeBool(false);
     }
 
+    memcpy(output.writeInplace(16 * sizeof(float)),
+           colorTransform.asArray(), 16 * sizeof(float));
+
     return NO_ERROR;
 }
 
@@ -130,6 +133,8 @@
         sidebandStream = NativeHandle::create(input.readNativeHandle(), true);
     }
 
+    colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
+
     return NO_ERROR;
 }
 
@@ -314,6 +319,10 @@
         what |= eSidebandStreamChanged;
         sidebandStream = other.sidebandStream;
     }
+    if (other.what & eColorTransformChanged) {
+        what |= eColorTransformChanged;
+        colorTransform = other.colorTransform;
+    }
 
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 09ea0f6..1ac9609 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -602,6 +602,18 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform(
+    const sp<SurfaceControl>& sc, const mat3& matrix, const vec3& translation) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eColorTransformChanged;
+    s->colorTransform = mat4(matrix, translation);
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index 9716be4..e06e40f 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -311,7 +311,7 @@
 
     // Movable.
     FrameEventHistoryDelta(FrameEventHistoryDelta&& src) = default;
-    FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src);
+    FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src) noexcept;
     // Not copyable.
     FrameEventHistoryDelta(const FrameEventHistoryDelta& src) = delete;
     FrameEventHistoryDelta& operator=(
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 9a9f633..e06e2b1 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -23,6 +23,7 @@
 #include <utils/Errors.h>
 
 #include <gui/IGraphicBufferProducer.h>
+#include <math/mat4.h>
 #include <math/vec3.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Rect.h>
@@ -72,6 +73,7 @@
         eSurfaceDamageRegionChanged = 0x02000000,
         eApiChanged = 0x04000000,
         eSidebandStreamChanged = 0x08000000,
+        eColorTransformChanged = 0x10000000,
     };
 
     layer_state_t()
@@ -94,7 +96,8 @@
             crop(Rect::INVALID_RECT),
             dataspace(ui::Dataspace::UNKNOWN),
             surfaceDamageRegion(),
-            api(-1) {
+            api(-1),
+            colorTransform(mat4()) {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
         hdrMetadata.validTypes = 0;
@@ -150,6 +153,7 @@
     Region surfaceDamageRegion;
     int32_t api;
     sp<NativeHandle> sidebandStream;
+    mat4 colorTransform;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 314b118..69a759f 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -269,6 +269,10 @@
 
         Transaction& destroySurface(const sp<SurfaceControl>& sc);
 
+        // Set a color transform matrix on the given layer on the built-in display.
+        Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix,
+                                       const vec3& translation);
+
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
 
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 5242a18..af97c34 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "VelocityTracker_test"
 
+#include <array>
 #include <math.h>
 
 #include <android-base/stringprintf.h>
@@ -34,29 +35,35 @@
 // here EV = expected value, tol = VELOCITY_TOLERANCE
 constexpr float VELOCITY_TOLERANCE = 0.2;
 
+// estimate coefficients must be within 0.001% of the target value
+constexpr float COEFFICIENT_TOLERANCE = 0.00001;
+
 // --- VelocityTrackerTest ---
 class VelocityTrackerTest : public testing::Test { };
 
-static void checkVelocity(float Vactual, float Vtarget) {
-    // Compare directions
-    if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) {
-        FAIL() << StringPrintf("Velocity %f does not have the same direction"
-                " as the target velocity %f", Vactual, Vtarget);
-    }
+/*
+ * Similar to EXPECT_NEAR, but ensures that the difference between the two float values
+ * is at most a certain fraction of the target value.
+ * If fraction is zero, require exact match.
+ */
+static void EXPECT_NEAR_BY_FRACTION(float actual, float target, float fraction) {
+    float tolerance = fabsf(target * fraction);
 
-    // Compare magnitudes
-    const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE));
-    const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE));
-    if (fabsf(Vactual) < Vlower) {
-        FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f",
-                Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+    if (target == 0 && fraction != 0) {
+        // If target is zero, this would force actual == target, which is too harsh.
+        // Relax this requirement a little. The value is determined empirically from the
+        // coefficients computed by the quadratic least squares algorithms.
+        tolerance = 1E-6;
     }
-    if (fabsf(Vactual) > Vupper) {
-        FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f",
-                Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
-    }
-    SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)",
-            Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+    EXPECT_NEAR(actual, target, tolerance);
+}
+
+static void checkVelocity(float Vactual, float Vtarget) {
+    EXPECT_NEAR_BY_FRACTION(Vactual, Vtarget, VELOCITY_TOLERANCE);
+}
+
+static void checkCoefficient(float actual, float target) {
+    EXPECT_NEAR_BY_FRACTION(actual, target, COEFFICIENT_TOLERANCE);
 }
 
 void failWithMessage(std::string message) {
@@ -125,6 +132,19 @@
     delete event;
 }
 
+static void computeAndCheckQuadraticEstimate(const Position* positions, size_t numSamples,
+        const std::array<float, 3>& coefficients) {
+    VelocityTracker vt("lsq2");
+    MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
+    vt.addMovement(event);
+    VelocityTracker::Estimator estimator;
+    EXPECT_TRUE(vt.getEstimator(0, &estimator));
+    for (size_t i = 0; i< coefficients.size(); i++) {
+        checkCoefficient(estimator.xCoeff[i], coefficients[i]);
+        checkCoefficient(estimator.yCoeff[i], coefficients[i]);
+    }
+}
+
 /*
  * ================== VelocityTracker tests generated manually =====================================
  */
@@ -662,5 +682,114 @@
     computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
 }
 
+/*
+ * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy
+ * getEstimator function. In particular:
+ * - inside the function, time gets converted from nanoseconds to seconds
+ *   before being used in the fit.
+ * - any values that are older than 100 ms are being discarded.
+ * - the newest time gets subtracted from all of the other times before being used in the fit.
+ * So these tests have to be designed with those limitations in mind.
+ *
+ * General approach for the tests below:
+ * We only used timestamps in milliseconds, 0 ms, 1 ms, and 2 ms, to be sure that
+ * we are well within the HORIZON range.
+ * When specifying the expected values of the coefficients, we treat the x values as if
+ * they were in ms. Then, to adjust for the time units, the coefficients get progressively
+ * multiplied by powers of 1E3.
+ * For example:
+ * data: t(ms), x
+ *        1 ms, 1
+ *        2 ms, 4
+ *        3 ms, 9
+ * The coefficients are (0, 0, 1).
+ * In the test, we would convert these coefficients to (0*(1E3)^0, 0*(1E3)^1, 1*(1E3)^2).
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constant) {
+    Position values[] = {
+        { 0000000, 1, 1 }, // 0 s
+        { 1000000, 1, 1 }, // 0.001 s
+        { 2000000, 1, 1 }, // 0.002 s
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 1
+    // -0.000, 1
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({1, 0, 0}));
+}
+
+/*
+ * Straight line y = x :: the constant and quadratic coefficients are zero.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) {
+    Position values[] = {
+        { 0000000, -2, -2 },
+        { 1000000, -1, -1 },
+        { 2000000, -0, -0 },
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, -2
+    // -0.001, -1
+    // -0.000,  0
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 1E3, 0}));
+}
+
+/*
+ * Parabola
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic) {
+    Position values[] = {
+        { 0000000, 1, 1 },
+        { 1000000, 4, 4 },
+        { 2000000, 8, 8 },
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 4
+    // -0.000, 8
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({8, 4.5E3, 0.5E6}));
+}
+
+/*
+ * Parabola
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic2) {
+    Position values[] = {
+        { 0000000, 1, 1 },
+        { 1000000, 4, 4 },
+        { 2000000, 9, 9 },
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 4
+    // -0.000, 9
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({9, 6E3, 1E6}));
+}
+
+/*
+ * Parabola :: y = x^2 :: the constant and linear coefficients are zero.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic3) {
+    Position values[] = {
+        { 0000000, 4, 4 },
+        { 1000000, 1, 1 },
+        { 2000000, 0, 0 },
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 4
+    // -0.001, 1
+    // -0.000, 0
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 0E3, 1E6}));
+}
 
 } // namespace android
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index a36911d..a5b3e89 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -24,8 +24,8 @@
 #endif
 
 HdrCapabilities::~HdrCapabilities() = default;
-HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default;
-HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default;
+HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) noexcept = default;
+HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) noexcept = default;
 
 size_t HdrCapabilities::getFlattenedSize() const {
     return  sizeof(mMaxLuminance) +
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 4e98c28..65ac26c 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -37,8 +37,8 @@
         mMinLuminance(minLuminance) {}
 
     // Make this move-constructable and move-assignable
-    HdrCapabilities(HdrCapabilities&& other);
-    HdrCapabilities& operator=(HdrCapabilities&& other);
+    HdrCapabilities(HdrCapabilities&& other) noexcept;
+    HdrCapabilities& operator=(HdrCapabilities&& other) noexcept;
 
     HdrCapabilities()
       : mSupportedHdrTypes(),
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 69b6422..93091e3 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -13,10 +13,14 @@
 // limitations under the License.
 
 sourceFiles = [
+    "buffer_hub_base.cpp",
     "buffer_hub_client.cpp",
+    "buffer_hub_metadata.cpp",
     "buffer_hub_rpc.cpp",
+    "consumer_buffer.cpp",
     "detached_buffer.cpp",
     "ion_buffer.cpp",
+    "producer_buffer.cpp",
 ]
 
 localIncludeFiles = [
@@ -66,3 +70,10 @@
     name: "buffer_hub-test",
 }
 
+cc_test {
+    srcs: ["buffer_hub_metadata-test.cpp"],
+    static_libs: ["libbufferhub"],
+    shared_libs: sharedLibraries,
+    header_libs: headerLibraries,
+    name: "buffer_hub_metadata-test",
+}
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
new file mode 100644
index 0000000..b2bcda7
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -0,0 +1,224 @@
+#include <poll.h>
+#include <sys/epoll.h>
+
+#include <pdx/default_transport/client_channel.h>
+#include <pdx/default_transport/client_channel_factory.h>
+#include <private/dvr/buffer_hub_base.h>
+
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+using android::pdx::default_transport::ClientChannel;
+using android::pdx::default_transport::ClientChannelFactory;
+
+namespace android {
+namespace dvr {
+
+BufferHubBase::BufferHubBase(LocalChannelHandle channel_handle)
+    : Client{pdx::default_transport::ClientChannel::Create(
+          std::move(channel_handle))},
+      id_(-1),
+      cid_(-1) {}
+BufferHubBase::BufferHubBase(const std::string& endpoint_path)
+    : Client{pdx::default_transport::ClientChannelFactory::Create(
+          endpoint_path)},
+      id_(-1),
+      cid_(-1) {}
+
+BufferHubBase::~BufferHubBase() {
+  if (metadata_header_ != nullptr) {
+    metadata_buffer_.Unlock();
+  }
+}
+
+Status<LocalChannelHandle> BufferHubBase::CreateConsumer() {
+  Status<LocalChannelHandle> status =
+      InvokeRemoteMethod<BufferHubRPC::NewConsumer>();
+  ALOGE_IF(!status,
+           "BufferHub::CreateConsumer: Failed to create consumer channel: %s",
+           status.GetErrorMessage().c_str());
+  return status;
+}
+
+int BufferHubBase::ImportBuffer() {
+  ATRACE_NAME("BufferHubBase::ImportBuffer");
+
+  Status<BufferDescription<LocalHandle>> status =
+      InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
+  if (!status) {
+    ALOGE("BufferHubBase::ImportBuffer: Failed to get buffer: %s",
+          status.GetErrorMessage().c_str());
+    return -status.error();
+  } else if (status.get().id() < 0) {
+    ALOGE("BufferHubBase::ImportBuffer: Received an invalid id!");
+    return -EIO;
+  }
+
+  auto buffer_desc = status.take();
+
+  // Stash the buffer id to replace the value in id_.
+  const int new_id = buffer_desc.id();
+
+  // Import the buffer.
+  IonBuffer ion_buffer;
+  ALOGD_IF(TRACE, "BufferHubBase::ImportBuffer: id=%d.", buffer_desc.id());
+
+  if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
+    return ret;
+
+  // Import the metadata.
+  IonBuffer metadata_buffer;
+  if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
+    ALOGE("Failed to import metadata buffer, error=%d", ret);
+    return ret;
+  }
+  size_t metadata_buf_size = metadata_buffer.width();
+  if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
+    ALOGE("BufferHubBase::ImportBuffer: metadata buffer too small: %zu",
+          metadata_buf_size);
+    return -ENOMEM;
+  }
+
+  // If all imports succee, replace the previous buffer and id.
+  buffer_ = std::move(ion_buffer);
+  metadata_buffer_ = std::move(metadata_buffer);
+  metadata_buf_size_ = metadata_buf_size;
+  user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
+
+  void* metadata_ptr = nullptr;
+  if (const int ret =
+          metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
+                                /*y=*/0, metadata_buf_size_,
+                                /*height=*/1, &metadata_ptr)) {
+    ALOGE("BufferHubBase::ImportBuffer: Failed to lock metadata.");
+    return ret;
+  }
+
+  // Set up shared fences.
+  shared_acquire_fence_ = buffer_desc.take_acquire_fence();
+  shared_release_fence_ = buffer_desc.take_release_fence();
+  if (!shared_acquire_fence_ || !shared_release_fence_) {
+    ALOGE("BufferHubBase::ImportBuffer: Failed to import shared fences.");
+    return -EIO;
+  }
+
+  metadata_header_ =
+      reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
+  if (user_metadata_size_) {
+    user_metadata_ptr_ =
+        reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
+                                BufferHubDefs::kMetadataHeaderSize);
+  } else {
+    user_metadata_ptr_ = nullptr;
+  }
+
+  id_ = new_id;
+  cid_ = buffer_desc.buffer_cid();
+  buffer_state_bit_ = buffer_desc.buffer_state_bit();
+
+  // Note that here the buffer state is mapped from shared memory as an atomic
+  // object. The std::atomic's constructor will not be called so that the
+  // original value stored in the memory region will be preserved.
+  buffer_state_ = &metadata_header_->buffer_state;
+  ALOGD_IF(TRACE,
+           "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
+           id(), buffer_state_->load());
+  fence_state_ = &metadata_header_->fence_state;
+  ALOGD_IF(TRACE,
+           "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
+           fence_state_->load());
+
+  return 0;
+}
+
+int BufferHubBase::CheckMetadata(size_t user_metadata_size) const {
+  if (user_metadata_size && !user_metadata_ptr_) {
+    ALOGE("BufferHubBase::CheckMetadata: doesn't support custom metadata.");
+    return -EINVAL;
+  }
+  if (user_metadata_size > user_metadata_size_) {
+    ALOGE("BufferHubBase::CheckMetadata: too big: %zu, maximum: %zu.",
+          user_metadata_size, user_metadata_size_);
+    return -E2BIG;
+  }
+  return 0;
+}
+
+int BufferHubBase::UpdateSharedFence(const LocalHandle& new_fence,
+                                     const LocalHandle& shared_fence) {
+  if (pending_fence_fd_.Get() != new_fence.Get()) {
+    // First, replace the old fd if there was already one. Skipping if the new
+    // one is the same as the old.
+    if (pending_fence_fd_.IsValid()) {
+      const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
+                                pending_fence_fd_.Get(), nullptr);
+      ALOGW_IF(ret,
+               "BufferHubBase::UpdateSharedFence: failed to remove old fence "
+               "fd from epoll set, error: %s.",
+               strerror(errno));
+    }
+
+    if (new_fence.IsValid()) {
+      // If ready fence is valid, we put that into the epoll set.
+      epoll_event event;
+      event.events = EPOLLIN;
+      event.data.u64 = buffer_state_bit();
+      pending_fence_fd_ = new_fence.Duplicate();
+      if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
+                    &event) < 0) {
+        const int error = errno;
+        ALOGE(
+            "BufferHubBase::UpdateSharedFence: failed to add new fence fd "
+            "into epoll set, error: %s.",
+            strerror(error));
+        return -error;
+      }
+      // Set bit in fence state to indicate that there is a fence from this
+      // producer or consumer.
+      fence_state_->fetch_or(buffer_state_bit());
+    } else {
+      // Unset bit in fence state to indicate that there is no fence, so that
+      // when consumer to acquire or producer to acquire, it knows no need to
+      // check fence for this buffer.
+      fence_state_->fetch_and(~buffer_state_bit());
+    }
+  }
+
+  return 0;
+}
+
+int BufferHubBase::Poll(int timeout_ms) {
+  ATRACE_NAME("BufferHubBase::Poll");
+  pollfd p = {event_fd(), POLLIN, 0};
+  return poll(&p, 1, timeout_ms);
+}
+
+int BufferHubBase::Lock(int usage, int x, int y, int width, int height,
+                        void** address) {
+  return buffer_.Lock(usage, x, y, width, height, address);
+}
+
+int BufferHubBase::Unlock() { return buffer_.Unlock(); }
+
+int BufferHubBase::GetBlobReadWritePointer(size_t size, void** addr) {
+  int width = static_cast<int>(size);
+  int height = 1;
+  int ret = Lock(usage(), 0, 0, width, height, addr);
+  if (ret == 0)
+    Unlock();
+  return ret;
+}
+
+int BufferHubBase::GetBlobReadOnlyPointer(size_t size, void** addr) {
+  return GetBlobReadWritePointer(size, addr);
+}
+
+void BufferHubBase::GetBlobFds(int* fds, size_t* fds_count,
+                               size_t max_fds_count) const {
+  size_t numFds = static_cast<size_t>(native_handle()->numFds);
+  *fds_count = std::min(max_fds_count, numFds);
+  std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 577cba9..3f20024 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -1,20 +1,12 @@
-#include <private/dvr/buffer_hub_client.h>
-
-#include <log/log.h>
-#include <poll.h>
-#include <sys/epoll.h>
-#include <utils/Trace.h>
-
 #include <mutex>
 
+#include <log/log.h>
 #include <pdx/default_transport/client_channel.h>
 #include <pdx/default_transport/client_channel_factory.h>
-
-#include "include/private/dvr/bufferhub_rpc.h"
+#include <private/dvr/buffer_hub_client.h>
+#include <utils/Trace.h>
 
 using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
 using android::pdx::default_transport::ClientChannel;
 using android::pdx::default_transport::ClientChannelFactory;
 
@@ -39,615 +31,5 @@
   }
 }
 
-BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle)
-    : Client{pdx::default_transport::ClientChannel::Create(
-          std::move(channel_handle))},
-      id_(-1),
-      cid_(-1) {}
-BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path)
-    : Client{pdx::default_transport::ClientChannelFactory::Create(
-          endpoint_path)},
-      id_(-1),
-      cid_(-1) {}
-
-BufferHubBuffer::~BufferHubBuffer() {
-  if (metadata_header_ != nullptr) {
-    metadata_buffer_.Unlock();
-  }
-}
-
-Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() {
-  Status<LocalChannelHandle> status =
-      InvokeRemoteMethod<BufferHubRPC::NewConsumer>();
-  ALOGE_IF(!status,
-           "BufferHub::CreateConsumer: Failed to create consumer channel: %s",
-           status.GetErrorMessage().c_str());
-  return status;
-}
-
-int BufferHubBuffer::ImportBuffer() {
-  ATRACE_NAME("BufferHubBuffer::ImportBuffer");
-
-  Status<BufferDescription<LocalHandle>> status =
-      InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
-  if (!status) {
-    ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
-  } else if (status.get().id() < 0) {
-    ALOGE("BufferHubBuffer::ImportBuffer: Received an invalid id!");
-    return -EIO;
-  }
-
-  auto buffer_desc = status.take();
-
-  // Stash the buffer id to replace the value in id_.
-  const int new_id = buffer_desc.id();
-
-  // Import the buffer.
-  IonBuffer ion_buffer;
-  ALOGD_IF(TRACE, "BufferHubBuffer::ImportBuffer: id=%d.", buffer_desc.id());
-
-  if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
-    return ret;
-
-  // Import the metadata.
-  IonBuffer metadata_buffer;
-  if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
-    ALOGE("Failed to import metadata buffer, error=%d", ret);
-    return ret;
-  }
-  size_t metadata_buf_size = metadata_buffer.width();
-  if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
-    ALOGE("BufferHubBuffer::ImportBuffer: metadata buffer too small: %zu",
-          metadata_buf_size);
-    return -ENOMEM;
-  }
-
-  // If all imports succee, replace the previous buffer and id.
-  buffer_ = std::move(ion_buffer);
-  metadata_buffer_ = std::move(metadata_buffer);
-  metadata_buf_size_ = metadata_buf_size;
-  user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
-
-  void* metadata_ptr = nullptr;
-  if (const int ret =
-          metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
-                                /*y=*/0, metadata_buf_size_,
-                                /*height=*/1, &metadata_ptr)) {
-    ALOGE("BufferHubBuffer::ImportBuffer: Failed to lock metadata.");
-    return ret;
-  }
-
-  // Set up shared fences.
-  shared_acquire_fence_ = buffer_desc.take_acquire_fence();
-  shared_release_fence_ = buffer_desc.take_release_fence();
-  if (!shared_acquire_fence_ || !shared_release_fence_) {
-    ALOGE("BufferHubBuffer::ImportBuffer: Failed to import shared fences.");
-    return -EIO;
-  }
-
-  metadata_header_ =
-      reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
-  if (user_metadata_size_) {
-    user_metadata_ptr_ =
-        reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
-                                BufferHubDefs::kMetadataHeaderSize);
-  } else {
-    user_metadata_ptr_ = nullptr;
-  }
-
-  id_ = new_id;
-  cid_ = buffer_desc.buffer_cid();
-  buffer_state_bit_ = buffer_desc.buffer_state_bit();
-
-  // Note that here the buffer state is mapped from shared memory as an atomic
-  // object. The std::atomic's constructor will not be called so that the
-  // original value stored in the memory region will be preserved.
-  buffer_state_ = &metadata_header_->buffer_state;
-  ALOGD_IF(TRACE,
-           "BufferHubBuffer::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
-           id(), buffer_state_->load());
-  fence_state_ = &metadata_header_->fence_state;
-  ALOGD_IF(TRACE,
-           "BufferHubBuffer::ImportBuffer: id=%d, fence_state=%" PRIx64 ".",
-           id(), fence_state_->load());
-
-  return 0;
-}
-
-inline int BufferHubBuffer::CheckMetadata(size_t user_metadata_size) const {
-  if (user_metadata_size && !user_metadata_ptr_) {
-    ALOGE("BufferHubBuffer::CheckMetadata: doesn't support custom metadata.");
-    return -EINVAL;
-  }
-  if (user_metadata_size > user_metadata_size_) {
-    ALOGE("BufferHubBuffer::CheckMetadata: too big: %zu, maximum: %zu.",
-          user_metadata_size, user_metadata_size_);
-    return -E2BIG;
-  }
-  return 0;
-}
-
-int BufferHubBuffer::UpdateSharedFence(const LocalHandle& new_fence,
-                                       const LocalHandle& shared_fence) {
-  if (pending_fence_fd_.Get() != new_fence.Get()) {
-    // First, replace the old fd if there was already one. Skipping if the new
-    // one is the same as the old.
-    if (pending_fence_fd_.IsValid()) {
-      const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
-                                pending_fence_fd_.Get(), nullptr);
-      ALOGW_IF(ret,
-               "BufferHubBuffer::UpdateSharedFence: failed to remove old fence "
-               "fd from epoll set, error: %s.",
-               strerror(errno));
-    }
-
-    if (new_fence.IsValid()) {
-      // If ready fence is valid, we put that into the epoll set.
-      epoll_event event;
-      event.events = EPOLLIN;
-      event.data.u64 = buffer_state_bit();
-      pending_fence_fd_ = new_fence.Duplicate();
-      if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
-                    &event) < 0) {
-        const int error = errno;
-        ALOGE(
-            "BufferHubBuffer::UpdateSharedFence: failed to add new fence fd "
-            "into epoll set, error: %s.",
-            strerror(error));
-        return -error;
-      }
-      // Set bit in fence state to indicate that there is a fence from this
-      // producer or consumer.
-      fence_state_->fetch_or(buffer_state_bit());
-    } else {
-      // Unset bit in fence state to indicate that there is no fence, so that
-      // when consumer to acquire or producer to acquire, it knows no need to
-      // check fence for this buffer.
-      fence_state_->fetch_and(~buffer_state_bit());
-    }
-  }
-
-  return 0;
-}
-
-int BufferHubBuffer::Poll(int timeout_ms) {
-  ATRACE_NAME("BufferHubBuffer::Poll");
-  pollfd p = {event_fd(), POLLIN, 0};
-  return poll(&p, 1, timeout_ms);
-}
-
-int BufferHubBuffer::Lock(int usage, int x, int y, int width, int height,
-                          void** address) {
-  return buffer_.Lock(usage, x, y, width, height, address);
-}
-
-int BufferHubBuffer::Unlock() { return buffer_.Unlock(); }
-
-int BufferHubBuffer::GetBlobReadWritePointer(size_t size, void** addr) {
-  int width = static_cast<int>(size);
-  int height = 1;
-  int ret = Lock(usage(), 0, 0, width, height, addr);
-  if (ret == 0)
-    Unlock();
-  return ret;
-}
-
-int BufferHubBuffer::GetBlobReadOnlyPointer(size_t size, void** addr) {
-  return GetBlobReadWritePointer(size, addr);
-}
-
-void BufferHubBuffer::GetBlobFds(int* fds, size_t* fds_count,
-                                 size_t max_fds_count) const {
-  size_t numFds = static_cast<size_t>(native_handle()->numFds);
-  *fds_count = std::min(max_fds_count, numFds);
-  std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
-}
-
-BufferConsumer::BufferConsumer(LocalChannelHandle channel)
-    : BASE(std::move(channel)) {
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE("BufferConsumer::BufferConsumer: Failed to import buffer: %s",
-          strerror(-ret));
-    Close(ret);
-  }
-}
-
-std::unique_ptr<BufferConsumer> BufferConsumer::Import(
-    LocalChannelHandle channel) {
-  ATRACE_NAME("BufferConsumer::Import");
-  ALOGD_IF(TRACE, "BufferConsumer::Import: channel=%d", channel.value());
-  return BufferConsumer::Create(std::move(channel));
-}
-
-std::unique_ptr<BufferConsumer> BufferConsumer::Import(
-    Status<LocalChannelHandle> status) {
-  return Import(status ? status.take()
-                       : LocalChannelHandle{nullptr, -status.error()});
-}
-
-int BufferConsumer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
-                                 LocalHandle* out_fence) {
-  if (!out_meta)
-    return -EINVAL;
-
-  // Only check producer bit and this consumer buffer's particular consumer bit.
-  // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
-  // is not set.
-  uint64_t buffer_state = buffer_state_->load();
-  if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
-    ALOGE("BufferConsumer::LocalAcquire: not posted, id=%d state=%" PRIx64
-          " buffer_state_bit=%" PRIx64 ".",
-          id(), buffer_state, buffer_state_bit());
-    return -EBUSY;
-  }
-
-  // Copy the canonical metadata.
-  void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
-  memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
-  // Fill in the user_metadata_ptr in address space of the local process.
-  if (out_meta->user_metadata_size) {
-    out_meta->user_metadata_ptr =
-        reinterpret_cast<uint64_t>(user_metadata_ptr_);
-  } else {
-    out_meta->user_metadata_ptr = 0;
-  }
-
-  uint64_t fence_state = fence_state_->load();
-  // If there is an acquire fence from producer, we need to return it.
-  if (fence_state & BufferHubDefs::kProducerStateBit) {
-    *out_fence = shared_acquire_fence_.Duplicate();
-  }
-
-  // Set the consumer bit unique to this consumer.
-  BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
-  return 0;
-}
-
-int BufferConsumer::Acquire(LocalHandle* ready_fence) {
-  return Acquire(ready_fence, nullptr, 0);
-}
-
-int BufferConsumer::Acquire(LocalHandle* ready_fence, void* meta,
-                            size_t user_metadata_size) {
-  ATRACE_NAME("BufferConsumer::Acquire");
-
-  if (const int error = CheckMetadata(user_metadata_size))
-    return error;
-
-  DvrNativeBufferMetadata canonical_meta;
-  if (const int error = LocalAcquire(&canonical_meta, ready_fence))
-    return error;
-
-  if (meta && user_metadata_size) {
-    void* metadata_src =
-        reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
-    if (metadata_src) {
-      memcpy(meta, metadata_src, user_metadata_size);
-    } else {
-      ALOGW("BufferConsumer::Acquire: no user-defined metadata.");
-    }
-  }
-
-  auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
-  if (!status)
-    return -status.error();
-  return 0;
-}
-
-int BufferConsumer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
-                                 LocalHandle* out_fence) {
-  ATRACE_NAME("BufferConsumer::AcquireAsync");
-
-  if (const int error = LocalAcquire(out_meta, out_fence))
-    return error;
-
-  auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
-  if (!status)
-    return -status.error();
-  return 0;
-}
-
-int BufferConsumer::LocalRelease(const DvrNativeBufferMetadata* meta,
-                                 const LocalHandle& release_fence) {
-  if (const int error = CheckMetadata(meta->user_metadata_size))
-    return error;
-
-  // Check invalid state transition.
-  uint64_t buffer_state = buffer_state_->load();
-  if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
-    ALOGE("BufferConsumer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
-          id(), buffer_state);
-    return -EBUSY;
-  }
-
-  // On release, only the user requested metadata is copied back into the shared
-  // memory for metadata. Since there are multiple consumers, it doesn't make
-  // sense to send the canonical metadata back to the producer. However, one of
-  // the consumer can still choose to write up to user_metadata_size bytes of
-  // data into user_metadata_ptr.
-  if (meta->user_metadata_ptr && meta->user_metadata_size) {
-    void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
-    memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
-  }
-
-  // Send out the release fence through the shared epoll fd. Note that during
-  // releasing the producer is not expected to be polling on the fence.
-  if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
-    return error;
-
-  // For release operation, the client don't need to change the state as it's
-  // bufferhubd's job to flip the produer bit once all consumers are released.
-  return 0;
-}
-
-int BufferConsumer::Release(const LocalHandle& release_fence) {
-  ATRACE_NAME("BufferConsumer::Release");
-
-  DvrNativeBufferMetadata meta;
-  if (const int error = LocalRelease(&meta, release_fence))
-    return error;
-
-  return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
-      BorrowedFence(release_fence.Borrow())));
-}
-
-int BufferConsumer::ReleaseAsync() {
-  DvrNativeBufferMetadata meta;
-  return ReleaseAsync(&meta, LocalHandle());
-}
-
-int BufferConsumer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
-                                 const LocalHandle& release_fence) {
-  ATRACE_NAME("BufferConsumer::ReleaseAsync");
-
-  if (const int error = LocalRelease(meta, release_fence))
-    return error;
-
-  return ReturnStatusOrError(
-      SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
-}
-
-int BufferConsumer::Discard() { return Release(LocalHandle()); }
-
-int BufferConsumer::SetIgnore(bool ignore) {
-  return ReturnStatusOrError(
-      InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore));
-}
-
-BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                               uint64_t usage, size_t user_metadata_size)
-    : BASE(BufferHubRPC::kClientPath) {
-  ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE,
-           "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u "
-           "usage=%" PRIx64 " user_metadata_size=%zu",
-           event_fd(), width, height, format, usage, user_metadata_size);
-
-  auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
-      width, height, format, usage, user_metadata_size);
-  if (!status) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to create producer buffer: %s",
-        status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
-        strerror(-ret));
-    Close(ret);
-  }
-}
-
-BufferProducer::BufferProducer(uint64_t usage, size_t size)
-    : BASE(BufferHubRPC::kClientPath) {
-  ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE, "BufferProducer::BufferProducer: usage=%" PRIx64 " size=%zu",
-           usage, size);
-  const int width = static_cast<int>(size);
-  const int height = 1;
-  const int format = HAL_PIXEL_FORMAT_BLOB;
-  const size_t user_metadata_size = 0;
-
-  auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
-      width, height, format, usage, user_metadata_size);
-  if (!status) {
-    ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s",
-          status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
-        strerror(-ret));
-    Close(ret);
-  }
-}
-
-BufferProducer::BufferProducer(LocalChannelHandle channel)
-    : BASE(std::move(channel)) {
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
-        strerror(-ret));
-    Close(ret);
-  }
-}
-
-int BufferProducer::LocalPost(const DvrNativeBufferMetadata* meta,
-                              const LocalHandle& ready_fence) {
-  if (const int error = CheckMetadata(meta->user_metadata_size))
-    return error;
-
-  // Check invalid state transition.
-  uint64_t buffer_state = buffer_state_->load();
-  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
-    ALOGE("BufferProducer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
-          id(), buffer_state);
-    return -EBUSY;
-  }
-
-  // Copy the canonical metadata.
-  void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
-  memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata));
-  // Copy extra user requested metadata.
-  if (meta->user_metadata_ptr && meta->user_metadata_size) {
-    void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
-    memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
-  }
-
-  // Send out the acquire fence through the shared epoll fd. Note that during
-  // posting no consumer is not expected to be polling on the fence.
-  if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_))
-    return error;
-
-  // Set the producer bit atomically to transit into posted state.
-  BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
-                                   BufferHubDefs::kProducerStateBit);
-  return 0;
-}
-
-int BufferProducer::Post(const LocalHandle& ready_fence, const void* meta,
-                         size_t user_metadata_size) {
-  ATRACE_NAME("BufferProducer::Post");
-
-  // Populate cononical metadata for posting.
-  DvrNativeBufferMetadata canonical_meta;
-  canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta);
-  canonical_meta.user_metadata_size = user_metadata_size;
-
-  if (const int error = LocalPost(&canonical_meta, ready_fence))
-    return error;
-
-  return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>(
-      BorrowedFence(ready_fence.Borrow())));
-}
-
-int BufferProducer::PostAsync(const DvrNativeBufferMetadata* meta,
-                              const LocalHandle& ready_fence) {
-  ATRACE_NAME("BufferProducer::PostAsync");
-
-  if (const int error = LocalPost(meta, ready_fence))
-    return error;
-
-  return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode));
-}
-
-int BufferProducer::LocalGain(DvrNativeBufferMetadata* out_meta,
-                              LocalHandle* out_fence) {
-  uint64_t buffer_state = buffer_state_->load();
-  ALOGD_IF(TRACE, "BufferProducer::LocalGain: buffer=%d, state=%" PRIx64 ".",
-           id(), buffer_state);
-
-  if (!out_meta)
-    return -EINVAL;
-
-  if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
-    if (BufferHubDefs::IsBufferGained(buffer_state)) {
-      // We don't want to log error when gaining a newly allocated
-      // buffer.
-      ALOGI("BufferProducer::LocalGain: already gained id=%d.", id());
-      return -EALREADY;
-    }
-    ALOGE("BufferProducer::LocalGain: not released id=%d state=%" PRIx64 ".",
-          id(), buffer_state);
-    return -EBUSY;
-  }
-
-  // Canonical metadata is undefined on Gain. Except for user_metadata and
-  // release_fence_mask. Fill in the user_metadata_ptr in address space of the
-  // local process.
-  if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) {
-    out_meta->user_metadata_size =
-        metadata_header_->metadata.user_metadata_size;
-    out_meta->user_metadata_ptr =
-        reinterpret_cast<uint64_t>(user_metadata_ptr_);
-  } else {
-    out_meta->user_metadata_size = 0;
-    out_meta->user_metadata_ptr = 0;
-  }
-
-  uint64_t fence_state = fence_state_->load();
-  // If there is an release fence from consumer, we need to return it.
-  if (fence_state & BufferHubDefs::kConsumerStateMask) {
-    *out_fence = shared_release_fence_.Duplicate();
-    out_meta->release_fence_mask =
-        fence_state & BufferHubDefs::kConsumerStateMask;
-  }
-
-  // Clear out all bits and the buffer is now back to gained state.
-  buffer_state_->store(0ULL);
-  return 0;
-}
-
-int BufferProducer::Gain(LocalHandle* release_fence) {
-  ATRACE_NAME("BufferProducer::Gain");
-
-  DvrNativeBufferMetadata meta;
-  if (const int error = LocalGain(&meta, release_fence))
-    return error;
-
-  auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
-  if (!status)
-    return -status.error();
-  return 0;
-}
-
-int BufferProducer::GainAsync(DvrNativeBufferMetadata* out_meta,
-                              LocalHandle* release_fence) {
-  ATRACE_NAME("BufferProducer::GainAsync");
-
-  if (const int error = LocalGain(out_meta, release_fence))
-    return error;
-
-  return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
-}
-
-int BufferProducer::GainAsync() {
-  DvrNativeBufferMetadata meta;
-  LocalHandle fence;
-  return GainAsync(&meta, &fence);
-}
-
-std::unique_ptr<BufferProducer> BufferProducer::Import(
-    LocalChannelHandle channel) {
-  ALOGD_IF(TRACE, "BufferProducer::Import: channel=%d", channel.value());
-  return BufferProducer::Create(std::move(channel));
-}
-
-std::unique_ptr<BufferProducer> BufferProducer::Import(
-    Status<LocalChannelHandle> status) {
-  return Import(status ? status.take()
-                       : LocalChannelHandle{nullptr, -status.error()});
-}
-
-Status<LocalChannelHandle> BufferProducer::Detach() {
-  uint64_t buffer_state = buffer_state_->load();
-  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
-    // Can only detach a BufferProducer when it's in gained state.
-    ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64
-          ") is not in gained state.",
-          id(), buffer_state);
-    return {};
-  }
-
-  Status<LocalChannelHandle> status =
-      InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
-  ALOGE_IF(!status,
-           "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(),
-           status.GetErrorMessage().c_str());
-  return status;
-}
-
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub_metadata-test.cpp b/libs/vr/libbufferhub/buffer_hub_metadata-test.cpp
new file mode 100644
index 0000000..8c1c01c
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_hub_metadata-test.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <private/dvr/buffer_hub_metadata.h>
+
+using android::dvr::BufferHubDefs::IsBufferGained;
+
+namespace android {
+namespace dvr {
+
+constexpr size_t kEmptyUserMetadataSize = 0;
+
+class BufferHubMetadataTest : public ::testing::Test {};
+
+TEST_F(BufferHubMetadataTest, Create_UserMetdataSizeTooBig) {
+  BufferHubMetadata m1 =
+      BufferHubMetadata::Create(std::numeric_limits<uint32_t>::max());
+  EXPECT_FALSE(m1.IsValid());
+}
+
+TEST_F(BufferHubMetadataTest, Create_Success) {
+  BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize);
+  EXPECT_TRUE(m1.IsValid());
+  EXPECT_NE(m1.metadata_header(), nullptr);
+}
+
+TEST_F(BufferHubMetadataTest, Import_Success) {
+  BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize);
+  EXPECT_TRUE(m1.IsValid());
+  EXPECT_NE(m1.metadata_header(), nullptr);
+
+  pdx::LocalHandle h2 = m1.ashmem_handle().Duplicate();
+  EXPECT_TRUE(h2.IsValid());
+
+  BufferHubMetadata m2 = BufferHubMetadata::Import(std::move(h2));
+  EXPECT_FALSE(h2.IsValid());
+  EXPECT_TRUE(m1.IsValid());
+  BufferHubDefs::MetadataHeader* mh1 = m1.metadata_header();
+  EXPECT_NE(mh1, nullptr);
+
+  // TODO(b/111976433): Update this test once BufferHub state machine gets
+  // updated. In the old model, buffer starts in the gained state (i.e.
+  // valued 0). In the new model, buffer states in the released state.
+  EXPECT_TRUE(IsBufferGained(mh1->fence_state.load()));
+
+  EXPECT_TRUE(m2.IsValid());
+  BufferHubDefs::MetadataHeader* mh2 = m2.metadata_header();
+  EXPECT_NE(mh2, nullptr);
+
+  // TODO(b/111976433): Update this test once BufferHub state machine gets
+  // updated. In the old model, buffer starts in the gained state (i.e.
+  // valued 0). In the new model, buffer states in the released state.
+  EXPECT_TRUE(IsBufferGained(mh2->fence_state.load()));
+}
+
+TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) {
+  BufferHubMetadata m1 = BufferHubMetadata::Create(sizeof(int));
+  EXPECT_TRUE(m1.IsValid());
+  EXPECT_NE(m1.metadata_header(), nullptr);
+  EXPECT_TRUE(m1.ashmem_handle().IsValid());
+  EXPECT_EQ(m1.user_metadata_size(), sizeof(int));
+
+  BufferHubMetadata m2 = std::move(m1);
+
+  // After the move, the metadata header (a raw pointer) should be reset in the
+  // older buffer.
+  EXPECT_EQ(m1.metadata_header(), nullptr);
+  EXPECT_NE(m2.metadata_header(), nullptr);
+
+  EXPECT_FALSE(m1.ashmem_handle().IsValid());
+  EXPECT_TRUE(m2.ashmem_handle().IsValid());
+
+  EXPECT_EQ(m1.user_metadata_size(), 0U);
+  EXPECT_EQ(m2.user_metadata_size(), sizeof(int));
+
+  BufferHubMetadata m3{std::move(m2)};
+
+  // After the move, the metadata header (a raw pointer) should be reset in the
+  // older buffer.
+  EXPECT_EQ(m2.metadata_header(), nullptr);
+  EXPECT_NE(m3.metadata_header(), nullptr);
+
+  EXPECT_FALSE(m2.ashmem_handle().IsValid());
+  EXPECT_TRUE(m3.ashmem_handle().IsValid());
+
+  EXPECT_EQ(m2.user_metadata_size(), 0U);
+  EXPECT_EQ(m3.user_metadata_size(), sizeof(int));
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub_metadata.cpp b/libs/vr/libbufferhub/buffer_hub_metadata.cpp
new file mode 100644
index 0000000..8243fc5
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_hub_metadata.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include <cutils/ashmem.h>
+#include <log/log.h>
+#include <private/dvr/buffer_hub_metadata.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+static const int kAshmemProt = PROT_READ | PROT_WRITE;
+
+}  // namespace
+
+using BufferHubDefs::kMetadataHeaderSize;
+using BufferHubDefs::MetadataHeader;
+
+/* static */
+BufferHubMetadata BufferHubMetadata::Create(size_t user_metadata_size) {
+  // The size the of metadata buffer is used as the "width" parameter during
+  // allocation. Thus it cannot overflow uint32_t.
+  if (user_metadata_size >=
+      (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) {
+    ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.",
+          user_metadata_size);
+    return {};
+  }
+
+  const size_t metadata_size = user_metadata_size + kMetadataHeaderSize;
+  int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadata_size);
+  if (fd < 0) {
+    ALOGE("BufferHubMetadata::Create: failed to create ashmem region.");
+    return {};
+  }
+
+  // Hand over the ownership of the fd to a pdx::LocalHandle immediately after
+  // the successful return of ashmem_create_region. The ashmem_handle is going
+  // to own the fd and to prevent fd leaks during error handling.
+  pdx::LocalHandle ashmem_handle{fd};
+
+  if (ashmem_set_prot_region(ashmem_handle.Get(), kAshmemProt) != 0) {
+    ALOGE("BufferHubMetadata::Create: failed to set protect region.");
+    return {};
+  }
+
+  return BufferHubMetadata::Import(std::move(ashmem_handle));
+}
+
+/* static */
+BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmem_handle) {
+  if (!ashmem_valid(ashmem_handle.Get())) {
+    ALOGE("BufferHubMetadata::Import: invalid ashmem fd.");
+    return {};
+  }
+
+  size_t metadata_size = ashmem_get_size_region(ashmem_handle.Get());
+  size_t user_metadata_size = metadata_size - kMetadataHeaderSize;
+
+  auto metadata_header = static_cast<MetadataHeader*>(
+      mmap(nullptr, metadata_size, kAshmemProt, MAP_SHARED, ashmem_handle.Get(),
+           /*offset=*/0));
+  if (metadata_header == nullptr) {
+    ALOGE("BufferHubMetadata::Import: failed to map region.");
+    return {};
+  }
+
+  return BufferHubMetadata(user_metadata_size, std::move(ashmem_handle),
+                           metadata_header);
+}
+
+BufferHubMetadata::BufferHubMetadata(size_t user_metadata_size,
+                                     pdx::LocalHandle ashmem_handle,
+                                     MetadataHeader* metadata_header)
+    : user_metadata_size_(user_metadata_size),
+      ashmem_handle_(std::move(ashmem_handle)),
+      metadata_header_(metadata_header) {}
+
+BufferHubMetadata::~BufferHubMetadata() {
+  if (metadata_header_ != nullptr) {
+    int ret = munmap(metadata_header_, metadata_size());
+    ALOGE_IF(ret != 0,
+             "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, "
+             "error=%d.",
+             errno);
+    metadata_header_ = nullptr;
+  }
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
new file mode 100644
index 0000000..4e8c36b
--- /dev/null
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -0,0 +1,183 @@
+#include <private/dvr/consumer_buffer.h>
+
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+
+namespace android {
+namespace dvr {
+
+ConsumerBuffer::ConsumerBuffer(LocalChannelHandle channel)
+    : BASE(std::move(channel)) {
+  const int ret = ImportBuffer();
+  if (ret < 0) {
+    ALOGE("ConsumerBuffer::ConsumerBuffer: Failed to import buffer: %s",
+          strerror(-ret));
+    Close(ret);
+  }
+}
+
+std::unique_ptr<ConsumerBuffer> ConsumerBuffer::Import(
+    LocalChannelHandle channel) {
+  ATRACE_NAME("ConsumerBuffer::Import");
+  ALOGD_IF(TRACE, "ConsumerBuffer::Import: channel=%d", channel.value());
+  return ConsumerBuffer::Create(std::move(channel));
+}
+
+std::unique_ptr<ConsumerBuffer> ConsumerBuffer::Import(
+    Status<LocalChannelHandle> status) {
+  return Import(status ? status.take()
+                       : LocalChannelHandle{nullptr, -status.error()});
+}
+
+int ConsumerBuffer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
+                                 LocalHandle* out_fence) {
+  if (!out_meta)
+    return -EINVAL;
+
+  // Only check producer bit and this consumer buffer's particular consumer bit.
+  // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
+  // is not set.
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
+    ALOGE("ConsumerBuffer::LocalAcquire: not posted, id=%d state=%" PRIx64
+          " buffer_state_bit=%" PRIx64 ".",
+          id(), buffer_state, buffer_state_bit());
+    return -EBUSY;
+  }
+
+  // Copy the canonical metadata.
+  void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
+  memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
+  // Fill in the user_metadata_ptr in address space of the local process.
+  if (out_meta->user_metadata_size) {
+    out_meta->user_metadata_ptr =
+        reinterpret_cast<uint64_t>(user_metadata_ptr_);
+  } else {
+    out_meta->user_metadata_ptr = 0;
+  }
+
+  uint64_t fence_state = fence_state_->load();
+  // If there is an acquire fence from producer, we need to return it.
+  if (fence_state & BufferHubDefs::kProducerStateBit) {
+    *out_fence = shared_acquire_fence_.Duplicate();
+  }
+
+  // Set the consumer bit unique to this consumer.
+  BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
+  return 0;
+}
+
+int ConsumerBuffer::Acquire(LocalHandle* ready_fence) {
+  return Acquire(ready_fence, nullptr, 0);
+}
+
+int ConsumerBuffer::Acquire(LocalHandle* ready_fence, void* meta,
+                            size_t user_metadata_size) {
+  ATRACE_NAME("ConsumerBuffer::Acquire");
+
+  if (const int error = CheckMetadata(user_metadata_size))
+    return error;
+
+  DvrNativeBufferMetadata canonical_meta;
+  if (const int error = LocalAcquire(&canonical_meta, ready_fence))
+    return error;
+
+  if (meta && user_metadata_size) {
+    void* metadata_src =
+        reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
+    if (metadata_src) {
+      memcpy(meta, metadata_src, user_metadata_size);
+    } else {
+      ALOGW("ConsumerBuffer::Acquire: no user-defined metadata.");
+    }
+  }
+
+  auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
+  if (!status)
+    return -status.error();
+  return 0;
+}
+
+int ConsumerBuffer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
+                                 LocalHandle* out_fence) {
+  ATRACE_NAME("ConsumerBuffer::AcquireAsync");
+
+  if (const int error = LocalAcquire(out_meta, out_fence))
+    return error;
+
+  auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
+  if (!status)
+    return -status.error();
+  return 0;
+}
+
+int ConsumerBuffer::LocalRelease(const DvrNativeBufferMetadata* meta,
+                                 const LocalHandle& release_fence) {
+  if (const int error = CheckMetadata(meta->user_metadata_size))
+    return error;
+
+  // Check invalid state transition.
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
+    ALOGE("ConsumerBuffer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
+          id(), buffer_state);
+    return -EBUSY;
+  }
+
+  // On release, only the user requested metadata is copied back into the shared
+  // memory for metadata. Since there are multiple consumers, it doesn't make
+  // sense to send the canonical metadata back to the producer. However, one of
+  // the consumer can still choose to write up to user_metadata_size bytes of
+  // data into user_metadata_ptr.
+  if (meta->user_metadata_ptr && meta->user_metadata_size) {
+    void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
+    memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
+  }
+
+  // Send out the release fence through the shared epoll fd. Note that during
+  // releasing the producer is not expected to be polling on the fence.
+  if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
+    return error;
+
+  // For release operation, the client don't need to change the state as it's
+  // bufferhubd's job to flip the produer bit once all consumers are released.
+  return 0;
+}
+
+int ConsumerBuffer::Release(const LocalHandle& release_fence) {
+  ATRACE_NAME("ConsumerBuffer::Release");
+
+  DvrNativeBufferMetadata meta;
+  if (const int error = LocalRelease(&meta, release_fence))
+    return error;
+
+  return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
+      BorrowedFence(release_fence.Borrow())));
+}
+
+int ConsumerBuffer::ReleaseAsync() {
+  DvrNativeBufferMetadata meta;
+  return ReleaseAsync(&meta, LocalHandle());
+}
+
+int ConsumerBuffer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
+                                 const LocalHandle& release_fence) {
+  ATRACE_NAME("ConsumerBuffer::ReleaseAsync");
+
+  if (const int error = LocalRelease(meta, release_fence))
+    return error;
+
+  return ReturnStatusOrError(
+      SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
+}
+
+int ConsumerBuffer::Discard() { return Release(LocalHandle()); }
+
+int ConsumerBuffer::SetIgnore(bool ignore) {
+  return ReturnStatusOrError(
+      InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore));
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
new file mode 100644
index 0000000..24db241
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -0,0 +1,172 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_BASE_H_
+#define ANDROID_DVR_BUFFER_HUB_BASE_H_
+
+#include <vector>
+
+#include <private/dvr/bufferhub_rpc.h>
+
+namespace android {
+namespace dvr {
+
+// Base class of two types of BufferHub clients: dvr::ProducerBuffer and
+// dvr::ConsumerBuffer.
+class BufferHubBase : public pdx::Client {
+ public:
+  using LocalHandle = pdx::LocalHandle;
+  using LocalChannelHandle = pdx::LocalChannelHandle;
+  template <typename T>
+  using Status = pdx::Status<T>;
+
+  // Create a new consumer channel that is attached to the producer. Returns
+  // a file descriptor for the new channel or a negative error code.
+  Status<LocalChannelHandle> CreateConsumer();
+
+  // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
+  int Poll(int timeout_ms);
+
+  // Locks the area specified by (x, y, width, height) for a specific usage. If
+  // the usage is software then |addr| will be updated to point to the address
+  // of the buffer in virtual memory. The caller should only access/modify the
+  // pixels in the specified area. anything else is undefined behavior.
+  int Lock(int usage, int x, int y, int width, int height, void** addr);
+
+  // Must be called after Lock() when the caller has finished changing the
+  // buffer.
+  int Unlock();
+
+  // Gets a blob buffer that was created with ProducerBuffer::CreateBlob.
+  // Locking and Unlocking is handled internally. There's no need to Unlock
+  // after calling this method.
+  int GetBlobReadWritePointer(size_t size, void** addr);
+
+  // Gets a blob buffer that was created with ProducerBuffer::CreateBlob.
+  // Locking and Unlocking is handled internally. There's no need to Unlock
+  // after calling this method.
+  int GetBlobReadOnlyPointer(size_t size, void** addr);
+
+  // Returns a dup'd file descriptor for accessing the blob shared memory. The
+  // caller takes ownership of the file descriptor and must close it or pass on
+  // ownership. Some GPU API extensions can take file descriptors to bind shared
+  // memory gralloc buffers to GPU buffer objects.
+  LocalHandle GetBlobFd() const {
+    // Current GPU vendor puts the buffer allocation in one FD. If we change GPU
+    // vendors and this is the wrong fd, late-latching and EDS will very clearly
+    // stop working and we will need to correct this. The alternative is to use
+    // a GL context in the pose service to allocate this buffer or to use the
+    // ION API directly instead of gralloc.
+    return LocalHandle(dup(native_handle()->data[0]));
+  }
+
+  // Get up to |max_fds_count| file descriptors for accessing the blob shared
+  // memory. |fds_count| will contain the actual number of file descriptors.
+  void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
+
+  using Client::event_fd;
+
+  Status<int> GetEventMask(int events) {
+    if (auto* client_channel = GetChannel()) {
+      return client_channel->GetEventMask(events);
+    } else {
+      return pdx::ErrorStatus(EINVAL);
+    }
+  }
+
+  std::vector<pdx::ClientChannel::EventSource> GetEventSources() const {
+    if (auto* client_channel = GetChannel()) {
+      return client_channel->GetEventSources();
+    } else {
+      return {};
+    }
+  }
+
+  native_handle_t* native_handle() const {
+    return const_cast<native_handle_t*>(buffer_.handle());
+  }
+
+  IonBuffer* buffer() { return &buffer_; }
+  const IonBuffer* buffer() const { return &buffer_; }
+
+  // Gets ID of the buffer client. All BufferHub clients derived from the same
+  // buffer in bufferhubd share the same buffer id.
+  int id() const { return id_; }
+
+  // Gets the channel id of the buffer client. Each BufferHub client has its
+  // system unique channel id.
+  int cid() const { return cid_; }
+
+  // Returns the buffer buffer state.
+  uint64_t buffer_state() { return buffer_state_->load(); };
+
+  // A state mask which is unique to a buffer hub client among all its siblings
+  // sharing the same concrete graphic buffer.
+  uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+
+  // The following methods return settings of the first buffer. Currently,
+  // it is only possible to create multi-buffer BufferHubBases with the same
+  // settings.
+  uint32_t width() const { return buffer_.width(); }
+  uint32_t height() const { return buffer_.height(); }
+  uint32_t stride() const { return buffer_.stride(); }
+  uint32_t format() const { return buffer_.format(); }
+  uint32_t usage() const { return buffer_.usage(); }
+  uint32_t layer_count() const { return buffer_.layer_count(); }
+
+  uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
+  void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
+
+ protected:
+  explicit BufferHubBase(LocalChannelHandle channel);
+  explicit BufferHubBase(const std::string& endpoint_path);
+  virtual ~BufferHubBase();
+
+  // Initialization helper.
+  int ImportBuffer();
+
+  // Check invalid metadata operation. Returns 0 if requested metadata is valid.
+  int CheckMetadata(size_t user_metadata_size) const;
+
+  // Send out the new fence by updating the shared fence (shared_release_fence
+  // for producer and shared_acquire_fence for consumer). Note that during this
+  // should only be used in LocalPost() or LocalRelease, and the shared fence
+  // shouldn't be poll'ed by the other end.
+  int UpdateSharedFence(const LocalHandle& new_fence,
+                        const LocalHandle& shared_fence);
+
+  // IonBuffer that is shared between bufferhubd, producer, and consumers.
+  size_t metadata_buf_size_{0};
+  size_t user_metadata_size_{0};
+  BufferHubDefs::MetadataHeader* metadata_header_{nullptr};
+  void* user_metadata_ptr_{nullptr};
+  std::atomic<uint64_t>* buffer_state_{nullptr};
+  std::atomic<uint64_t>* fence_state_{nullptr};
+
+  LocalHandle shared_acquire_fence_;
+  LocalHandle shared_release_fence_;
+
+  // A local fence fd that holds the ownership of the fence fd on Post (for
+  // producer) and Release (for consumer).
+  LocalHandle pending_fence_fd_;
+
+ private:
+  BufferHubBase(const BufferHubBase&) = delete;
+  void operator=(const BufferHubBase&) = delete;
+
+  // Global id for the buffer that is consistent across processes. It is meant
+  // for logging and debugging purposes only and should not be used for lookup
+  // or any other functional purpose as a security precaution.
+  int id_;
+
+  // Channel id.
+  int cid_;
+
+  // Client bit mask which indicates the locations of this client object in the
+  // buffer_state_.
+  uint64_t buffer_state_bit_{0ULL};
+  IonBuffer buffer_;
+  IonBuffer metadata_buffer_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFER_HUB_BASE_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index 0b2666a..7b317d1 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -1,17 +1,10 @@
 #ifndef ANDROID_DVR_BUFFER_HUB_CLIENT_H_
 #define ANDROID_DVR_BUFFER_HUB_CLIENT_H_
 
-#include <hardware/gralloc.h>
 #include <pdx/channel_handle.h>
 #include <pdx/client.h>
-#include <pdx/file_handle.h>
-#include <pdx/status.h>
-
-#include <vector>
-
-#include <private/dvr/ion_buffer.h>
-
-#include "bufferhub_rpc.h"
+#include <private/dvr/consumer_buffer.h>
+#include <private/dvr/producer_buffer.h>
 
 namespace android {
 namespace dvr {
@@ -31,322 +24,6 @@
   using pdx::Client::event_fd;
 };
 
-class BufferHubBuffer : public pdx::Client {
- public:
-  using LocalHandle = pdx::LocalHandle;
-  using LocalChannelHandle = pdx::LocalChannelHandle;
-  template <typename T>
-  using Status = pdx::Status<T>;
-
-  // Create a new consumer channel that is attached to the producer. Returns
-  // a file descriptor for the new channel or a negative error code.
-  Status<LocalChannelHandle> CreateConsumer();
-
-  // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
-  int Poll(int timeout_ms);
-
-  // Locks the area specified by (x, y, width, height) for a specific usage. If
-  // the usage is software then |addr| will be updated to point to the address
-  // of the buffer in virtual memory. The caller should only access/modify the
-  // pixels in the specified area. anything else is undefined behavior.
-  int Lock(int usage, int x, int y, int width, int height, void** addr);
-
-  // Must be called after Lock() when the caller has finished changing the
-  // buffer.
-  int Unlock();
-
-  // Gets a blob buffer that was created with BufferProducer::CreateBlob.
-  // Locking and Unlocking is handled internally. There's no need to Unlock
-  // after calling this method.
-  int GetBlobReadWritePointer(size_t size, void** addr);
-
-  // Gets a blob buffer that was created with BufferProducer::CreateBlob.
-  // Locking and Unlocking is handled internally. There's no need to Unlock
-  // after calling this method.
-  int GetBlobReadOnlyPointer(size_t size, void** addr);
-
-  // Returns a dup'd file descriptor for accessing the blob shared memory. The
-  // caller takes ownership of the file descriptor and must close it or pass on
-  // ownership. Some GPU API extensions can take file descriptors to bind shared
-  // memory gralloc buffers to GPU buffer objects.
-  LocalHandle GetBlobFd() const {
-    // Current GPU vendor puts the buffer allocation in one FD. If we change GPU
-    // vendors and this is the wrong fd, late-latching and EDS will very clearly
-    // stop working and we will need to correct this. The alternative is to use
-    // a GL context in the pose service to allocate this buffer or to use the
-    // ION API directly instead of gralloc.
-    return LocalHandle(dup(native_handle()->data[0]));
-  }
-
-  // Get up to |max_fds_count| file descriptors for accessing the blob shared
-  // memory. |fds_count| will contain the actual number of file descriptors.
-  void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
-
-  using Client::event_fd;
-
-  Status<int> GetEventMask(int events) {
-    if (auto* client_channel = GetChannel()) {
-      return client_channel->GetEventMask(events);
-    } else {
-      return pdx::ErrorStatus(EINVAL);
-    }
-  }
-
-  std::vector<pdx::ClientChannel::EventSource> GetEventSources() const {
-    if (auto* client_channel = GetChannel()) {
-      return client_channel->GetEventSources();
-    } else {
-      return {};
-    }
-  }
-
-  native_handle_t* native_handle() const {
-    return const_cast<native_handle_t*>(buffer_.handle());
-  }
-
-  IonBuffer* buffer() { return &buffer_; }
-  const IonBuffer* buffer() const { return &buffer_; }
-
-  // Gets ID of the buffer client. All BufferHubBuffer clients derived from the
-  // same buffer in bufferhubd share the same buffer id.
-  int id() const { return id_; }
-
-  // Gets the channel id of the buffer client. Each BufferHubBuffer client has
-  // its system unique channel id.
-  int cid() const { return cid_; }
-
-  // Returns the buffer buffer state.
-  uint64_t buffer_state() { return buffer_state_->load(); };
-
-  // A state mask which is unique to a buffer hub client among all its siblings
-  // sharing the same concrete graphic buffer.
-  uint64_t buffer_state_bit() const { return buffer_state_bit_; }
-
-  // The following methods return settings of the first buffer. Currently,
-  // it is only possible to create multi-buffer BufferHubBuffers with the same
-  // settings.
-  uint32_t width() const { return buffer_.width(); }
-  uint32_t height() const { return buffer_.height(); }
-  uint32_t stride() const { return buffer_.stride(); }
-  uint32_t format() const { return buffer_.format(); }
-  uint32_t usage() const { return buffer_.usage(); }
-  uint32_t layer_count() const { return buffer_.layer_count(); }
-
-  uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
-  void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
-
- protected:
-  explicit BufferHubBuffer(LocalChannelHandle channel);
-  explicit BufferHubBuffer(const std::string& endpoint_path);
-  virtual ~BufferHubBuffer();
-
-  // Initialization helper.
-  int ImportBuffer();
-
-  // Check invalid metadata operation. Returns 0 if requested metadata is valid.
-  int CheckMetadata(size_t user_metadata_size) const;
-
-  // Send out the new fence by updating the shared fence (shared_release_fence
-  // for producer and shared_acquire_fence for consumer). Note that during this
-  // should only be used in LocalPost() or LocalRelease, and the shared fence
-  // shouldn't be poll'ed by the other end.
-  int UpdateSharedFence(const LocalHandle& new_fence,
-                        const LocalHandle& shared_fence);
-
-  // IonBuffer that is shared between bufferhubd, producer, and consumers.
-  size_t metadata_buf_size_{0};
-  size_t user_metadata_size_{0};
-  BufferHubDefs::MetadataHeader* metadata_header_{nullptr};
-  void* user_metadata_ptr_{nullptr};
-  std::atomic<uint64_t>* buffer_state_{nullptr};
-  std::atomic<uint64_t>* fence_state_{nullptr};
-
-  LocalHandle shared_acquire_fence_;
-  LocalHandle shared_release_fence_;
-
-  // A local fence fd that holds the ownership of the fence fd on Post (for
-  // producer) and Release (for consumer).
-  LocalHandle pending_fence_fd_;
-
- private:
-  BufferHubBuffer(const BufferHubBuffer&) = delete;
-  void operator=(const BufferHubBuffer&) = delete;
-
-  // Global id for the buffer that is consistent across processes. It is meant
-  // for logging and debugging purposes only and should not be used for lookup
-  // or any other functional purpose as a security precaution.
-  int id_;
-  int cid_;
-  uint64_t buffer_state_bit_{0ULL};
-  IonBuffer buffer_;
-  IonBuffer metadata_buffer_;
-};
-
-// This represents a writable buffer. Calling Post notifies all clients and
-// makes the buffer read-only. Call Gain to acquire write access. A buffer
-// may have many consumers.
-//
-// The user of BufferProducer is responsible with making sure that the Post() is
-// done with the correct metadata type and size. The user is also responsible
-// for making sure that remote ends (BufferConsumers) are also using the correct
-// metadata when acquiring the buffer. The API guarantees that a Post() with a
-// metadata of wrong size will fail. However, it currently does not do any
-// type checking.
-// The API also assumes that metadata is a serializable type (plain old data).
-class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> {
- public:
-  // Imports a bufferhub producer channel, assuming ownership of its handle.
-  static std::unique_ptr<BufferProducer> Import(LocalChannelHandle channel);
-  static std::unique_ptr<BufferProducer> Import(
-      Status<LocalChannelHandle> status);
-
-  // Asynchronously posts a buffer. The fence and metadata are passed to
-  // consumer via shared fd and shared memory.
-  int PostAsync(const DvrNativeBufferMetadata* meta,
-                const LocalHandle& ready_fence);
-
-  // Post this buffer, passing |ready_fence| to the consumers. The bytes in
-  // |meta| are passed unaltered to the consumers. The producer must not modify
-  // the buffer until it is re-gained.
-  // This returns zero or a negative unix error code.
-  int Post(const LocalHandle& ready_fence, const void* meta,
-           size_t user_metadata_size);
-
-  int Post(const LocalHandle& ready_fence) {
-    return Post(ready_fence, nullptr, 0);
-  }
-
-  template <typename Meta, typename = typename std::enable_if<
-                               !std::is_void<Meta>::value>::type>
-  int Post(const LocalHandle& ready_fence, const Meta& meta) {
-    return Post(ready_fence, &meta, sizeof(meta));
-  }
-
-  // Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
-  // must be waited on before using the buffer. If it is not valid then the
-  // buffer is free for immediate use. This call will only succeed if the buffer
-  // is in the released state.
-  // This returns zero or a negative unix error code.
-  int Gain(LocalHandle* release_fence);
-  int GainAsync();
-
-  // Asynchronously marks a released buffer as gained. This method is similar to
-  // the synchronous version above, except that it does not wait for BufferHub
-  // to acknowledge success or failure. Because of the asynchronous nature of
-  // the underlying message, no error is returned if this method is called when
-  // the buffer is in an incorrect state. Returns zero if sending the message
-  // succeeded, or a negative errno code if local error check fails.
-  int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
-
-  // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
-  // be called when a producer buffer has exclusive access to the buffer (i.e.
-  // in the gain'ed state). On the successful return of the IPC call, a new
-  // LocalChannelHandle representing a detached buffer will be returned and all
-  // existing producer and consumer channels will be closed. Further IPCs
-  // towards those channels will return error.
-  Status<LocalChannelHandle> Detach();
-
- private:
-  friend BASE;
-
-  // Constructors are automatically exposed through BufferProducer::Create(...)
-  // static template methods inherited from ClientBase, which take the same
-  // arguments as the constructors.
-
-  // Constructs a buffer with the given geometry and parameters.
-  BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                 uint64_t usage, size_t metadata_size = 0);
-
-  // Constructs a blob (flat) buffer with the given usage flags.
-  BufferProducer(uint64_t usage, size_t size);
-
-  // Imports the given file handle to a producer channel, taking ownership.
-  explicit BufferProducer(LocalChannelHandle channel);
-
-  // Local state transition helpers.
-  int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
-  int LocalPost(const DvrNativeBufferMetadata* meta,
-                const LocalHandle& ready_fence);
-};
-
-// This is a connection to a producer buffer, which can be located in another
-// application. When that buffer is Post()ed, this fd will be signaled and
-// Acquire allows read access. The user is responsible for making sure that
-// Acquire is called with the correct metadata structure. The only guarantee the
-// API currently provides is that an Acquire() with metadata of the wrong size
-// will fail.
-class BufferConsumer : public pdx::ClientBase<BufferConsumer, BufferHubBuffer> {
- public:
-  // This call assumes ownership of |fd|.
-  static std::unique_ptr<BufferConsumer> Import(LocalChannelHandle channel);
-  static std::unique_ptr<BufferConsumer> Import(
-      Status<LocalChannelHandle> status);
-
-  // Attempt to retrieve a post event from buffer hub. If successful,
-  // |ready_fence| will be set to a fence to wait on until the buffer is ready.
-  // This call will only succeed after the fd is signalled. This call may be
-  // performed as an alternative to the Acquire() with metadata. In such cases
-  // the metadata is not read.
-  //
-  // This returns zero or negative unix error code.
-  int Acquire(LocalHandle* ready_fence);
-
-  // Attempt to retrieve a post event from buffer hub. If successful,
-  // |ready_fence| is set to a fence signaling that the contents of the buffer
-  // are available. This call will only succeed if the buffer is in the posted
-  // state.
-  // Returns zero on success, or a negative errno code otherwise.
-  int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
-
-  // Attempt to retrieve a post event from buffer hub. If successful,
-  // |ready_fence| is set to a fence to wait on until the buffer is ready. This
-  // call will only succeed after the fd is signaled. This returns zero or a
-  // negative unix error code.
-  template <typename Meta>
-  int Acquire(LocalHandle* ready_fence, Meta* meta) {
-    return Acquire(ready_fence, meta, sizeof(*meta));
-  }
-
-  // Asynchronously acquires a bufer.
-  int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
-
-  // This should be called after a successful Acquire call. If the fence is
-  // valid the fence determines the buffer usage, otherwise the buffer is
-  // released immediately.
-  // This returns zero or a negative unix error code.
-  int Release(const LocalHandle& release_fence);
-  int ReleaseAsync();
-
-  // Asynchronously releases a buffer. Similar to the synchronous version above,
-  // except that it does not wait for BufferHub to reply with success or error.
-  // The fence and metadata are passed to consumer via shared fd and shared
-  // memory.
-  int ReleaseAsync(const DvrNativeBufferMetadata* meta,
-                   const LocalHandle& release_fence);
-
-  // May be called after or instead of Acquire to indicate that the consumer
-  // does not need to access the buffer this cycle. This returns zero or a
-  // negative unix error code.
-  int Discard();
-
-  // When set, this consumer is no longer notified when this buffer is
-  // available. The system behaves as if Discard() is immediately called
-  // whenever the buffer is posted. If ignore is set to true while a buffer is
-  // pending, it will act as if Discard() was also called.
-  // This returns zero or a negative unix error code.
-  int SetIgnore(bool ignore);
-
- private:
-  friend BASE;
-
-  explicit BufferConsumer(LocalChannelHandle channel);
-
-  // Local state transition helpers.
-  int LocalAcquire(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
-  int LocalRelease(const DvrNativeBufferMetadata* meta,
-                   const LocalHandle& release_fence);
-};
-
 }  // namespace dvr
 }  // namespace android
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_metadata.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_metadata.h
new file mode 100644
index 0000000..980ade7
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_metadata.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DVR_BUFFER_HUB_METADATA_H_
+#define ANDROID_DVR_BUFFER_HUB_METADATA_H_
+
+#include <pdx/file_handle.h>
+#include <private/dvr/buffer_hub_defs.h>
+
+namespace android {
+namespace dvr {
+
+class BufferHubMetadata {
+ public:
+  // Creates a new BufferHubMetadata backed by an ashmem region.
+  //
+  // @param user_metadata_size Size in bytes of the user defined metadata. The
+  //        entire metadata shared memory region to be allocated is the size of
+  //        canonical BufferHubDefs::MetadataHeader plus user_metadata_size.
+  static BufferHubMetadata Create(size_t user_metadata_size);
+
+  // Imports an existing BufferHubMetadata from an ashmem FD.
+  //
+  // TODO(b/112338294): Refactor BufferHub to use Binder as its internal IPC
+  // backend instead of UDS.
+  //
+  // @param ashmem_handle Ashmem file handle representing an ashmem region.
+  static BufferHubMetadata Import(pdx::LocalHandle ashmem_handle);
+
+  BufferHubMetadata() = default;
+
+  BufferHubMetadata(BufferHubMetadata&& other) { *this = std::move(other); }
+
+  ~BufferHubMetadata();
+
+  BufferHubMetadata& operator=(BufferHubMetadata&& other) {
+    if (this != &other) {
+      user_metadata_size_ = other.user_metadata_size_;
+      other.user_metadata_size_ = 0;
+
+      ashmem_handle_ = std::move(other.ashmem_handle_);
+
+      // The old raw metadata_header_ pointer must be cleared, otherwise the
+      // destructor will automatically mummap() the shared memory.
+      metadata_header_ = other.metadata_header_;
+      other.metadata_header_ = nullptr;
+    }
+    return *this;
+  }
+
+  // Returns true if the metadata is valid, i.e. the metadata has a valid ashmem
+  // fd and the ashmem has been mapped into virtual address space.
+  bool IsValid() const {
+    return ashmem_handle_.IsValid() && metadata_header_ != nullptr;
+  }
+
+  size_t user_metadata_size() const { return user_metadata_size_; }
+  size_t metadata_size() const {
+    return user_metadata_size_ + BufferHubDefs::kMetadataHeaderSize;
+  }
+
+  const pdx::LocalHandle& ashmem_handle() const { return ashmem_handle_; }
+  BufferHubDefs::MetadataHeader* metadata_header() { return metadata_header_; }
+
+ private:
+  BufferHubMetadata(size_t user_metadata_size, pdx::LocalHandle ashmem_handle,
+                    BufferHubDefs::MetadataHeader* metadata_header);
+
+  BufferHubMetadata(const BufferHubMetadata&) = delete;
+  void operator=(const BufferHubMetadata&) = delete;
+
+  size_t user_metadata_size_ = 0;
+  pdx::LocalHandle ashmem_handle_;
+  BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFER_HUB_METADATA_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index e163216..1483e16 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -38,8 +38,8 @@
       opaque_ints_.push_back(buffer.handle()->data[fd_count + i]);
     }
   }
-  NativeBufferHandle(NativeBufferHandle&& other) = default;
-  NativeBufferHandle& operator=(NativeBufferHandle&& other) = default;
+  NativeBufferHandle(NativeBufferHandle&& other) noexcept = default;
+  NativeBufferHandle& operator=(NativeBufferHandle&& other) noexcept = default;
 
   // Imports the native handle into the given IonBuffer instance.
   int Import(IonBuffer* buffer) {
@@ -110,16 +110,18 @@
         acquire_fence_fd_(acquire_fence_fd.Borrow()),
         release_fence_fd_(release_fence_fd.Borrow()) {}
 
-  BufferDescription(BufferDescription&& other) = default;
-  BufferDescription& operator=(BufferDescription&& other) = default;
+  BufferDescription(BufferDescription&& other) noexcept = default;
+  BufferDescription& operator=(BufferDescription&& other) noexcept = default;
 
-  // ID of the buffer client. All BufferHubBuffer clients derived from the same
-  // buffer in bufferhubd share the same buffer id.
+  // ID of the buffer client. All BufferHub clients derived from the same buffer
+  // in bufferhubd share the same buffer id.
   int id() const { return id_; }
-  // Channel ID of the buffer client. Each BufferHubBuffer client has its system
+
+  // Channel ID of the buffer client. Each BufferHub client has its system
   // unique channel id.
   int buffer_cid() const { return buffer_cid_; }
-  // State mask of the buffer client. Each BufferHubBuffer client backed by the
+
+  // State mask of the buffer client. Each BufferHub client backed by the
   // same buffer channel has uniqued state bit among its siblings. For a
   // producer buffer the bit must be kProducerStateBit; for a consumer the bit
   // must be one of the kConsumerStateMask.
@@ -159,8 +161,8 @@
   FenceHandle() = default;
   explicit FenceHandle(int fence) : fence_{fence} {}
   explicit FenceHandle(FileHandleType&& fence) : fence_{std::move(fence)} {}
-  FenceHandle(FenceHandle&&) = default;
-  FenceHandle& operator=(FenceHandle&&) = default;
+  FenceHandle(FenceHandle&&) noexcept = default;
+  FenceHandle& operator=(FenceHandle&&) noexcept = default;
 
   explicit operator bool() const { return fence_.IsValid(); }
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
new file mode 100644
index 0000000..089eff8
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
@@ -0,0 +1,100 @@
+#ifndef ANDROID_DVR_CONSUMER_BUFFER_H_
+#define ANDROID_DVR_CONSUMER_BUFFER_H_
+
+#include <private/dvr/buffer_hub_base.h>
+
+namespace android {
+namespace dvr {
+
+// BufferConsumer was originally poorly named and gets easily confused with
+// IGraphicBufferConsumer. Actually, BufferConsumer is a single buffer that can
+// consume (i.e. read) data from a buffer, but it doesn't consume buffer. On
+// the other hand, IGraphicBufferConsumer is the consumer end of a BufferQueue
+// and it is used to consume buffers.
+//
+// TODO(b/116855254): Remove this typedef once rename is complete in other
+// projects and/or branches.
+typedef class ConsumerBuffer BufferConsumer;
+
+// This is a connection to a producer buffer, which can be located in another
+// application. When that buffer is Post()ed, this fd will be signaled and
+// Acquire allows read access. The user is responsible for making sure that
+// Acquire is called with the correct metadata structure. The only guarantee the
+// API currently provides is that an Acquire() with metadata of the wrong size
+// will fail.
+class ConsumerBuffer : public pdx::ClientBase<ConsumerBuffer, BufferHubBase> {
+ public:
+  // This call assumes ownership of |fd|.
+  static std::unique_ptr<ConsumerBuffer> Import(LocalChannelHandle channel);
+  static std::unique_ptr<ConsumerBuffer> Import(
+      Status<LocalChannelHandle> status);
+
+  // Attempt to retrieve a post event from buffer hub. If successful,
+  // |ready_fence| will be set to a fence to wait on until the buffer is ready.
+  // This call will only succeed after the fd is signalled. This call may be
+  // performed as an alternative to the Acquire() with metadata. In such cases
+  // the metadata is not read.
+  //
+  // This returns zero or negative unix error code.
+  int Acquire(LocalHandle* ready_fence);
+
+  // Attempt to retrieve a post event from buffer hub. If successful,
+  // |ready_fence| is set to a fence signaling that the contents of the buffer
+  // are available. This call will only succeed if the buffer is in the posted
+  // state.
+  // Returns zero on success, or a negative errno code otherwise.
+  int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
+
+  // Attempt to retrieve a post event from buffer hub. If successful,
+  // |ready_fence| is set to a fence to wait on until the buffer is ready. This
+  // call will only succeed after the fd is signaled. This returns zero or a
+  // negative unix error code.
+  template <typename Meta>
+  int Acquire(LocalHandle* ready_fence, Meta* meta) {
+    return Acquire(ready_fence, meta, sizeof(*meta));
+  }
+
+  // Asynchronously acquires a bufer.
+  int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+
+  // This should be called after a successful Acquire call. If the fence is
+  // valid the fence determines the buffer usage, otherwise the buffer is
+  // released immediately.
+  // This returns zero or a negative unix error code.
+  int Release(const LocalHandle& release_fence);
+  int ReleaseAsync();
+
+  // Asynchronously releases a buffer. Similar to the synchronous version above,
+  // except that it does not wait for BufferHub to reply with success or error.
+  // The fence and metadata are passed to consumer via shared fd and shared
+  // memory.
+  int ReleaseAsync(const DvrNativeBufferMetadata* meta,
+                   const LocalHandle& release_fence);
+
+  // May be called after or instead of Acquire to indicate that the consumer
+  // does not need to access the buffer this cycle. This returns zero or a
+  // negative unix error code.
+  int Discard();
+
+  // When set, this consumer is no longer notified when this buffer is
+  // available. The system behaves as if Discard() is immediately called
+  // whenever the buffer is posted. If ignore is set to true while a buffer is
+  // pending, it will act as if Discard() was also called.
+  // This returns zero or a negative unix error code.
+  int SetIgnore(bool ignore);
+
+ private:
+  friend BASE;
+
+  explicit ConsumerBuffer(LocalChannelHandle channel);
+
+  // Local state transition helpers.
+  int LocalAcquire(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+  int LocalRelease(const DvrNativeBufferMetadata* meta,
+                   const LocalHandle& release_fence);
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_CONSUMER_BUFFER_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
index f6bc547..860f08a 100644
--- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
@@ -20,8 +20,8 @@
             uint64_t usage);
   ~IonBuffer();
 
-  IonBuffer(IonBuffer&& other);
-  IonBuffer& operator=(IonBuffer&& other);
+  IonBuffer(IonBuffer&& other) noexcept;
+  IonBuffer& operator=(IonBuffer&& other) noexcept;
 
   // Returns check this IonBuffer holds a valid Gralloc buffer.
   bool IsValid() const { return buffer_ && buffer_->initCheck() == NO_ERROR; }
diff --git a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
new file mode 100644
index 0000000..b5e1c5b
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
@@ -0,0 +1,109 @@
+#ifndef ANDROID_DVR_PRODUCER_BUFFER_H_
+#define ANDROID_DVR_PRODUCER_BUFFER_H_
+
+#include <private/dvr/buffer_hub_base.h>
+
+namespace android {
+namespace dvr {
+
+// BufferProducer was originally poorly named and gets easily confused with
+// IGraphicBufferProducer. Actually, BufferProducer is a single buffer that can
+// produce (i.e. write) data into a buffer, but it doesn't produce buffer. On
+// the other hand, IGraphicBufferProducer is the producer end of a BufferQueue
+// and it is used to produce buffers.
+//
+// TODO(b/116855254): Remove this typedef once rename is complete in other
+// projects and/or branches.
+typedef class ProducerBuffer BufferProducer;
+
+// This represents a writable buffer. Calling Post notifies all clients and
+// makes the buffer read-only. Call Gain to acquire write access. A buffer
+// may have many consumers.
+//
+// The user of ProducerBuffer is responsible with making sure that the Post() is
+// done with the correct metadata type and size. The user is also responsible
+// for making sure that remote ends (BufferConsumers) are also using the correct
+// metadata when acquiring the buffer. The API guarantees that a Post() with a
+// metadata of wrong size will fail. However, it currently does not do any
+// type checking.
+// The API also assumes that metadata is a serializable type (plain old data).
+class ProducerBuffer : public pdx::ClientBase<ProducerBuffer, BufferHubBase> {
+ public:
+  // Imports a bufferhub producer channel, assuming ownership of its handle.
+  static std::unique_ptr<ProducerBuffer> Import(LocalChannelHandle channel);
+  static std::unique_ptr<ProducerBuffer> Import(
+      Status<LocalChannelHandle> status);
+
+  // Asynchronously posts a buffer. The fence and metadata are passed to
+  // consumer via shared fd and shared memory.
+  int PostAsync(const DvrNativeBufferMetadata* meta,
+                const LocalHandle& ready_fence);
+
+  // Post this buffer, passing |ready_fence| to the consumers. The bytes in
+  // |meta| are passed unaltered to the consumers. The producer must not modify
+  // the buffer until it is re-gained.
+  // This returns zero or a negative unix error code.
+  int Post(const LocalHandle& ready_fence, const void* meta,
+           size_t user_metadata_size);
+
+  int Post(const LocalHandle& ready_fence) {
+    return Post(ready_fence, nullptr, 0);
+  }
+
+  template <typename Meta, typename = typename std::enable_if<
+                               !std::is_void<Meta>::value>::type>
+  int Post(const LocalHandle& ready_fence, const Meta& meta) {
+    return Post(ready_fence, &meta, sizeof(meta));
+  }
+
+  // Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
+  // must be waited on before using the buffer. If it is not valid then the
+  // buffer is free for immediate use. This call will only succeed if the buffer
+  // is in the released state.
+  // This returns zero or a negative unix error code.
+  int Gain(LocalHandle* release_fence);
+  int GainAsync();
+
+  // Asynchronously marks a released buffer as gained. This method is similar to
+  // the synchronous version above, except that it does not wait for BufferHub
+  // to acknowledge success or failure. Because of the asynchronous nature of
+  // the underlying message, no error is returned if this method is called when
+  // the buffer is in an incorrect state. Returns zero if sending the message
+  // succeeded, or a negative errno code if local error check fails.
+  int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+
+  // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
+  // be called when a producer buffer has exclusive access to the buffer (i.e.
+  // in the gain'ed state). On the successful return of the IPC call, a new
+  // LocalChannelHandle representing a detached buffer will be returned and all
+  // existing producer and consumer channels will be closed. Further IPCs
+  // towards those channels will return error.
+  Status<LocalChannelHandle> Detach();
+
+ private:
+  friend BASE;
+
+  // Constructors are automatically exposed through ProducerBuffer::Create(...)
+  // static template methods inherited from ClientBase, which take the same
+  // arguments as the constructors.
+
+  // Constructs a buffer with the given geometry and parameters.
+  ProducerBuffer(uint32_t width, uint32_t height, uint32_t format,
+                 uint64_t usage, size_t metadata_size = 0);
+
+  // Constructs a blob (flat) buffer with the given usage flags.
+  ProducerBuffer(uint64_t usage, size_t size);
+
+  // Imports the given file handle to a producer channel, taking ownership.
+  explicit ProducerBuffer(LocalChannelHandle channel);
+
+  // Local state transition helpers.
+  int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+  int LocalPost(const DvrNativeBufferMetadata* meta,
+                const LocalHandle& ready_fence);
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_PRODUCER_BUFFER_H_
diff --git a/libs/vr/libbufferhub/ion_buffer.cpp b/libs/vr/libbufferhub/ion_buffer.cpp
index cbaa24a..1295531 100644
--- a/libs/vr/libbufferhub/ion_buffer.cpp
+++ b/libs/vr/libbufferhub/ion_buffer.cpp
@@ -49,11 +49,11 @@
   FreeHandle();
 }
 
-IonBuffer::IonBuffer(IonBuffer&& other) : IonBuffer() {
+IonBuffer::IonBuffer(IonBuffer&& other) noexcept : IonBuffer() {
   *this = std::move(other);
 }
 
-IonBuffer& IonBuffer::operator=(IonBuffer&& other) {
+IonBuffer& IonBuffer::operator=(IonBuffer&& other) noexcept {
   ALOGD_IF(TRACE, "IonBuffer::operator=: handle_=%p other.handle_=%p", handle(),
            other.handle());
 
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
new file mode 100644
index 0000000..c4f1a3b
--- /dev/null
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -0,0 +1,243 @@
+#include <private/dvr/producer_buffer.h>
+
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+
+namespace android {
+namespace dvr {
+
+ProducerBuffer::ProducerBuffer(uint32_t width, uint32_t height, uint32_t format,
+                               uint64_t usage, size_t user_metadata_size)
+    : BASE(BufferHubRPC::kClientPath) {
+  ATRACE_NAME("ProducerBuffer::ProducerBuffer");
+  ALOGD_IF(TRACE,
+           "ProducerBuffer::ProducerBuffer: fd=%d width=%u height=%u format=%u "
+           "usage=%" PRIx64 " user_metadata_size=%zu",
+           event_fd(), width, height, format, usage, user_metadata_size);
+
+  auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
+      width, height, format, usage, user_metadata_size);
+  if (!status) {
+    ALOGE(
+        "ProducerBuffer::ProducerBuffer: Failed to create producer buffer: %s",
+        status.GetErrorMessage().c_str());
+    Close(-status.error());
+    return;
+  }
+
+  const int ret = ImportBuffer();
+  if (ret < 0) {
+    ALOGE(
+        "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s",
+        strerror(-ret));
+    Close(ret);
+  }
+}
+
+ProducerBuffer::ProducerBuffer(uint64_t usage, size_t size)
+    : BASE(BufferHubRPC::kClientPath) {
+  ATRACE_NAME("ProducerBuffer::ProducerBuffer");
+  ALOGD_IF(TRACE, "ProducerBuffer::ProducerBuffer: usage=%" PRIx64 " size=%zu",
+           usage, size);
+  const int width = static_cast<int>(size);
+  const int height = 1;
+  const int format = HAL_PIXEL_FORMAT_BLOB;
+  const size_t user_metadata_size = 0;
+
+  auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
+      width, height, format, usage, user_metadata_size);
+  if (!status) {
+    ALOGE("ProducerBuffer::ProducerBuffer: Failed to create blob: %s",
+          status.GetErrorMessage().c_str());
+    Close(-status.error());
+    return;
+  }
+
+  const int ret = ImportBuffer();
+  if (ret < 0) {
+    ALOGE(
+        "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s",
+        strerror(-ret));
+    Close(ret);
+  }
+}
+
+ProducerBuffer::ProducerBuffer(LocalChannelHandle channel)
+    : BASE(std::move(channel)) {
+  const int ret = ImportBuffer();
+  if (ret < 0) {
+    ALOGE(
+        "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s",
+        strerror(-ret));
+    Close(ret);
+  }
+}
+
+int ProducerBuffer::LocalPost(const DvrNativeBufferMetadata* meta,
+                              const LocalHandle& ready_fence) {
+  if (const int error = CheckMetadata(meta->user_metadata_size))
+    return error;
+
+  // Check invalid state transition.
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+    ALOGE("ProducerBuffer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
+          id(), buffer_state);
+    return -EBUSY;
+  }
+
+  // Copy the canonical metadata.
+  void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
+  memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata));
+  // Copy extra user requested metadata.
+  if (meta->user_metadata_ptr && meta->user_metadata_size) {
+    void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
+    memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
+  }
+
+  // Send out the acquire fence through the shared epoll fd. Note that during
+  // posting no consumer is not expected to be polling on the fence.
+  if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_))
+    return error;
+
+  // Set the producer bit atomically to transit into posted state.
+  BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
+                                   BufferHubDefs::kProducerStateBit);
+  return 0;
+}
+
+int ProducerBuffer::Post(const LocalHandle& ready_fence, const void* meta,
+                         size_t user_metadata_size) {
+  ATRACE_NAME("ProducerBuffer::Post");
+
+  // Populate cononical metadata for posting.
+  DvrNativeBufferMetadata canonical_meta;
+  canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta);
+  canonical_meta.user_metadata_size = user_metadata_size;
+
+  if (const int error = LocalPost(&canonical_meta, ready_fence))
+    return error;
+
+  return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>(
+      BorrowedFence(ready_fence.Borrow())));
+}
+
+int ProducerBuffer::PostAsync(const DvrNativeBufferMetadata* meta,
+                              const LocalHandle& ready_fence) {
+  ATRACE_NAME("ProducerBuffer::PostAsync");
+
+  if (const int error = LocalPost(meta, ready_fence))
+    return error;
+
+  return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode));
+}
+
+int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
+                              LocalHandle* out_fence) {
+  uint64_t buffer_state = buffer_state_->load();
+  ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
+           id(), buffer_state);
+
+  if (!out_meta)
+    return -EINVAL;
+
+  if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
+    if (BufferHubDefs::IsBufferGained(buffer_state)) {
+      // We don't want to log error when gaining a newly allocated
+      // buffer.
+      ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
+      return -EALREADY;
+    }
+    ALOGE("ProducerBuffer::LocalGain: not released id=%d state=%" PRIx64 ".",
+          id(), buffer_state);
+    return -EBUSY;
+  }
+
+  // Canonical metadata is undefined on Gain. Except for user_metadata and
+  // release_fence_mask. Fill in the user_metadata_ptr in address space of the
+  // local process.
+  if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) {
+    out_meta->user_metadata_size =
+        metadata_header_->metadata.user_metadata_size;
+    out_meta->user_metadata_ptr =
+        reinterpret_cast<uint64_t>(user_metadata_ptr_);
+  } else {
+    out_meta->user_metadata_size = 0;
+    out_meta->user_metadata_ptr = 0;
+  }
+
+  uint64_t fence_state = fence_state_->load();
+  // If there is an release fence from consumer, we need to return it.
+  if (fence_state & BufferHubDefs::kConsumerStateMask) {
+    *out_fence = shared_release_fence_.Duplicate();
+    out_meta->release_fence_mask =
+        fence_state & BufferHubDefs::kConsumerStateMask;
+  }
+
+  // Clear out all bits and the buffer is now back to gained state.
+  buffer_state_->store(0ULL);
+  return 0;
+}
+
+int ProducerBuffer::Gain(LocalHandle* release_fence) {
+  ATRACE_NAME("ProducerBuffer::Gain");
+
+  DvrNativeBufferMetadata meta;
+  if (const int error = LocalGain(&meta, release_fence))
+    return error;
+
+  auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
+  if (!status)
+    return -status.error();
+  return 0;
+}
+
+int ProducerBuffer::GainAsync(DvrNativeBufferMetadata* out_meta,
+                              LocalHandle* release_fence) {
+  ATRACE_NAME("ProducerBuffer::GainAsync");
+
+  if (const int error = LocalGain(out_meta, release_fence))
+    return error;
+
+  return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
+}
+
+int ProducerBuffer::GainAsync() {
+  DvrNativeBufferMetadata meta;
+  LocalHandle fence;
+  return GainAsync(&meta, &fence);
+}
+
+std::unique_ptr<ProducerBuffer> ProducerBuffer::Import(
+    LocalChannelHandle channel) {
+  ALOGD_IF(TRACE, "ProducerBuffer::Import: channel=%d", channel.value());
+  return ProducerBuffer::Create(std::move(channel));
+}
+
+std::unique_ptr<ProducerBuffer> ProducerBuffer::Import(
+    Status<LocalChannelHandle> status) {
+  return Import(status ? status.take()
+                       : LocalChannelHandle{nullptr, -status.error()});
+}
+
+Status<LocalChannelHandle> ProducerBuffer::Detach() {
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+    // Can only detach a ProducerBuffer when it's in gained state.
+    ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx64
+          ") is not in gained state.",
+          id(), buffer_state);
+    return {};
+  }
+
+  Status<LocalChannelHandle> status =
+      InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
+  ALOGE_IF(!status,
+           "ProducerBuffer::Detach: Failed to detach buffer (id=%d): %s.", id(),
+           status.GetErrorMessage().c_str());
+  return status;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 44276ba..e1c1aa9 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -278,7 +278,7 @@
 }
 
 Status<void> BufferHubQueue::AddBuffer(
-    const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
+    const std::shared_ptr<BufferHubBase>& buffer, size_t slot) {
   ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu",
            buffer->id(), slot);
 
@@ -356,8 +356,8 @@
   }
 }
 
-Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(int timeout,
-                                                                 size_t* slot) {
+Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout,
+                                                               size_t* slot) {
   ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
            timeout);
 
@@ -372,7 +372,7 @@
   PDX_TRACE_FORMAT("buffer|buffer_id=%d;slot=%zu|", entry.buffer->id(),
                    entry.slot);
 
-  std::shared_ptr<BufferHubBuffer> buffer = std::move(entry.buffer);
+  std::shared_ptr<BufferHubBase> buffer = std::move(entry.buffer);
   *slot = entry.slot;
 
   available_buffers_.pop();
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 df500b4..c69002d 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
@@ -31,13 +31,13 @@
 
 class ConsumerQueue;
 
-// |BufferHubQueue| manages a queue of |BufferHubBuffer|s. Buffers are
+// |BufferHubQueue| manages a queue of |BufferHubBase|s. Buffers are
 // automatically re-requeued when released by the remote side.
 class BufferHubQueue : public pdx::Client {
  public:
   using BufferAvailableCallback = std::function<void()>;
   using BufferRemovedCallback =
-      std::function<void(const std::shared_ptr<BufferHubBuffer>&)>;
+      std::function<void(const std::shared_ptr<BufferHubBase>&)>;
 
   virtual ~BufferHubQueue() {}
 
@@ -93,7 +93,7 @@
                                                       : -1;
   }
 
-  std::shared_ptr<BufferHubBuffer> GetBuffer(size_t slot) const {
+  std::shared_ptr<BufferHubBase> GetBuffer(size_t slot) const {
     return buffers_[slot];
   }
 
@@ -142,7 +142,7 @@
 
   // Register a buffer for management by the queue. Used by subclasses to add a
   // buffer to internal bookkeeping.
-  pdx::Status<void> AddBuffer(const std::shared_ptr<BufferHubBuffer>& buffer,
+  pdx::Status<void> AddBuffer(const std::shared_ptr<BufferHubBase>& buffer,
                               size_t slot);
 
   // Called by ProducerQueue::RemoveBuffer and ConsumerQueue::RemoveBuffer only
@@ -158,8 +158,8 @@
   // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely,
   // while specifying a timeout equal to zero cause Dequeue() to return
   // immediately, even if no buffers are available.
-  pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(int timeout,
-                                                        size_t* slot);
+  pdx::Status<std::shared_ptr<BufferHubBase>> Dequeue(int timeout,
+                                                      size_t* slot);
 
   // Waits for buffers to become available and adds them to the available queue.
   bool WaitForBuffers(int timeout);
@@ -172,10 +172,10 @@
   // per-buffer data.
   struct Entry {
     Entry() : slot(0) {}
-    Entry(const std::shared_ptr<BufferHubBuffer>& in_buffer, size_t in_slot,
+    Entry(const std::shared_ptr<BufferHubBase>& in_buffer, size_t in_slot,
           uint64_t in_index)
         : buffer(in_buffer), slot(in_slot), index(in_index) {}
-    Entry(const std::shared_ptr<BufferHubBuffer>& in_buffer,
+    Entry(const std::shared_ptr<BufferHubBase>& in_buffer,
           std::unique_ptr<uint8_t[]> in_metadata, pdx::LocalHandle in_fence,
           size_t in_slot)
         : buffer(in_buffer),
@@ -185,7 +185,7 @@
     Entry(Entry&&) = default;
     Entry& operator=(Entry&&) = default;
 
-    std::shared_ptr<BufferHubBuffer> buffer;
+    std::shared_ptr<BufferHubBase> buffer;
     std::unique_ptr<uint8_t[]> metadata;
     pdx::LocalHandle fence;
     size_t slot;
@@ -250,7 +250,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::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_;
+  std::array<std::shared_ptr<BufferHubBase>, kMaxQueueCapacity> buffers_;
 
   // Buffers and related data that are available for dequeue.
   std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
index 4dea9b2..ad3f56b 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
@@ -28,8 +28,8 @@
  public:
   BufferHubQueueParcelable() = default;
 
-  BufferHubQueueParcelable(BufferHubQueueParcelable&& other) = default;
-  BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) {
+  BufferHubQueueParcelable(BufferHubQueueParcelable&& other) noexcept = default;
+  BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) noexcept {
     channel_parcelable_ = std::move(other.channel_parcelable_);
     return *this;
   }
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 571558a..f4c6600 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -9,7 +9,7 @@
 
 using namespace android;
 using android::dvr::BufferConsumer;
-using android::dvr::BufferHubBuffer;
+using android::dvr::BufferHubBase;
 using android::dvr::BufferProducer;
 using android::dvr::ConsumerQueue;
 using android::dvr::ProducerQueue;
@@ -439,7 +439,7 @@
     consumer_queue_->SetBufferRemovedCallback(nullptr);
   } else {
     consumer_queue_->SetBufferRemovedCallback(
-        [callback, context](const std::shared_ptr<BufferHubBuffer>& buffer) {
+        [callback, context](const std::shared_ptr<BufferHubBase>& buffer) {
           // When buffer is removed from the queue, the slot is already invalid.
           auto read_buffer = std::make_unique<DvrReadBuffer>();
           read_buffer->read_buffer =
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
index de8bb96..df8125a 100644
--- a/libs/vr/libdvr/dvr_internal.h
+++ b/libs/vr/libdvr/dvr_internal.h
@@ -16,8 +16,11 @@
 namespace android {
 namespace dvr {
 
-class BufferProducer;
-class BufferConsumer;
+// TODO(b/116855254): Remove this typedef once rename is complete in libdvr.
+// Note that the dvr::BufferProducer and dvr::BufferConsumer were poorly named,
+// they should really be named as ProducerBuffer and ConsumerBuffer.
+typedef class ProducerBuffer BufferProducer;
+typedef class ConsumerBuffer BufferConsumer;
 class IonBuffer;
 
 DvrBuffer* CreateDvrBufferFromIonBuffer(
diff --git a/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h b/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
index 44485a7..1824241 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
+++ b/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
@@ -23,9 +23,9 @@
   explicit RingBuffer(size_t capacity) { Reset(capacity); }
 
   RingBuffer(const RingBuffer& other) = default;
-  RingBuffer(RingBuffer&& other) = default;
+  RingBuffer(RingBuffer&& other) noexcept = default;
   RingBuffer& operator=(const RingBuffer& other) = default;
-  RingBuffer& operator=(RingBuffer&& other) = default;
+  RingBuffer& operator=(RingBuffer&& other) noexcept = default;
 
   void Append(const T& val) {
     if (IsFull())
diff --git a/libs/vr/libpdx/private/pdx/channel_handle.h b/libs/vr/libpdx/private/pdx/channel_handle.h
index 1e62d25..daa08f4 100644
--- a/libs/vr/libpdx/private/pdx/channel_handle.h
+++ b/libs/vr/libpdx/private/pdx/channel_handle.h
@@ -50,14 +50,14 @@
  public:
   ChannelHandle() = default;
   using ChannelHandleBase::ChannelHandleBase;
-  ChannelHandle(ChannelHandle&& other) : ChannelHandleBase{other.value_} {
+  ChannelHandle(ChannelHandle&& other) noexcept : ChannelHandleBase{other.value_} {
     other.value_ = kEmptyHandle;
   }
   ~ChannelHandle() = default;
 
   ChannelHandle Duplicate() const { return ChannelHandle{value_}; }
 
-  ChannelHandle& operator=(ChannelHandle&& other) {
+  ChannelHandle& operator=(ChannelHandle&& other) noexcept {
     value_ = other.value_;
     other.value_ = kEmptyHandle;
     return *this;
@@ -74,13 +74,13 @@
   ChannelHandle(const ChannelHandle&) = delete;
   ChannelHandle& operator=(const ChannelHandle&) = delete;
 
-  ChannelHandle(ChannelHandle&& other)
+  ChannelHandle(ChannelHandle&& other) noexcept
       : ChannelHandleBase{other.value_}, manager_{other.manager_} {
     other.manager_ = nullptr;
     other.value_ = kEmptyHandle;
   }
 
-  ChannelHandle& operator=(ChannelHandle&& other) {
+  ChannelHandle& operator=(ChannelHandle&& other) noexcept {
     value_ = other.value_;
     manager_ = other.manager_;
     other.value_ = kEmptyHandle;
diff --git a/libs/vr/libpdx/private/pdx/file_handle.h b/libs/vr/libpdx/private/pdx/file_handle.h
index b3c3ad7..fed1529 100644
--- a/libs/vr/libpdx/private/pdx/file_handle.h
+++ b/libs/vr/libpdx/private/pdx/file_handle.h
@@ -43,7 +43,7 @@
 
   // Move constructor that assumes ownership of the file descriptor, leaving the
   // other FileHandle object empty.
-  FileHandle(FileHandle&& other) {
+  FileHandle(FileHandle&& other) noexcept {
     fd_ = other.fd_;
     other.fd_ = kEmptyFileHandle;
   }
@@ -62,7 +62,7 @@
 
   // Move assignment operator that assumes ownership of the underlying file
   // descriptor, leaving the other FileHandle object empty.
-  FileHandle& operator=(FileHandle&& other) {
+  FileHandle& operator=(FileHandle&& other) noexcept {
     if (this != &other) {
       Reset(other.fd_);
       other.fd_ = kEmptyFileHandle;
diff --git a/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
index 93d87f3..d835c57 100644
--- a/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
@@ -39,7 +39,7 @@
 
   ArrayWrapper(const ArrayWrapper& other) { *this = other; }
 
-  ArrayWrapper(ArrayWrapper&& other) { *this = std::move(other); }
+  ArrayWrapper(ArrayWrapper&& other) noexcept { *this = std::move(other); }
 
   ArrayWrapper& operator=(const ArrayWrapper& other) {
     if (&other == this) {
@@ -53,7 +53,7 @@
     return *this;
   }
 
-  ArrayWrapper& operator=(ArrayWrapper&& other) {
+  ArrayWrapper& operator=(ArrayWrapper&& other) noexcept {
     if (&other == this) {
       return *this;
     } else {
diff --git a/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
index aa86531..0421220 100644
--- a/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
@@ -39,7 +39,7 @@
 
   BufferWrapper(const BufferWrapper& other) { *this = other; }
 
-  BufferWrapper(BufferWrapper&& other) { *this = std::move(other); }
+  BufferWrapper(BufferWrapper&& other) noexcept { *this = std::move(other); }
 
   BufferWrapper& operator=(const BufferWrapper& other) {
     if (&other == this) {
@@ -53,7 +53,7 @@
     return *this;
   }
 
-  BufferWrapper& operator=(BufferWrapper&& other) {
+  BufferWrapper& operator=(BufferWrapper&& other) noexcept {
     if (&other == this) {
       return *this;
     } else {
@@ -117,9 +117,9 @@
   BufferWrapper(BufferType&& buffer, const Allocator& allocator)
       : buffer_(std::move(buffer), allocator) {}
   BufferWrapper(const BufferWrapper&) = default;
-  BufferWrapper(BufferWrapper&&) = default;
+  BufferWrapper(BufferWrapper&&) noexcept = default;
   BufferWrapper& operator=(const BufferWrapper&) = default;
-  BufferWrapper& operator=(BufferWrapper&&) = default;
+  BufferWrapper& operator=(BufferWrapper&&) noexcept = default;
 
   pointer data() { return buffer_.data(); }
   const_pointer data() const { return buffer_.data(); }
diff --git a/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
index d496719..1cb85de 100644
--- a/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
@@ -15,9 +15,9 @@
 
   PointerWrapper(T* pointer) : pointer_(pointer) {}
   PointerWrapper(const PointerWrapper&) = default;
-  PointerWrapper(PointerWrapper&&) = default;
+  PointerWrapper(PointerWrapper&&) noexcept = default;
   PointerWrapper& operator=(const PointerWrapper&) = default;
-  PointerWrapper& operator=(PointerWrapper&&) = default;
+  PointerWrapper& operator=(PointerWrapper&&) noexcept = default;
 
   T& Dereference() { return *pointer_; }
   const T& Dereference() const { return *pointer_; }
diff --git a/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
index 19fc4c1..2d0a4ea 100644
--- a/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
@@ -44,7 +44,7 @@
 
   StringWrapper(const StringWrapper& other) { *this = other; }
 
-  StringWrapper(StringWrapper&& other) { *this = std::move(other); }
+  StringWrapper(StringWrapper&& other) noexcept { *this = std::move(other); }
 
   StringWrapper& operator=(const StringWrapper& other) {
     if (&other == this) {
@@ -58,7 +58,7 @@
     return *this;
   }
 
-  StringWrapper& operator=(StringWrapper&& other) {
+  StringWrapper& operator=(StringWrapper&& other) noexcept {
     if (&other == this) {
       return *this;
     } else {
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index 0a4802e..a1292b0 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -447,7 +447,7 @@
 
   Variant(const Variant& other)
       : index_{other.index_}, value_{other.value_, other.index_} {}
-  Variant(Variant&& other)
+  Variant(Variant&& other) noexcept
       : index_{other.index_}, value_{std::move(other.value_), other.index_} {}
 
 // Recent Clang versions has a regression that produces bogus
@@ -472,7 +472,7 @@
     other.Visit([this](const auto& value) { *this = value; });
     return *this;
   }
-  Variant& operator=(Variant&& other) {
+  Variant& operator=(Variant&& other) noexcept {
     other.Visit([this](auto&& value) { *this = std::move(value); });
     return *this;
   }
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 15fa327..d38b174 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -101,8 +101,8 @@
   /*
    * Message objects support move construction and assignment.
    */
-  Message(Message&& other);
-  Message& operator=(Message&& other);
+  Message(Message&& other) noexcept;
+  Message& operator=(Message&& other) noexcept;
 
   /*
    * Read/write payload, in either single buffer or iovec form.
diff --git a/libs/vr/libpdx/private/pdx/status.h b/libs/vr/libpdx/private/pdx/status.h
index 067fe25..7e51a52 100644
--- a/libs/vr/libpdx/private/pdx/status.h
+++ b/libs/vr/libpdx/private/pdx/status.h
@@ -41,14 +41,14 @@
   // Copy/move constructors. Move constructor leaves |other| object in empty
   // state.
   Status(const Status& other) = default;
-  Status(Status&& other)
+  Status(Status&& other) noexcept
       : value_{std::move(other.value_)}, error_{other.error_} {
     other.error_ = -1;
   }
 
   // Assignment operators.
   Status& operator=(const Status& other) = default;
-  Status& operator=(Status&& other) {
+  Status& operator=(Status&& other) noexcept {
     error_ = other.error_;
     value_ = std::move(other.value_);
     other.error_ = -1;
diff --git a/libs/vr/libpdx/private/pdx/utility.h b/libs/vr/libpdx/private/pdx/utility.h
index 08fcaea..c9a0c21 100644
--- a/libs/vr/libpdx/private/pdx/utility.h
+++ b/libs/vr/libpdx/private/pdx/utility.h
@@ -33,7 +33,7 @@
     return *this;
   }
 
-  ByteBuffer& operator=(ByteBuffer&& other) {
+  ByteBuffer& operator=(ByteBuffer&& other) noexcept {
     std::swap(data_, other.data_);
     std::swap(size_, other.size_);
     std::swap(capacity_, other.capacity_);
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index 1d3b62a..68b8dd7 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -31,9 +31,9 @@
 
 // C++11 specifies the move semantics for shared_ptr but not weak_ptr. This
 // means we have to manually implement the desired move semantics for Message.
-Message::Message(Message&& other) { *this = std::move(other); }
+Message::Message(Message&& other) noexcept { *this = std::move(other); }
 
-Message& Message::operator=(Message&& other) {
+Message& Message::operator=(Message&& other) noexcept {
   Destroy();
   auto base = reinterpret_cast<std::uint8_t*>(&info_);
   std::fill(&base[0], &base[sizeof(info_)], 0);
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index 9614c6d..5d873d1 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -31,13 +31,13 @@
   }
 }
 
-AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) {
+AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) noexcept {
   *this = std::move(other);
 }
 
 AcquiredBuffer::~AcquiredBuffer() { Release(LocalHandle(kEmptyFence)); }
 
-AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) {
+AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) noexcept {
   if (this != &other) {
     Release();
 
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index 32e912a..1a200aa 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -31,7 +31,7 @@
   AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer, int* error);
 
   // Move constructor. Behaves similarly to the move assignment operator below.
-  AcquiredBuffer(AcquiredBuffer&& other);
+  AcquiredBuffer(AcquiredBuffer&& other) noexcept;
 
   ~AcquiredBuffer();
 
@@ -39,7 +39,7 @@
   // |other| into this instance after RELEASING the current BufferConsumer and
   // closing the acquire fence. After the move |other| is left in the empty
   // state.
-  AcquiredBuffer& operator=(AcquiredBuffer&& other);
+  AcquiredBuffer& operator=(AcquiredBuffer&& other) noexcept;
 
   // Accessors for the underlying BufferConsumer, the acquire fence, and the
   // use-case specific sequence value from the acquisition (see
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index e98d592..5f6455c 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1338,9 +1338,9 @@
 
 Layer::~Layer() { Reset(); }
 
-Layer::Layer(Layer&& other) { *this = std::move(other); }
+Layer::Layer(Layer&& other) noexcept { *this = std::move(other); }
 
-Layer& Layer::operator=(Layer&& other) {
+Layer& Layer::operator=(Layer&& other) noexcept {
   if (this != &other) {
     Reset();
     using std::swap;
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 80fa7ac..94a2337 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -87,8 +87,8 @@
         const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
         HWC::Composition composition_type, size_t z_order);
 
-  Layer(Layer&&);
-  Layer& operator=(Layer&&);
+  Layer(Layer&&) noexcept;
+  Layer& operator=(Layer&&) noexcept;
 
   ~Layer();
 
diff --git a/opengl/include/EGL/Platform.h b/opengl/include/EGL/Platform.h
new file mode 100644
index 0000000..624d31f
--- /dev/null
+++ b/opengl/include/EGL/Platform.h
@@ -0,0 +1,329 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Platform.h: The public interface ANGLE exposes to the API layer, for
+//   doing platform-specific tasks like gathering data, or for tracing.
+
+#ifndef ANGLE_PLATFORM_H
+#define ANGLE_PLATFORM_H
+
+#include <stdint.h>
+#include <array>
+
+#define EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX 0x3482
+
+#if defined(_WIN32)
+#   if !defined(LIBANGLE_IMPLEMENTATION)
+#       define ANGLE_PLATFORM_EXPORT __declspec(dllimport)
+#   else
+#       define ANGLE_PLATFORM_EXPORT __declspec(dllexport)
+#   endif
+#elif defined(__GNUC__) || defined(__clang__)
+#   define ANGLE_PLATFORM_EXPORT __attribute__((visibility ("default")))
+#endif
+#if !defined(ANGLE_PLATFORM_EXPORT)
+#   define ANGLE_PLATFORM_EXPORT
+#endif
+
+#if defined(_WIN32)
+#   define ANGLE_APIENTRY __stdcall
+#else
+#   define ANGLE_APIENTRY
+#endif
+
+namespace angle
+{
+struct WorkaroundsD3D;
+using TraceEventHandle = uint64_t;
+using EGLDisplayType   = void *;
+struct PlatformMethods;
+
+// Use a C-like API to not trigger undefined calling behaviour.
+// Avoid using decltype here to work around sanitizer limitations.
+// TODO(jmadill): Use decltype here if/when UBSAN is fixed.
+
+// System --------------------------------------------------------------
+
+// Wall clock time in seconds since the epoch.
+// TODO(jmadill): investigate using an ANGLE internal time library
+using CurrentTimeFunc = double (*)(PlatformMethods *platform);
+inline double DefaultCurrentTime(PlatformMethods *platform)
+{
+    return 0.0;
+}
+
+// Monotonically increasing time in seconds from an arbitrary fixed point in the past.
+// This function is expected to return at least millisecond-precision values. For this reason,
+// it is recommended that the fixed point be no further in the past than the epoch.
+using MonotonicallyIncreasingTimeFunc = double (*)(PlatformMethods *platform);
+inline double DefaultMonotonicallyIncreasingTime(PlatformMethods *platform)
+{
+    return 0.0;
+}
+
+// Logging ------------------------------------------------------------
+
+// Log an error message within the platform implementation.
+using LogErrorFunc = void (*)(PlatformMethods *platform, const char *errorMessage);
+inline void DefaultLogError(PlatformMethods *platform, const char *errorMessage)
+{
+}
+
+// Log a warning message within the platform implementation.
+using LogWarningFunc = void (*)(PlatformMethods *platform, const char *warningMessage);
+inline void DefaultLogWarning(PlatformMethods *platform, const char *warningMessage)
+{
+}
+
+// Log an info message within the platform implementation.
+using LogInfoFunc = void (*)(PlatformMethods *platform, const char *infoMessage);
+inline void DefaultLogInfo(PlatformMethods *platform, const char *infoMessage)
+{
+}
+
+// Tracing --------
+
+// Get a pointer to the enabled state of the given trace category. The
+// embedder can dynamically change the enabled state as trace event
+// recording is started and stopped by the application. Only long-lived
+// literal strings should be given as the category name. The implementation
+// expects the returned pointer to be held permanently in a local static. If
+// the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
+// addTraceEvent is expected to be called by the trace event macros.
+using GetTraceCategoryEnabledFlagFunc = const unsigned char *(*)(PlatformMethods *platform,
+                                                                 const char *categoryName);
+inline const unsigned char *DefaultGetTraceCategoryEnabledFlag(PlatformMethods *platform,
+                                                               const char *categoryName)
+{
+    return nullptr;
+}
+
+//
+// Add a trace event to the platform tracing system. Depending on the actual
+// enabled state, this event may be recorded or dropped.
+// - phase specifies the type of event:
+//   - BEGIN ('B'): Marks the beginning of a scoped event.
+//   - END ('E'): Marks the end of a scoped event.
+//   - COMPLETE ('X'): Marks the beginning of a scoped event, but doesn't
+//     need a matching END event. Instead, at the end of the scope,
+//     updateTraceEventDuration() must be called with the TraceEventHandle
+//     returned from addTraceEvent().
+//   - INSTANT ('I'): Standalone, instantaneous event.
+//   - START ('S'): Marks the beginning of an asynchronous event (the end
+//     event can occur in a different scope or thread). The id parameter is
+//     used to match START/FINISH pairs.
+//   - FINISH ('F'): Marks the end of an asynchronous event.
+//   - COUNTER ('C'): Used to trace integer quantities that change over
+//     time. The argument values are expected to be of type int.
+//   - METADATA ('M'): Reserved for internal use.
+// - categoryEnabled is the pointer returned by getTraceCategoryEnabledFlag.
+// - name is the name of the event. Also used to match BEGIN/END and
+//   START/FINISH pairs.
+// - id optionally allows events of the same name to be distinguished from
+//   each other. For example, to trace the construction and destruction of
+//   objects, specify the pointer as the id parameter.
+// - timestamp should be a time value returned from monotonicallyIncreasingTime.
+// - numArgs specifies the number of elements in argNames, argTypes, and
+//   argValues.
+// - argNames is the array of argument names. Use long-lived literal strings
+//   or specify the COPY flag.
+// - argTypes is the array of argument types:
+//   - BOOL (1): bool
+//   - UINT (2): unsigned long long
+//   - INT (3): long long
+//   - DOUBLE (4): double
+//   - POINTER (5): void*
+//   - STRING (6): char* (long-lived null-terminated char* string)
+//   - COPY_STRING (7): char* (temporary null-terminated char* string)
+//   - CONVERTABLE (8): WebConvertableToTraceFormat
+// - argValues is the array of argument values. Each value is the unsigned
+//   long long member of a union of all supported types.
+// - flags can be 0 or one or more of the following, ORed together:
+//   - COPY (0x1): treat all strings (name, argNames and argValues of type
+//     string) as temporary so that they will be copied by addTraceEvent.
+//   - HAS_ID (0x2): use the id argument to uniquely identify the event for
+//     matching with other events of the same name.
+//   - MANGLE_ID (0x4): specify this flag if the id parameter is the value
+//     of a pointer.
+using AddTraceEventFunc = angle::TraceEventHandle (*)(PlatformMethods *platform,
+                                                      char phase,
+                                                      const unsigned char *categoryEnabledFlag,
+                                                      const char *name,
+                                                      unsigned long long id,
+                                                      double timestamp,
+                                                      int numArgs,
+                                                      const char **argNames,
+                                                      const unsigned char *argTypes,
+                                                      const unsigned long long *argValues,
+                                                      unsigned char flags);
+inline angle::TraceEventHandle DefaultAddTraceEvent(PlatformMethods *platform,
+                                                    char phase,
+                                                    const unsigned char *categoryEnabledFlag,
+                                                    const char *name,
+                                                    unsigned long long id,
+                                                    double timestamp,
+                                                    int numArgs,
+                                                    const char **argNames,
+                                                    const unsigned char *argTypes,
+                                                    const unsigned long long *argValues,
+                                                    unsigned char flags)
+{
+    return 0;
+}
+
+// Set the duration field of a COMPLETE trace event.
+using UpdateTraceEventDurationFunc = void (*)(PlatformMethods *platform,
+                                              const unsigned char *categoryEnabledFlag,
+                                              const char *name,
+                                              angle::TraceEventHandle eventHandle);
+inline void DefaultUpdateTraceEventDuration(PlatformMethods *platform,
+                                            const unsigned char *categoryEnabledFlag,
+                                            const char *name,
+                                            angle::TraceEventHandle eventHandle)
+{
+}
+
+// Callbacks for reporting histogram data.
+// CustomCounts histogram has exponential bucket sizes, so that min=1, max=1000000, bucketCount=50
+// would do.
+using HistogramCustomCountsFunc = void (*)(PlatformMethods *platform,
+                                           const char *name,
+                                           int sample,
+                                           int min,
+                                           int max,
+                                           int bucketCount);
+inline void DefaultHistogramCustomCounts(PlatformMethods *platform,
+                                         const char *name,
+                                         int sample,
+                                         int min,
+                                         int max,
+                                         int bucketCount)
+{
+}
+// Enumeration histogram buckets are linear, boundaryValue should be larger than any possible sample
+// value.
+using HistogramEnumerationFunc = void (*)(PlatformMethods *platform,
+                                          const char *name,
+                                          int sample,
+                                          int boundaryValue);
+inline void DefaultHistogramEnumeration(PlatformMethods *platform,
+                                        const char *name,
+                                        int sample,
+                                        int boundaryValue)
+{
+}
+// Unlike enumeration histograms, sparse histograms only allocate memory for non-empty buckets.
+using HistogramSparseFunc = void (*)(PlatformMethods *platform, const char *name, int sample);
+inline void DefaultHistogramSparse(PlatformMethods *platform, const char *name, int sample)
+{
+}
+// Boolean histograms track two-state variables.
+using HistogramBooleanFunc = void (*)(PlatformMethods *platform, const char *name, bool sample);
+inline void DefaultHistogramBoolean(PlatformMethods *platform, const char *name, bool sample)
+{
+}
+
+// Allows us to programatically override ANGLE's default workarounds for testing purposes.
+using OverrideWorkaroundsD3DFunc = void (*)(PlatformMethods *platform,
+                                            angle::WorkaroundsD3D *workaroundsD3D);
+inline void DefaultOverrideWorkaroundsD3D(PlatformMethods *platform,
+                                          angle::WorkaroundsD3D *workaroundsD3D)
+{
+}
+
+// Callback on a successful program link with the program binary. Can be used to store
+// shaders to disk. Keys are a 160-bit SHA-1 hash.
+using ProgramKeyType   = std::array<uint8_t, 20>;
+using CacheProgramFunc = void (*)(PlatformMethods *platform,
+                                  const ProgramKeyType &key,
+                                  size_t programSize,
+                                  const uint8_t *programBytes);
+inline void DefaultCacheProgram(PlatformMethods *platform,
+                                const ProgramKeyType &key,
+                                size_t programSize,
+                                const uint8_t *programBytes)
+{
+}
+
+// Platform methods are enumerated here once.
+#define ANGLE_PLATFORM_OP(OP)                                    \
+    OP(currentTime, CurrentTime)                                 \
+    OP(monotonicallyIncreasingTime, MonotonicallyIncreasingTime) \
+    OP(logError, LogError)                                       \
+    OP(logWarning, LogWarning)                                   \
+    OP(logInfo, LogInfo)                                         \
+    OP(getTraceCategoryEnabledFlag, GetTraceCategoryEnabledFlag) \
+    OP(addTraceEvent, AddTraceEvent)                             \
+    OP(updateTraceEventDuration, UpdateTraceEventDuration)       \
+    OP(histogramCustomCounts, HistogramCustomCounts)             \
+    OP(histogramEnumeration, HistogramEnumeration)               \
+    OP(histogramSparse, HistogramSparse)                         \
+    OP(histogramBoolean, HistogramBoolean)                       \
+    OP(overrideWorkaroundsD3D, OverrideWorkaroundsD3D)           \
+    OP(cacheProgram, CacheProgram)
+
+#define ANGLE_PLATFORM_METHOD_DEF(Name, CapsName) CapsName##Func Name = Default##CapsName;
+
+struct ANGLE_PLATFORM_EXPORT PlatformMethods
+{
+    PlatformMethods() {}
+
+    // User data pointer for any implementation specific members. Put it at the start of the
+    // platform structure so it doesn't become overwritten if one version of the platform
+    // adds or removes new members.
+    void *context = 0;
+
+    ANGLE_PLATFORM_OP(ANGLE_PLATFORM_METHOD_DEF);
+};
+
+#undef ANGLE_PLATFORM_METHOD_DEF
+
+// Subtract one to account for the context pointer.
+constexpr unsigned int g_NumPlatformMethods = (sizeof(PlatformMethods) / sizeof(uintptr_t)) - 1;
+
+#define ANGLE_PLATFORM_METHOD_STRING(Name) #Name
+#define ANGLE_PLATFORM_METHOD_STRING2(Name, CapsName) ANGLE_PLATFORM_METHOD_STRING(Name),
+
+constexpr const char *const g_PlatformMethodNames[g_NumPlatformMethods] = {
+    ANGLE_PLATFORM_OP(ANGLE_PLATFORM_METHOD_STRING2)};
+
+#undef ANGLE_PLATFORM_METHOD_STRING2
+#undef ANGLE_PLATFORM_METHOD_STRING
+
+}  // namespace angle
+
+extern "C" {
+
+// Gets the platform methods on the passed-in EGL display. If the method name signature does not
+// match the compiled signature for this ANGLE, false is returned. On success true is returned.
+// The application should set any platform methods it cares about on the returned pointer.
+// If display is not valid, behaviour is undefined.
+
+ANGLE_PLATFORM_EXPORT bool ANGLE_APIENTRY ANGLEGetDisplayPlatform(angle::EGLDisplayType display,
+                                                                  const char *const methodNames[],
+                                                                  unsigned int methodNameCount,
+                                                                  void *context,
+                                                                  void *platformMethodsOut);
+
+// Sets the platform methods back to their defaults.
+// If display is not valid, behaviour is undefined.
+ANGLE_PLATFORM_EXPORT void ANGLE_APIENTRY ANGLEResetDisplayPlatform(angle::EGLDisplayType display);
+
+}  // extern "C"
+
+namespace angle
+{
+typedef bool(ANGLE_APIENTRY *GetDisplayPlatformFunc)(angle::EGLDisplayType,
+                                                     const char *const *,
+                                                     unsigned int,
+                                                     void *,
+                                                     void *);
+typedef void(ANGLE_APIENTRY *ResetDisplayPlatformFunc)(angle::EGLDisplayType);
+}  // namespace angle
+
+// This function is not exported
+angle::PlatformMethods *ANGLEPlatformCurrent();
+
+#endif // ANGLE_PLATFORM_H
diff --git a/opengl/include/EGL/eglext_angle.h b/opengl/include/EGL/eglext_angle.h
new file mode 100644
index 0000000..0556ea1
--- /dev/null
+++ b/opengl/include/EGL/eglext_angle.h
@@ -0,0 +1,191 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// eglext_angle.h: ANGLE modifications to the eglext.h header file.
+//   Currently we don't include this file directly, we patch eglext.h
+//   to include it implicitly so it is visible throughout our code.
+
+#ifndef INCLUDE_EGL_EGLEXT_ANGLE_
+#define INCLUDE_EGL_EGLEXT_ANGLE_
+
+// clang-format off
+
+#ifndef EGL_ANGLE_robust_resource_initialization
+#define EGL_ANGLE_robust_resource_initialization 1
+#define EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE 0x3453
+#endif /* EGL_ANGLE_robust_resource_initialization */
+
+#ifndef EGL_ANGLE_keyed_mutex
+#define EGL_ANGLE_keyed_mutex 1
+#define EGL_DXGI_KEYED_MUTEX_ANGLE        0x33A2
+#endif /* EGL_ANGLE_keyed_mutex */
+
+#ifndef EGL_ANGLE_d3d_texture_client_buffer
+#define EGL_ANGLE_d3d_texture_client_buffer 1
+#define EGL_D3D_TEXTURE_ANGLE             0x33A3
+#endif /* EGL_ANGLE_d3d_texture_client_buffer */
+
+#ifndef EGL_ANGLE_software_display
+#define EGL_ANGLE_software_display 1
+#define EGL_SOFTWARE_DISPLAY_ANGLE ((EGLNativeDisplayType)-1)
+#endif /* EGL_ANGLE_software_display */
+
+#ifndef EGL_ANGLE_direct3d_display
+#define EGL_ANGLE_direct3d_display 1
+#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
+#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
+#endif /* EGL_ANGLE_direct3d_display */
+
+#ifndef EGL_ANGLE_direct_composition
+#define EGL_ANGLE_direct_composition 1
+#define EGL_DIRECT_COMPOSITION_ANGLE 0x33A5
+#endif /* EGL_ANGLE_direct_composition */
+
+#ifndef EGL_ANGLE_platform_angle
+#define EGL_ANGLE_platform_angle 1
+#define EGL_PLATFORM_ANGLE_ANGLE          0x3202
+#define EGL_PLATFORM_ANGLE_TYPE_ANGLE     0x3203
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205
+#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206
+#define EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE 0x3451
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE 0x345E
+#endif /* EGL_ANGLE_platform_angle */
+
+#ifndef EGL_ANGLE_platform_angle_d3d
+#define EGL_ANGLE_platform_angle_d3d 1
+#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE 0x320B
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE 0x320C
+#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F
+#endif /* EGL_ANGLE_platform_angle_d3d */
+
+#ifndef EGL_ANGLE_platform_angle_opengl
+#define EGL_ANGLE_platform_angle_opengl 1
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E
+#define EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE 0x3480
+#endif /* EGL_ANGLE_platform_angle_opengl */
+
+#ifndef EGL_ANGLE_platform_angle_null
+#define EGL_ANGLE_platform_angle_null 1
+#define EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE 0x33AE
+#endif /* EGL_ANGLE_platform_angle_null */
+
+#ifndef EGL_ANGLE_platform_angle_vulkan
+#define EGL_ANGLE_platform_angle_vulkan 1
+#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450
+#endif /* EGL_ANGLE_platform_angle_vulkan */
+
+#ifndef EGL_ANGLE_platform_angle_context_virtualization
+#define EGL_ANGLE_platform_angle_context_virtualization 1
+#define EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE 0x3481
+#endif /* EGL_ANGLE_platform_angle_context_virtualization */
+
+#ifndef EGL_ANGLE_x11_visual
+#define EGL_ANGLE_x11_visual
+#define EGL_X11_VISUAL_ID_ANGLE 0x33A3
+#endif /* EGL_ANGLE_x11_visual */
+
+#ifndef EGL_ANGLE_flexible_surface_compatibility
+#define EGL_ANGLE_flexible_surface_compatibility 1
+#define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6
+#endif /* EGL_ANGLE_flexible_surface_compatibility */
+
+#ifndef EGL_ANGLE_surface_orientation
+#define EGL_ANGLE_surface_orientation
+#define EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE 0x33A7
+#define EGL_SURFACE_ORIENTATION_ANGLE 0x33A8
+#define EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE 0x0001
+#define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002
+#endif /* EGL_ANGLE_surface_orientation */
+
+#ifndef EGL_ANGLE_experimental_present_path
+#define EGL_ANGLE_experimental_present_path
+#define EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE 0x33A4
+#define EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE 0x33A9
+#define EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE 0x33AA
+#endif /* EGL_ANGLE_experimental_present_path */
+
+#ifndef EGL_ANGLE_stream_producer_d3d_texture
+#define EGL_ANGLE_stream_producer_d3d_texture
+#define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x33AB
+typedef EGLBoolean(EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERD3DTEXTUREANGLEPROC)(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+typedef EGLBoolean(EGLAPIENTRYP PFNEGLSTREAMPOSTD3DTEXTUREANGLEPROC)(EGLDisplay dpy, EGLStreamKHR stream, void *texture, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglCreateStreamProducerD3DTextureANGLE(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamPostD3DTextureANGLE(EGLDisplay dpy, EGLStreamKHR stream, void *texture, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_ANGLE_stream_producer_d3d_texture */
+
+#ifndef EGL_ANGLE_create_context_webgl_compatibility
+#define EGL_ANGLE_create_context_webgl_compatibility 1
+#define EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x33AC
+#endif /* EGL_ANGLE_create_context_webgl_compatibility */
+
+#ifndef EGL_ANGLE_display_texture_share_group
+#define EGL_ANGLE_display_texture_share_group 1
+#define EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE 0x33AF
+#endif /* EGL_ANGLE_display_texture_share_group */
+
+#ifndef EGL_CHROMIUM_create_context_bind_generates_resource
+#define EGL_CHROMIUM_create_context_bind_generates_resource 1
+#define EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM 0x33AD
+#endif /* EGL_CHROMIUM_create_context_bind_generates_resource */
+
+#ifndef EGL_ANGLE_create_context_client_arrays
+#define EGL_ANGLE_create_context_client_arrays 1
+#define EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE 0x3452
+#endif /* EGL_ANGLE_create_context_client_arrays */
+
+#ifndef EGL_ANGLE_device_creation
+#define EGL_ANGLE_device_creation 1
+typedef EGLDeviceEXT(EGLAPIENTRYP PFNEGLCREATEDEVICEANGLEPROC) (EGLint device_type, void *native_device, const EGLAttrib *attrib_list);
+typedef EGLBoolean(EGLAPIENTRYP PFNEGLRELEASEDEVICEANGLEPROC) (EGLDeviceEXT device);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDeviceEXT EGLAPIENTRY eglCreateDeviceANGLE(EGLint device_type, void *native_device, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseDeviceANGLE(EGLDeviceEXT device);
+#endif
+#endif /* EGL_ANGLE_device_creation */
+
+#ifndef EGL_ANGLE_program_cache_control
+#define EGL_ANGLE_program_cache_control 1
+#define EGL_PROGRAM_CACHE_SIZE_ANGLE 0x3455
+#define EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE 0x3456
+#define EGL_PROGRAM_CACHE_RESIZE_ANGLE 0x3457
+#define EGL_PROGRAM_CACHE_TRIM_ANGLE 0x3458
+#define EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE 0x3459
+typedef EGLint (EGLAPIENTRYP PFNEGLPROGRAMCACHEGETATTRIBANGLEPROC) (EGLDisplay dpy, EGLenum attrib);
+typedef void (EGLAPIENTRYP PFNEGLPROGRAMCACHEQUERYANGLEPROC) (EGLDisplay dpy, EGLint index, void *key, EGLint *keysize, void *binary, EGLint *binarysize);
+typedef void (EGLAPIENTRYP PFNEGPROGRAMCACHELPOPULATEANGLEPROC) (EGLDisplay dpy, const void *key, EGLint keysize, const void *binary, EGLint binarysize);
+typedef EGLint (EGLAPIENTRYP PFNEGLPROGRAMCACHERESIZEANGLEPROC) (EGLDisplay dpy, EGLint limit, EGLenum mode);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglProgramCacheGetAttribANGLE(EGLDisplay dpy, EGLenum attrib);
+EGLAPI void EGLAPIENTRY eglProgramCacheQueryANGLE(EGLDisplay dpy, EGLint index, void *key, EGLint *keysize, void *binary, EGLint *binarysize);
+EGLAPI void EGLAPIENTRY eglProgramCachePopulateANGLE(EGLDisplay dpy, const void *key, EGLint keysize, const void *binary, EGLint binarysize);
+EGLAPI EGLint EGLAPIENTRY eglProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLenum mode);
+#endif
+#endif /* EGL_ANGLE_program_cache_control */
+
+#ifndef EGL_ANGLE_iosurface_client_buffer
+#define EGL_ANGLE_iosurface_client_buffer 1
+#define EGL_IOSURFACE_ANGLE 0x3454
+#define EGL_IOSURFACE_PLANE_ANGLE 0x345A
+#define EGL_TEXTURE_RECTANGLE_ANGLE 0x345B
+#define EGL_TEXTURE_TYPE_ANGLE 0x345C
+#define EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D
+#endif /* EGL_ANGLE_iosurface_client_buffer */
+
+#ifndef EGL_ANGLE_create_context_extensions_enabled
+#define EGL_ANGLE_create_context_extensions_enabled 1
+#define EGL_EXTENSIONS_ENABLED_ANGLE 0x345F
+#endif /* EGL_ANGLE_create_context_extensions_enabled */
+
+// clang-format on
+
+#endif // INCLUDE_EGL_EGLEXT_ANGLE_
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index d43c164..2a6dee4 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -143,6 +143,7 @@
         "EGL/egl.cpp",
         "EGL/eglApi.cpp",
         "EGL/Loader.cpp",
+        "EGL/egl_angle_platform.cpp",
     ],
     shared_libs: [
         "libvndksupport",
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index e954b4f..1421a48 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -38,6 +38,18 @@
 
 extern "C" {
   android_namespace_t* android_get_exported_namespace(const char*);
+
+  // TODO(ianelliott@): Get this from an ANGLE header:
+  typedef enum ANGLEPreference {
+      ANGLE_NO_PREFERENCE = 0,
+      ANGLE_PREFER_NATIVE = 1,
+      ANGLE_PREFER_ANGLE = 2,
+  } ANGLEPreference;
+
+  // TODO(ianelliott@): Get this from an ANGLE header:
+  typedef bool (*fpANGLEUseForApplication)(const char* appName, const char* deviceMfr,
+                                           const char* deviceModel, ANGLEPreference developerOption,
+                                           ANGLEPreference appPreference);
 }
 
 // ----------------------------------------------------------------------------
@@ -455,6 +467,114 @@
     return dso;
 }
 
+static void* load_angle_from_namespace(const char* kind, android_namespace_t* ns) {
+    const android_dlextinfo dlextinfo = {
+            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+            .library_namespace = ns,
+    };
+
+    std::string name = std::string("lib") + kind + "_angle.so";
+
+    void* so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+
+    if (so) {
+        ALOGD("dlopen_ext from APK (%s) success at %p", name.c_str(), so);
+        return so;
+    } else {
+        ALOGE("dlopen_ext(\"%s\") failed: %s", name.c_str(), dlerror());
+    }
+
+    return nullptr;
+}
+
+static ANGLEPreference getAnglePref(const char* app_pref) {
+    if (app_pref == nullptr)
+        return ANGLE_NO_PREFERENCE;
+
+    if (strcmp(app_pref, "angle") == 0) {
+        return ANGLE_PREFER_ANGLE;
+    } else if (strcmp(app_pref, "native") == 0) {
+        return ANGLE_PREFER_NATIVE;
+    }
+    return ANGLE_NO_PREFERENCE;
+}
+
+static void* load_angle(const char* kind, egl_connection_t* cnx) {
+    // Only attempt to load ANGLE libs
+    if (strcmp(kind, "EGL") != 0 && strcmp(kind, "GLESv2") != 0 && strcmp(kind, "GLESv1_CM") != 0)
+        return nullptr;
+
+    void* so = nullptr;
+    std::string name;
+    char prop[PROPERTY_VALUE_MAX];
+
+    android_namespace_t* ns = android_getAngleNamespace();
+    const char* app_name = android_getAngleAppName();
+    const char* app_pref = android_getAngleAppPref();
+    bool developer_opt_in = android_getAngleDeveloperOptIn();
+
+    // Determine whether or not to use ANGLE:
+    ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
+    bool use_angle = (developer_option == ANGLE_PREFER_ANGLE);
+
+    if (use_angle) {
+        ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+    } else {
+        // The "Developer Options" value wasn't set to force the use of ANGLE.  Need to temporarily
+        // load ANGLE and call the updatable opt-in/out logic:
+        std::string app_name_str = app_name ? app_name : "";
+        char manufacturer[PROPERTY_VALUE_MAX];
+        char model[PROPERTY_VALUE_MAX];
+        property_get("ro.product.manufacturer", manufacturer, "UNSET");
+        property_get("ro.product.model", model, "UNSET");
+        ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
+
+        so = load_angle_from_namespace("GLESv2", ns);
+        if (so) {
+            ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
+            fpANGLEUseForApplication fp =
+                    (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
+            if (fp) {
+                use_angle = (fp)(app_name_str.c_str(), manufacturer, model, developer_option,
+                                 app_preference);
+                ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
+            }
+
+            ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
+            dlclose(so);
+            so = nullptr;
+        } else {
+            // We weren't able to load and call the updateable opt-in/out logic.
+            // If we can't load the library, there is no ANGLE available.
+            use_angle = false;
+            ALOGV("Could not temporarily-load the ANGLE opt-in/out logic, cannot use ANGLE.");
+        }
+    }
+    if (use_angle) {
+        so = load_angle_from_namespace(kind, ns);
+    }
+
+    if (so) {
+        ALOGV("Loaded ANGLE %s library for %s (instead of native)",
+              kind, app_name ? app_name : "nullptr");
+        property_get("debug.angle.backend", prop, "UNSET");
+        ALOGV("ANGLE's backend set to %s", prop);
+        property_get("debug.hwui.renderer", prop, "UNSET");
+        ALOGV("Skia's renderer set to %s", prop);
+        cnx->useAngle = true;
+        // Find and load vendor libEGL for ANGLE
+        if (!cnx->vendorEGL) {
+            cnx->vendorEGL = load_system_driver("EGL");
+        }
+        return so;
+    } else {
+        ALOGV("Loaded native %s library for %s (instead of ANGLE)",
+              kind, app_name ? app_name : "nullptr");
+    }
+
+    return nullptr;
+}
+
 static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
     "ro.hardware.egl",
     "ro.board.platform",
@@ -486,10 +606,13 @@
     ATRACE_CALL();
 
     void* dso = nullptr;
+    dso = load_angle(kind, cnx);
 #ifndef __ANDROID_VNDK__
-    android_namespace_t* ns = android_getDriverNamespace();
-    if (ns) {
-        dso = load_updated_driver(kind, ns);
+    if (!dso) {
+        android_namespace_t* ns = android_getDriverNamespace();
+        if (ns) {
+            dso = load_updated_driver(kind, ns);
+        }
     }
 #endif
     if (!dso) {
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index c361ab0..1ed9850 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -25,6 +25,7 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
+#include <EGL/eglext_angle.h>
 
 #include <android/hardware_buffer.h>
 #include <private/android/AHardwareBufferHelpers.h>
@@ -711,12 +712,16 @@
             return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
         }
 
-        int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
-        if (result < 0) {
-            ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
-                    "failed (%#x) (already connected to another API?)",
-                    window, result);
-            return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+        // NOTE: When using Vulkan backend, the Vulkan runtime makes all the
+        // native_window_* calls, so don't do them here.
+        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+            int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+            if (result < 0) {
+                ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
+                      "failed (%#x) (already connected to another API?)",
+                      window, result);
+                return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            }
         }
 
         EGLDisplay iDpy = dp->disp.dpy;
@@ -733,7 +738,7 @@
         }
         attrib_list = strippedAttribList.data();
 
-        {
+        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
             int err = native_window_set_buffers_format(window, format);
             if (err != 0) {
                 ALOGE("error setting native window pixel format: %s (%d)",
@@ -741,16 +746,16 @@
                 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
                 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
             }
-        }
 
-        android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
-        if (dataSpace != HAL_DATASPACE_UNKNOWN) {
-            int err = native_window_set_buffers_data_space(window, dataSpace);
-            if (err != 0) {
-                ALOGE("error setting native window pixel dataSpace: %s (%d)",
-                      strerror(-err), err);
-                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+            android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
+            if (dataSpace != HAL_DATASPACE_UNKNOWN) {
+                err = native_window_set_buffers_data_space(window, dataSpace);
+                if (err != 0) {
+                    ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err),
+                          err);
+                    native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+                    return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+                }
             }
         }
 
@@ -769,8 +774,10 @@
         }
 
         // EGLSurface creation failed
-        native_window_set_buffers_format(window, 0);
-        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+            native_window_set_buffers_format(window, 0);
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+        }
     }
     return EGL_NO_SURFACE;
 }
@@ -1362,9 +1369,11 @@
         }
     }
 
-    if (!sendSurfaceMetadata(s)) {
-        native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
-        return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
+    if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+        if (!sendSurfaceMetadata(s)) {
+            native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
+            return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
+        }
     }
 
     if (n_rects == 0) {
@@ -1385,7 +1394,10 @@
         androidRect.bottom = y;
         androidRects.push_back(androidRect);
     }
-    native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), androidRects.size());
+    if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+        native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(),
+                                         androidRects.size());
+    }
 
     if (s->cnx->egl.eglSwapBuffersWithDamageKHR) {
         return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface,
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
new file mode 100644
index 0000000..7e0175a
--- /dev/null
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(__ANDROID__)
+
+#include "egl_angle_platform.h"
+#include <time.h>
+
+#include <log/log.h>
+
+namespace angle {
+
+GetDisplayPlatformFunc AnglePlatformImpl::angleGetDisplayPlatform = nullptr;
+ResetDisplayPlatformFunc AnglePlatformImpl::angleResetDisplayPlatform = nullptr;
+// Initialize start time
+time_t AnglePlatformImpl::startTime = time(nullptr);
+
+void AnglePlatformImpl::assignAnglePlatformMethods(PlatformMethods* platformMethods) {
+    platformMethods->addTraceEvent = addTraceEvent;
+    platformMethods->getTraceCategoryEnabledFlag = getTraceCategoryEnabledFlag;
+    platformMethods->monotonicallyIncreasingTime = monotonicallyIncreasingTime;
+    platformMethods->logError = logError;
+    platformMethods->logWarning = logWarning;
+    platformMethods->logInfo = logInfo;
+}
+
+const unsigned char* AnglePlatformImpl::getTraceCategoryEnabledFlag(PlatformMethods* /*platform*/,
+                                                                    const char* /*categoryName*/) {
+    // Returning ptr to 'g' (non-zero) to ALWAYS enable tracing initially.
+    // This ptr is what will be passed into "category_group_enabled" of addTraceEvent
+    static const unsigned char traceEnabled = 'g';
+    return &traceEnabled;
+}
+
+double AnglePlatformImpl::monotonicallyIncreasingTime(PlatformMethods* /*platform*/) {
+    return difftime(time(nullptr), startTime);
+}
+
+void AnglePlatformImpl::logError(PlatformMethods* /*platform*/, const char* errorMessage) {
+    ALOGE("ANGLE Error:%s", errorMessage);
+}
+
+void AnglePlatformImpl::logWarning(PlatformMethods* /*platform*/, const char* warningMessage) {
+    ALOGW("ANGLE Warn:%s", warningMessage);
+}
+
+void AnglePlatformImpl::logInfo(PlatformMethods* /*platform*/, const char* infoMessage) {
+    ALOGD("ANGLE Info:%s", infoMessage);
+}
+
+TraceEventHandle AnglePlatformImpl::addTraceEvent(
+        PlatformMethods* /**platform*/, char phase, const unsigned char* /*category_group_enabled*/,
+        const char* name, unsigned long long /*id*/, double /*timestamp*/, int /*num_args*/,
+        const char** /*arg_names*/, const unsigned char* /*arg_types*/,
+        const unsigned long long* /*arg_values*/, unsigned char /*flags*/) {
+    switch (phase) {
+        case 'B': {
+            ATRACE_BEGIN(name);
+            break;
+        }
+        case 'E': {
+            ATRACE_END();
+            break;
+        }
+        case 'I': {
+            ATRACE_NAME(name);
+            break;
+        }
+        default:
+            // Could handle other event types here
+            break;
+    }
+    // Return any non-zero handle to avoid assert in ANGLE
+    TraceEventHandle result = 1.0;
+    return result;
+}
+
+}; // namespace angle
+
+#endif // __ANDROID__
diff --git a/opengl/libs/EGL/egl_angle_platform.h b/opengl/libs/EGL/egl_angle_platform.h
new file mode 100644
index 0000000..7c6c8ed
--- /dev/null
+++ b/opengl/libs/EGL/egl_angle_platform.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if defined(__ANDROID__)
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#include <EGL/Platform.h>
+#pragma GCC diagnostic pop
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "egl_trace.h"
+
+namespace angle {
+
+class AnglePlatformImpl {
+public:
+    static void assignAnglePlatformMethods(PlatformMethods* platformMethods);
+    static GetDisplayPlatformFunc angleGetDisplayPlatform;
+    static ResetDisplayPlatformFunc angleResetDisplayPlatform;
+
+private:
+    static time_t startTime;
+    static const unsigned char* getTraceCategoryEnabledFlag(PlatformMethods* /*platform*/,
+                                                            const char* /*categoryName*/);
+    static double monotonicallyIncreasingTime(PlatformMethods* /*platform*/);
+    static void logError(PlatformMethods* /*platform*/, const char* errorMessage);
+    static void logWarning(PlatformMethods* /*platform*/, const char* warningMessage);
+    static void logInfo(PlatformMethods* /*platform*/, const char* infoMessage);
+    static TraceEventHandle addTraceEvent(PlatformMethods* /**platform*/, char phase,
+                                          const unsigned char* /*category_group_enabled*/,
+                                          const char* name, unsigned long long /*id*/,
+                                          double /*timestamp*/, int /*num_args*/,
+                                          const char** /*arg_names*/,
+                                          const unsigned char* /*arg_types*/,
+                                          const unsigned long long* /*arg_values*/,
+                                          unsigned char /*flags*/);
+};
+
+}; // namespace angle
+
+#endif // __ANDROID__
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index d16d33a..d452a6c 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -21,14 +21,19 @@
 
 #include "../egl_impl.h"
 
+#include <EGL/eglext_angle.h>
 #include <private/EGL/display.h>
 
+#include <cutils/properties.h>
+#include "Loader.h"
+#include "egl_angle_platform.h"
 #include "egl_cache.h"
 #include "egl_object.h"
 #include "egl_tls.h"
-#include "egl_trace.h"
-#include "Loader.h"
-#include <cutils/properties.h>
+
+#include <android/dlext.h>
+#include <dlfcn.h>
+#include <graphicsenv/GraphicsEnv.h>
 
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
@@ -121,6 +126,150 @@
     return sDisplay[uintptr_t(disp)].getDisplay(disp);
 }
 
+static void addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
+                                       std::vector<EGLAttrib>& attrs) {
+    intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
+
+    EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+    if (attrib_list) {
+        while (*attrib_list != EGL_NONE) {
+            EGLAttrib attr = *attrib_list++;
+            EGLAttrib value = *attrib_list++;
+            if (attr == EGL_PLATFORM_ANGLE_TYPE_ANGLE) {
+                switch (value) {
+                    case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
+                        angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+                        break;
+                    case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
+                    case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
+                        angleBackendDefault = value;
+                        break;
+                    default:
+                        ALOGW("Invalid EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute: 0x%" PRIxPTR,
+                              value);
+                        break;
+                }
+            }
+        }
+    }
+
+    cnx->angleBackend = angleBackendDefault;
+
+    // Allow debug property to override application's
+    char prop[PROPERTY_VALUE_MAX];
+    property_get("debug.angle.backend", prop, "0");
+    switch (atoi(prop)) {
+        case 1:
+            ALOGV("addAnglePlatformAttributes: Requesting OpenGLES back-end");
+            cnx->angleBackend = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
+            break;
+        case 2:
+            ALOGV("addAnglePlatformAttributes: Requesting Vulkan back-end");
+            cnx->angleBackend = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+            break;
+        default:
+            break;
+    }
+
+    attrs.reserve(4 * 2);
+
+    attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
+    attrs.push_back(cnx->angleBackend);
+
+    switch (cnx->angleBackend) {
+        case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
+            ALOGV("%s: Requesting Vulkan ANGLE back-end", __FUNCTION__);
+            property_get("debug.angle.validation", prop, "0");
+            attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
+            attrs.push_back(atoi(prop));
+            break;
+        case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
+            ALOGV("%s: Requesting Default ANGLE back-end", __FUNCTION__);
+            break;
+        case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
+            ALOGV("%s: Requesting OpenGL ES ANGLE back-end", __FUNCTION__);
+            // NOTE: This is only valid if the backend is OpenGL
+            attrs.push_back(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE);
+            attrs.push_back(vendorEGL);
+            break;
+        default:
+            ALOGV("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
+            break;
+    }
+    attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
+    attrs.push_back(EGL_FALSE);
+}
+
+// Initialize function ptrs for ANGLE PlatformMethods struct, used for systrace
+bool initializeAnglePlatform(EGLDisplay dpy) {
+    // Since we're inside libEGL, use dlsym to lookup fptr for ANGLEGetDisplayPlatform
+    android_namespace_t* ns = android_getAngleNamespace();
+    const android_dlextinfo dlextinfo = {
+            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+            .library_namespace = ns,
+    };
+    void* so = android_dlopen_ext("libEGL_angle.so", RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+    angle::AnglePlatformImpl::angleGetDisplayPlatform =
+            reinterpret_cast<angle::GetDisplayPlatformFunc>(dlsym(so, "ANGLEGetDisplayPlatform"));
+
+    if (!angle::AnglePlatformImpl::angleGetDisplayPlatform) {
+        ALOGE("dlsym lookup of ANGLEGetDisplayPlatform in libEGL_angle failed!");
+        return false;
+    }
+
+    angle::AnglePlatformImpl::angleResetDisplayPlatform =
+            reinterpret_cast<angle::ResetDisplayPlatformFunc>(
+                    eglGetProcAddress("ANGLEResetDisplayPlatform"));
+
+    angle::PlatformMethods* platformMethods = nullptr;
+    if (!((angle::AnglePlatformImpl::angleGetDisplayPlatform)(dpy, angle::g_PlatformMethodNames,
+                                                              angle::g_NumPlatformMethods, nullptr,
+                                                              &platformMethods))) {
+        ALOGE("ANGLEGetDisplayPlatform call failed!");
+        return false;
+    }
+    if (platformMethods) {
+        angle::AnglePlatformImpl::assignAnglePlatformMethods(platformMethods);
+    } else {
+        ALOGE("In initializeAnglePlatform() platformMethods struct ptr is NULL. Not assigning "
+              "tracing function ptrs!");
+    }
+    return true;
+}
+
+static EGLDisplay getDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx) {
+    EGLDisplay dpy = EGL_NO_DISPLAY;
+
+    // Locally define this until EGL 1.5 is supported
+    typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, void* native_display,
+                                                       const EGLAttrib* attrib_list);
+
+    PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplay =
+            reinterpret_cast<PFNEGLGETPLATFORMDISPLAYPROC>(
+                    cnx->egl.eglGetProcAddress("eglGetPlatformDisplay"));
+
+    if (eglGetPlatformDisplay) {
+        std::vector<EGLAttrib> attrs;
+        addAnglePlatformAttributes(cnx, nullptr, attrs);
+        attrs.push_back(EGL_NONE);
+
+        dpy = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
+                                    reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY), attrs.data());
+        if (dpy == EGL_NO_DISPLAY) {
+            ALOGE("eglGetPlatformDisplay failed!");
+        } else {
+            if (!initializeAnglePlatform(dpy)) {
+                ALOGE("initializeAnglePlatform failed!");
+            }
+        }
+    } else {
+        ALOGE("eglGetDisplay(%p) failed: Unable to look up eglGetPlatformDisplay from ANGLE",
+              display);
+    }
+
+    return dpy;
+}
+
 EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
 
     std::lock_guard<std::mutex> _l(lock);
@@ -131,7 +280,15 @@
 
     egl_connection_t* const cnx = &gEGLImpl;
     if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
-        EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
+        EGLDisplay dpy = EGL_NO_DISPLAY;
+
+        if (cnx->useAngle) {
+            dpy = getDisplayAngle(display, cnx);
+        }
+        if (dpy == EGL_NO_DISPLAY) {
+            dpy = cnx->egl.eglGetDisplay(display);
+        }
+
         disp.dpy = dpy;
         if (dpy == EGL_NO_DISPLAY) {
             loader.close(cnx->dso);
@@ -305,6 +462,10 @@
 
         egl_connection_t* const cnx = &gEGLImpl;
         if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
+            // If we're using ANGLE reset any custom DisplayPlatform
+            if (cnx->useAngle && angle::AnglePlatformImpl::angleResetDisplayPlatform) {
+                (angle::AnglePlatformImpl::angleResetDisplayPlatform)(disp.dpy);
+            }
             if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
                 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
                         egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 299d8f7..4990af6 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -47,6 +47,10 @@
     void*               libEgl;
     void*               libGles1;
     void*               libGles2;
+
+    bool                useAngle;
+    EGLint              angleBackend;
+    void*               vendorEGL;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 8f12129..57fc17f 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -258,64 +258,31 @@
 
 bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
         const std::string& uniqueDisplayId, DisplayViewport* outViewport) const {
-    const DisplayViewport* viewport = nullptr;
-    if (viewportType == ViewportType::VIEWPORT_VIRTUAL && !uniqueDisplayId.empty()) {
-
-        for (const DisplayViewport& currentViewport : mVirtualDisplays) {
-            if (currentViewport.uniqueId == uniqueDisplayId) {
-                viewport = &currentViewport;
-                break;
+    for (const DisplayViewport& currentViewport : mDisplays) {
+        if (currentViewport.type == viewportType) {
+            if (uniqueDisplayId.empty() ||
+                    (!uniqueDisplayId.empty() && uniqueDisplayId == currentViewport.uniqueId)) {
+                *outViewport = currentViewport;
+                return true;
             }
         }
-    } else if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
-        viewport = &mExternalDisplay;
-    } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
-        viewport = &mInternalDisplay;
-    }
-
-    if (viewport != nullptr && viewport->displayId >= 0) {
-        *outViewport = *viewport;
-        return true;
     }
     return false;
 }
 
-void InputReaderConfiguration::setPhysicalDisplayViewport(ViewportType viewportType,
-        const DisplayViewport& viewport) {
-    if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
-        mExternalDisplay = viewport;
-    } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
-        mInternalDisplay = viewport;
-    }
-}
-
-void InputReaderConfiguration::setVirtualDisplayViewports(
-        const Vector<DisplayViewport>& viewports) {
-    mVirtualDisplays = viewports;
+void InputReaderConfiguration::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
+    mDisplays = viewports;
 }
 
 void InputReaderConfiguration::dump(std::string& dump) const {
-    dump += INDENT4 "ViewportInternal:\n";
-    dumpViewport(dump, mInternalDisplay);
-    dump += INDENT4 "ViewportExternal:\n";
-    dumpViewport(dump, mExternalDisplay);
-    dump += INDENT4 "ViewportVirtual:\n";
-    for (const DisplayViewport& viewport : mVirtualDisplays) {
+    for (const DisplayViewport& viewport : mDisplays) {
         dumpViewport(dump, viewport);
     }
 }
 
-void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport) const {
-    dump += StringPrintf(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', "
-            "logicalFrame=[%d, %d, %d, %d], "
-            "physicalFrame=[%d, %d, %d, %d], "
-            "deviceSize=[%d, %d]\n",
-            viewport.displayId, viewport.orientation, viewport.uniqueId.c_str(),
-            viewport.logicalLeft, viewport.logicalTop,
-            viewport.logicalRight, viewport.logicalBottom,
-            viewport.physicalLeft, viewport.physicalTop,
-            viewport.physicalRight, viewport.physicalBottom,
-            viewport.deviceWidth, viewport.deviceHeight);
+void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport)
+        const {
+    dump += StringPrintf(INDENT4 "%s\n", viewport.toString().c_str());
 }
 
 
@@ -3600,6 +3567,12 @@
                 break;
             }
 
+            if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) {
+                ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str());
+                naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight;
+                naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth;
+            }
+
             mPhysicalWidth = naturalPhysicalWidth;
             mPhysicalHeight = naturalPhysicalHeight;
             mPhysicalLeft = naturalPhysicalLeft;
@@ -3913,17 +3886,7 @@
 }
 
 void TouchInputMapper::dumpSurface(std::string& dump) {
-    dump += StringPrintf(INDENT3 "Viewport: displayId=%d, orientation=%d, "
-            "logicalFrame=[%d, %d, %d, %d], "
-            "physicalFrame=[%d, %d, %d, %d], "
-            "deviceSize=[%d, %d]\n",
-            mViewport.displayId, mViewport.orientation,
-            mViewport.logicalLeft, mViewport.logicalTop,
-            mViewport.logicalRight, mViewport.logicalBottom,
-            mViewport.physicalLeft, mViewport.physicalTop,
-            mViewport.physicalRight, mViewport.physicalBottom,
-            mViewport.deviceWidth, mViewport.deviceHeight);
-
+    dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
     dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
     dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
     dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index c06168d..74668b7 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -38,6 +38,7 @@
 #include <optional>
 #include <stddef.h>
 #include <unistd.h>
+#include <vector>
 
 // Maximum supported size of a vibration pattern.
 // Must be at least 2.
@@ -203,17 +204,14 @@
 
     bool getDisplayViewport(ViewportType viewportType, const std::string& uniqueDisplayId,
             DisplayViewport* outViewport) const;
-    void setPhysicalDisplayViewport(ViewportType viewportType, const DisplayViewport& viewport);
-    void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
+    void setDisplayViewports(const std::vector<DisplayViewport>& viewports);
 
 
     void dump(std::string& dump) const;
     void dumpViewport(std::string& dump, const DisplayViewport& viewport) const;
 
 private:
-    DisplayViewport mInternalDisplay;
-    DisplayViewport mExternalDisplay;
-    Vector<DisplayViewport> mVirtualDisplays;
+    std::vector<DisplayViewport> mDisplays;
 };
 
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9b985dc..b70ee09 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -132,6 +132,7 @@
     InputReaderConfiguration mConfig;
     KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
     Vector<InputDeviceInfo> mInputDevices;
+    std::vector<DisplayViewport> mViewports;
     TouchAffineTransformation transform;
 
 protected:
@@ -143,17 +144,20 @@
 
     void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
             const std::string& uniqueId) {
-        DisplayViewport v = createDisplayViewport(displayId, width, height, orientation, uniqueId);
+        mViewports.clear();
         // Set the size of both the internal and external display at the same time.
-        mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL, v);
-        mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_EXTERNAL, v);
+        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+                ViewportType::VIEWPORT_INTERNAL));
+        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+                ViewportType::VIEWPORT_EXTERNAL));
+        mConfig.setDisplayViewports(mViewports);
     }
 
     void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
             const std::string& uniqueId) {
-        Vector<DisplayViewport> viewports;
-        viewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId));
-        mConfig.setVirtualDisplayViewports(viewports);
+        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+                ViewportType::VIEWPORT_VIRTUAL));
+        mConfig.setDisplayViewports(mViewports);
     }
 
     void addExcludedDeviceName(const std::string& deviceName) {
@@ -203,7 +207,7 @@
 
 private:
     DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
-            int32_t orientation, const std::string& uniqueId) {
+            int32_t orientation, const std::string& uniqueId, ViewportType type) {
         bool isRotated = (orientation == DISPLAY_ORIENTATION_90
                 || orientation == DISPLAY_ORIENTATION_270);
         DisplayViewport v;
@@ -220,6 +224,7 @@
         v.deviceWidth = isRotated ? height : width;
         v.deviceHeight = isRotated ? width : height;
         v.uniqueId = uniqueId;
+        v.type = type;
         return v;
     }
 
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index ebc7eb1..f813fe5 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -16,6 +16,7 @@
 
 #include "SensorDevice.h"
 
+#include "android/hardware/sensors/2.0/ISensorsCallback.h"
 #include "android/hardware/sensors/2.0/types.h"
 #include "SensorService.h"
 
@@ -32,6 +33,7 @@
 using namespace android::hardware::sensors;
 using namespace android::hardware::sensors::V1_0;
 using namespace android::hardware::sensors::V1_0::implementation;
+using android::hardware::sensors::V2_0::ISensorsCallback;
 using android::hardware::sensors::V2_0::EventQueueFlagBits;
 using android::hardware::hidl_vec;
 using android::hardware::Return;
@@ -57,6 +59,27 @@
     }
 }
 
+void SensorsHalDeathReceivier::serviceDied(
+        uint64_t /* cookie */,
+        const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
+    ALOGW("Sensors HAL died, attempting to reconnect.");
+    // TODO: Attempt reconnect
+}
+
+struct SensorsCallback : public ISensorsCallback {
+    using Result = ::android::hardware::sensors::V1_0::Result;
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo> &dynamicSensorsAdded) override {
+        return SensorDevice::getInstance().onDynamicSensorsConnected(dynamicSensorsAdded);
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t> &dynamicSensorHandlesRemoved) override {
+        return SensorDevice::getInstance().onDynamicSensorsDisconnected(
+                dynamicSensorHandlesRemoved);
+    }
+};
+
 SensorDevice::SensorDevice()
         : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {
     if (!connectHidlService()) {
@@ -166,13 +189,15 @@
         status_t status = StatusFromResult(checkReturn(mSensors->initialize(
                 *mEventQueue->getDesc(),
                 *mWakeLockQueue->getDesc(),
-                this)));
+                new SensorsCallback())));
 
         if (status != NO_ERROR) {
             connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
             ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status));
         } else {
             connectionStatus = HalConnectionStatus::CONNECTED;
+            mSensorsHalDeathReceiver = new SensorsHalDeathReceivier();
+            sensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */);
         }
     }
 
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 282550f..2da60b6 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -42,9 +42,12 @@
 namespace android {
 
 // ---------------------------------------------------------------------------
+class SensorsHalDeathReceivier : public android::hardware::hidl_death_recipient {
+    virtual void serviceDied(uint64_t cookie,
+                             const wp<::android::hidl::base::V1_0::IBase>& service) override;
+};
 
 class SensorDevice : public Singleton<SensorDevice>,
-                     public android::hardware::sensors::V2_0::ISensorsCallback,
                      public SensorServiceUtil::Dumpable {
 public:
     class HidlTransportErrorLog {
@@ -107,9 +110,9 @@
 
     using Result = ::android::hardware::sensors::V1_0::Result;
     hardware::Return<void> onDynamicSensorsConnected(
-            const hardware::hidl_vec<hardware::sensors::V1_0::SensorInfo> &dynamicSensorsAdded) override;
+            const hardware::hidl_vec<hardware::sensors::V1_0::SensorInfo> &dynamicSensorsAdded);
     hardware::Return<void> onDynamicSensorsDisconnected(
-            const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved) override;
+            const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved);
 
     // Dumpable
     virtual std::string dump() const;
@@ -223,6 +226,8 @@
     hardware::EventFlag* mEventQueueFlag;
 
     std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+
+    sp<SensorsHalDeathReceivier> mSensorsHalDeathReceiver;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 642ed2f..cafe26b 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -258,6 +258,7 @@
     getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
     getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
     getBE().compositionInfo.hwc.supportedPerFrameMetadata = display->getSupportedPerFrameMetadata();
+    getBE().compositionInfo.hwc.colorTransform = getColorTransform();
 
     setHwcLayerBuffer(display);
 }
@@ -319,7 +320,8 @@
     return true;
 }
 
-Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+                                const sp<Fence>& releaseFence) {
     ATRACE_CALL();
 
     std::optional<Region> sidebandStreamDirtyRegion = latchSidebandStream(recomputeVisibleRegions);
@@ -360,7 +362,7 @@
         return dirtyRegion;
     }
 
-    status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
+    status_t err = updateTexImage(recomputeVisibleRegions, latchTime, releaseFence);
     if (err != NO_ERROR) {
         return dirtyRegion;
     }
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 92bf132..a294793 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -91,7 +91,11 @@
     // the visible regions need to be recomputed (this is a fairly heavy
     // operation, so this should be set only if needed). Typically this is used
     // to figure out if the content or size of a surface has changed.
-    Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+    // If there was a GL composition step rendering the previous frame, then
+    // releaseFence will be populated with a native fence that fires when
+    // composition has completed.
+    Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+                       const sp<Fence>& releaseFence) override;
 
     bool isBufferLatched() const override { return mRefreshPending; }
 
@@ -135,7 +139,8 @@
     virtual void setFilteringEnabled(bool enabled) = 0;
 
     virtual status_t bindTextureImage() const = 0;
-    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
+    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+                                    const sp<Fence>& flushFence) = 0;
 
     virtual status_t updateActiveBuffer() = 0;
     virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index fa181ad..f499f06 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -147,7 +147,8 @@
 
 status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
                                              bool* autoRefresh, bool* queuedBuffer,
-                                             uint64_t maxFrameNumber) {
+                                             uint64_t maxFrameNumber,
+                                             const sp<Fence>& releaseFence) {
     ATRACE_CALL();
     BLC_LOGV("updateTexImage");
     Mutex::Autolock lock(mMutex);
@@ -198,12 +199,12 @@
     }
 
     // Release the previous buffer.
-    err = updateAndReleaseLocked(item, &mPendingRelease);
+    err = updateAndReleaseLocked(item, &mPendingRelease, releaseFence);
     if (err != NO_ERROR) {
         return err;
     }
 
-    if (mRE.useNativeFenceSync()) {
+    if (!mRE.useNativeFenceSync()) {
         // Bind the new buffer to the GL texture.
         //
         // Older devices require the "implicit" synchronization provided
@@ -278,14 +279,15 @@
 }
 
 status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
-                                                     PendingRelease* pendingRelease) {
+                                                     PendingRelease* pendingRelease,
+                                                     const sp<Fence>& releaseFence) {
     status_t err = NO_ERROR;
 
     int slot = item.mSlot;
 
     // Do whatever sync ops we need to do before releasing the old slot.
     if (slot != mCurrentTexture) {
-        err = syncForReleaseLocked();
+        err = syncForReleaseLocked(releaseFence);
         if (err != NO_ERROR) {
             // Release the buffer we just acquired.  It's not safe to
             // release the old buffer, so instead we just drop the new frame.
@@ -367,19 +369,19 @@
     return doFenceWaitLocked();
 }
 
-status_t BufferLayerConsumer::syncForReleaseLocked() {
+status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence) {
     BLC_LOGV("syncForReleaseLocked");
 
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (mRE.useNativeFenceSync()) {
-            base::unique_fd fenceFd = mRE.flush();
-            if (fenceFd == -1) {
+        if (mRE.useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
+            // TODO(alecmouri): fail further upstream if the fence is invalid
+            if (!releaseFence->isValid()) {
                 BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
                 return UNKNOWN_ERROR;
             }
-            sp<Fence> fence(new Fence(std::move(fenceFd)));
-            status_t err = addReleaseFenceLocked(mCurrentTexture,
-                                                 mCurrentTextureImage->graphicBuffer(), fence);
+            status_t err =
+                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
+                                          releaseFence);
             if (err != OK) {
                 BLC_LOGE("syncForReleaseLocked: error adding release fence: "
                          "%s (%d)",
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 257a4e5..dc00487 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -94,7 +94,8 @@
     // used to reject the newly acquired buffer.  It also does not bind the
     // RenderEngine texture until bindTextureImage is called.
     status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh,
-                            bool* queuedBuffer, uint64_t maxFrameNumber);
+                            bool* queuedBuffer, uint64_t maxFrameNumber,
+                            const sp<Fence>& releaseFence);
 
     // See BufferLayerConsumer::bindTextureImageLocked().
     status_t bindTextureImage();
@@ -208,7 +209,8 @@
     // completion of the method will instead be returned to the caller, so that
     // it may call releaseBufferLocked itself later.
     status_t updateAndReleaseLocked(const BufferItem& item,
-                                    PendingRelease* pendingRelease = nullptr);
+                                    PendingRelease* pendingRelease = nullptr,
+                                    const sp<Fence>& releaseFence = Fence::NO_FENCE);
 
     // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.  Uses
     // mCurrentTexture if it's set, mCurrentTextureImage if not.  If the
@@ -282,7 +284,7 @@
     // current slot from RenderEngine.  If needed it will set the current
     // slot's fence to guard against a producer accessing the buffer before
     // the outstanding accesses have completed.
-    status_t syncForReleaseLocked();
+    status_t syncForReleaseLocked(const sp<Fence>& releaseFence);
 
     // The default consumer usage flags that BufferLayerConsumer always sets on its
     // BufferQueue instance; these will be OR:d with any additional flags passed
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 17706b5..6822298 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -221,7 +221,8 @@
     return mConsumer->bindTextureImage();
 }
 
-status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+                                          const sp<Fence>& releaseFence) {
     // This boolean is used to make sure that SurfaceFlinger's shadow copy
     // of the buffer queue isn't modified when the buffer queue is returning
     // BufferItem's that weren't actually queued. This can happen in shared
@@ -232,7 +233,7 @@
                     getTransformToDisplayInverse(), mFreezeGeometryUpdates);
     status_t updateResult =
             mConsumer->updateTexImage(&r, *mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
-                                      mLastFrameNumberReceived);
+                                      mLastFrameNumberReceived, releaseFence);
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 051b15d..dcf39ee 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -90,7 +90,8 @@
     void setFilteringEnabled(bool enabled) override;
 
     status_t bindTextureImage() const override;
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+                            const sp<Fence>& releaseFence) override;
 
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 9c10868..2ecf71c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -377,7 +377,8 @@
     return NO_ERROR;
 }
 
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
+                                          const sp<Fence>& releaseFence) {
     const State& s(getDrawingState());
 
     if (!s.buffer) {
@@ -419,16 +420,13 @@
     }
 
     // Handle sync fences
-    if (SyncFeatures::getInstance().useNativeFenceSync()) {
-        base::unique_fd fenceFd = engine.flush();
-        if (fenceFd == -1) {
-            ALOGE("failed to flush RenderEngine");
+    if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
+        // TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
+        if (!releaseFence->isValid()) {
             mTimeStats.clearLayerRecord(getName().c_str());
             return UNKNOWN_ERROR;
         }
 
-        sp<Fence> fence(new Fence(std::move(fenceFd)));
-
         // Check status of fences first because merging is expensive.
         // Merging an invalid fence with any other fence results in an
         // invalid fence.
@@ -439,10 +437,10 @@
             return BAD_VALUE;
         }
 
-        auto incomingStatus = fence->getStatus();
+        auto incomingStatus = releaseFence->getStatus();
         if (incomingStatus == Fence::Status::Invalid) {
             ALOGE("New fence has invalid state");
-            mDrawingState.acquireFence = fence;
+            mDrawingState.acquireFence = releaseFence;
             mTimeStats.clearLayerRecord(getName().c_str());
             return BAD_VALUE;
         }
@@ -452,12 +450,13 @@
         if (currentStatus == incomingStatus) {
             char fenceName[32] = {};
             snprintf(fenceName, 32, "%.28s:%d", mName.string(), mFrameNumber);
-            sp<Fence> mergedFence = Fence::merge(fenceName, mDrawingState.acquireFence, fence);
+            sp<Fence> mergedFence =
+                    Fence::merge(fenceName, mDrawingState.acquireFence, releaseFence);
             if (!mergedFence.get()) {
                 ALOGE("failed to merge release fences");
                 // synchronization is broken, the best we can do is hope fences
                 // signal in order so the new fence will act like a union
-                mDrawingState.acquireFence = fence;
+                mDrawingState.acquireFence = releaseFence;
                 mTimeStats.clearLayerRecord(getName().c_str());
                 return BAD_VALUE;
             }
@@ -470,7 +469,7 @@
             // 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.
-            mDrawingState.acquireFence = fence;
+            mDrawingState.acquireFence = releaseFence;
         }
     } else {
         // Bind the new buffer to the GL texture.
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index b662b96..db11110 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -115,7 +115,8 @@
     void setFilteringEnabled(bool enabled) override;
 
     status_t bindTextureImage() const override;
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+                            const sp<Fence>& releaseFence) override;
 
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index b02c16c..3a554c9 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -75,6 +75,7 @@
 
     // Clear out the transform, because it doesn't make sense absent a source buffer
     getBE().compositionInfo.hwc.transform = HWC2::Transform::None;
+    getBE().compositionInfo.hwc.colorTransform = getColorTransform();
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f9bc1e7..8afd3b3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1546,6 +1546,25 @@
     return true;
 }
 
+bool Layer::setColorTransform(const mat4& matrix) {
+    if (mCurrentState.colorTransform == matrix) {
+        return false;
+    }
+    ++mCurrentState.sequence;
+    mCurrentState.colorTransform = matrix;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+const mat4& Layer::getColorTransform() const {
+    return getDrawingState().colorTransform;
+}
+
+bool Layer::hasColorTransform() const {
+    static const mat4 identityMatrix = mat4();
+    return getDrawingState().colorTransform != identityMatrix;
+}
+
 bool Layer::isLegacyDataSpace() const {
     // return true when no higher bits are set
     return !(mCurrentDataSpace & (ui::Dataspace::STANDARD_MASK |
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 874b551..3eb8327 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -181,6 +181,7 @@
         int32_t api;
 
         sp<NativeHandle> sidebandStream;
+        mat4 colorTransform;
     };
 
     explicit Layer(const LayerCreationArgs& args);
@@ -255,6 +256,9 @@
     virtual void setChildrenDrawingParent(const sp<Layer>& layer);
     virtual bool reparent(const sp<IBinder>& newParentHandle);
     virtual bool detachChildren();
+    virtual bool setColorTransform(const mat4& matrix);
+    virtual const mat4& getColorTransform() const;
+    virtual bool hasColorTransform() const;
 
     // Used only to set BufferStateLayer state
     virtual bool setTransform(uint32_t /*transform*/) { return false; };
@@ -457,7 +461,8 @@
      * operation, so this should be set only if needed). Typically this is used
      * to figure out if the content or size of a surface has changed.
      */
-    virtual Region latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
+    virtual Region latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
+                               const sp<Fence>& /*releaseFence*/) {
         return {};
     }
 
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
index ef017aa..c9b7933 100644
--- a/services/surfaceflinger/LayerBE.cpp
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -112,6 +112,20 @@
         hwc.surfaceDamage.dump(regionString, "surfaceDamage");
         result += regionString.string();
     }
+
+    result += base::StringPrintf("\tcolor transform matrix:\n"
+                                 "\t\t[%f, %f, %f, %f,\n"
+                                 "\t\t %f, %f, %f, %f,\n"
+                                 "\t\t %f, %f, %f, %f,\n"
+                                 "\t\t %f, %f, %f, %f]\n",
+                                 hwc.colorTransform[0][0], hwc.colorTransform[1][0],
+                                 hwc.colorTransform[2][0], hwc.colorTransform[3][0],
+                                 hwc.colorTransform[0][1], hwc.colorTransform[1][1],
+                                 hwc.colorTransform[2][1], hwc.colorTransform[3][1],
+                                 hwc.colorTransform[0][2], hwc.colorTransform[1][2],
+                                 hwc.colorTransform[2][2], hwc.colorTransform[3][2],
+                                 hwc.colorTransform[0][3], hwc.colorTransform[1][3],
+                                 hwc.colorTransform[2][3], hwc.colorTransform[3][3]);
 }
 
 void CompositionInfo::dumpRe(std::string& result, const char* tag) const {
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 2722b01..d63d16f 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -60,6 +60,7 @@
         bool clearClientTarget = false;
         bool supportedPerFrameMetadata = false;
         HdrMetadata hdrMetadata;
+        mat4 colorTransform;
     } hwc;
     struct {
         bool blackoutLayer = false;
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
index 9c2d312..c0174ae 100644
--- a/services/surfaceflinger/LayerStats.cpp
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -68,7 +68,7 @@
         base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
         base::StringAppendF(&key, ",%d", layer->isProtected);
         base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
-        base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format));
+        base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format).c_str());
         base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
         base::StringAppendF(&key, ",%s",
                             destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0],
@@ -162,8 +162,8 @@
     return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
 }
 
-const char* LayerStats::layerPixelFormat(int32_t pixelFormat) {
-    return decodePixelFormat(pixelFormat).c_str();
+std::string LayerStats::layerPixelFormat(int32_t pixelFormat) {
+    return decodePixelFormat(pixelFormat);
 }
 
 std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
index 944073b..9de9cce 100644
--- a/services/surfaceflinger/LayerStats.h
+++ b/services/surfaceflinger/LayerStats.h
@@ -50,7 +50,7 @@
     // Return the name of the composition type
     static const char* layerCompositionType(int32_t compositionType);
     // Return the name of the pixel format
-    static const char* layerPixelFormat(int32_t pixelFormat);
+    static std::string layerPixelFormat(int32_t pixelFormat);
     // Calculate scale ratios of layer's width/height with rotation information
     static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
     // Calculate scale ratio from source to destination and convert to string
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index 813c9e6..1b0a539 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -743,7 +743,7 @@
     mState.textureEnabled = true;
 }
 
-void GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
+void GLES20RenderEngine::setColorTransform(const mat4& colorTransform) {
     mState.colorMatrix = colorTransform;
 }
 
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
index fa01410..4f03a90 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
@@ -86,7 +86,7 @@
     void setupLayerTexturing(const Texture& texture) override;
     void setupLayerBlackedOut() override;
     void setupFillWithColor(float r, float g, float b, float a) override;
-    void setupColorTransform(const mat4& colorTransform) override;
+    void setColorTransform(const mat4& colorTransform) override;
     void disableTexturing() override;
     void disableBlending() override;
 
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
index 05668f8..122271f 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
@@ -115,7 +115,9 @@
     virtual void setupLayerTexturing(const Texture& texture) = 0;
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
-    virtual void setupColorTransform(const mat4& /* colorTransform */) = 0;
+
+    // Set a color transform matrix that is applied in linear space right before OETF.
+    virtual void setColorTransform(const mat4& /* colorTransform */) = 0;
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
@@ -163,7 +165,6 @@
 
     bool useNativeFenceSync() const override;
     bool useWaitSync() const override;
-    void setupColorTransform(const mat4& /* colorTransform */) override {}
 
 protected:
     RenderEngine(uint32_t featureFlags);
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h b/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
index efab8ff..911bb7a 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
@@ -68,6 +68,8 @@
 
     // projection matrix
     mat4 projectionMatrix;
+
+    // The color matrix will be applied in linear space right before OETF.
     mat4 colorMatrix;
     mat4 inputTransformMatrix;
     mat4 outputTransformMatrix;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index fa2b0a6..9bee9a3 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -111,14 +111,28 @@
 status_t EventThread::registerDisplayEventConnection(
         const sp<EventThread::Connection>& connection) {
     std::lock_guard<std::mutex> lock(mMutex);
-    mDisplayEventConnections.add(connection);
+
+    // this should never happen
+    auto it = std::find(mDisplayEventConnections.cbegin(),
+            mDisplayEventConnections.cend(), connection);
+    if (it != mDisplayEventConnections.cend()) {
+        ALOGW("DisplayEventConnection %p already exists", connection.get());
+        mCondition.notify_all();
+        return ALREADY_EXISTS;
+    }
+
+    mDisplayEventConnections.push_back(connection);
     mCondition.notify_all();
     return NO_ERROR;
 }
 
 void EventThread::removeDisplayEventConnectionLocked(
         const wp<EventThread::Connection>& connection) {
-    mDisplayEventConnections.remove(connection);
+    auto it = std::find(mDisplayEventConnections.cbegin(),
+            mDisplayEventConnections.cend(), connection);
+    if (it != mDisplayEventConnections.cend()) {
+        mDisplayEventConnections.erase(it);
+    }
 }
 
 void EventThread::setVsyncRate(uint32_t count, const sp<EventThread::Connection>& connection) {
@@ -181,7 +195,7 @@
     event.header.timestamp = systemTime();
     event.hotplug.connected = connected;
 
-    mPendingEvents.add(event);
+    mPendingEvents.push(event);
     mCondition.notify_all();
 }
 
@@ -189,13 +203,11 @@
     std::unique_lock<std::mutex> lock(mMutex);
     while (mKeepRunning) {
         DisplayEventReceiver::Event event;
-        Vector<sp<EventThread::Connection> > signalConnections;
+        std::vector<sp<EventThread::Connection>> signalConnections;
         signalConnections = waitForEventLocked(&lock, &event);
 
         // dispatch events to listeners...
-        const size_t count = signalConnections.size();
-        for (size_t i = 0; i < count; i++) {
-            const sp<Connection>& conn(signalConnections[i]);
+        for (const sp<Connection>& conn : signalConnections) {
             // now see if we still need to report this event
             status_t err = conn->postEvent(event);
             if (err == -EAGAIN || err == -EWOULDBLOCK) {
@@ -210,7 +222,7 @@
                 // handle any other error on the pipe as fatal. the only
                 // reasonable thing to do is to clean-up this connection.
                 // The most common error we'll get here is -EPIPE.
-                removeDisplayEventConnectionLocked(signalConnections[i]);
+                removeDisplayEventConnectionLocked(conn);
             }
         }
     }
@@ -218,11 +230,11 @@
 
 // This will return when (1) a vsync event has been received, and (2) there was
 // at least one connection interested in receiving it when we started waiting.
-Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(
+std::vector<sp<EventThread::Connection>> EventThread::waitForEventLocked(
         std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* outEvent) {
-    Vector<sp<EventThread::Connection> > signalConnections;
+    std::vector<sp<EventThread::Connection>> signalConnections;
 
-    while (signalConnections.isEmpty() && mKeepRunning) {
+    while (signalConnections.empty() && mKeepRunning) {
         bool eventPending = false;
         bool waitForVSync = false;
 
@@ -244,18 +256,18 @@
 
         if (!timestamp) {
             // no vsync event, see if there are some other event
-            eventPending = !mPendingEvents.isEmpty();
+            eventPending = !mPendingEvents.empty();
             if (eventPending) {
                 // we have some other event to dispatch
-                *outEvent = mPendingEvents[0];
-                mPendingEvents.removeAt(0);
+                *outEvent = mPendingEvents.front();
+                mPendingEvents.pop();
             }
         }
 
         // find out connections waiting for events
-        size_t count = mDisplayEventConnections.size();
-        for (size_t i = 0; i < count;) {
-            sp<Connection> connection(mDisplayEventConnections[i].promote());
+        auto it = mDisplayEventConnections.begin();
+        while (it != mDisplayEventConnections.end()) {
+            sp<Connection> connection(it->promote());
             if (connection != nullptr) {
                 bool added = false;
                 if (connection->count >= 0) {
@@ -268,12 +280,12 @@
                         if (connection->count == 0) {
                             // fired this time around
                             connection->count = -1;
-                            signalConnections.add(connection);
+                            signalConnections.push_back(connection);
                             added = true;
                         } else if (connection->count == 1 ||
                                    (vsyncCount % connection->count) == 0) {
                             // continuous event, and time to report it
-                            signalConnections.add(connection);
+                            signalConnections.push_back(connection);
                             added = true;
                         }
                     }
@@ -283,14 +295,13 @@
                     // we don't have a vsync event to process
                     // (timestamp==0), but we have some pending
                     // messages.
-                    signalConnections.add(connection);
+                    signalConnections.push_back(connection);
                 }
-                ++i;
+                ++it;
             } else {
                 // we couldn't promote this reference, the connection has
                 // died, so clean-up!
-                mDisplayEventConnections.removeAt(i);
-                --count;
+                it = mDisplayEventConnections.erase(it);
             }
         }
 
@@ -379,11 +390,12 @@
     result.appendFormat("  soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
     result.appendFormat("  numListeners=%zu,\n  events-delivered: %u\n",
                         mDisplayEventConnections.size(), mVSyncEvent[0].vsync.count);
-    for (size_t i = 0; i < mDisplayEventConnections.size(); i++) {
-        sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
+    for (const wp<Connection>& weak : mDisplayEventConnections) {
+        sp<Connection> connection = weak.promote();
         result.appendFormat("    %p: count=%d\n", connection.get(),
                             connection != nullptr ? connection->count : 0);
     }
+    result.appendFormat("  other-events-pending: %zu\n", mPendingEvents.size());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 127891e..5e7ed13 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -22,7 +22,9 @@
 #include <condition_variable>
 #include <cstdint>
 #include <mutex>
+#include <queue>
 #include <thread>
+#include <vector>
 
 #include <android-base/thread_annotations.h>
 
@@ -31,7 +33,6 @@
 #include <private/gui/BitTube.h>
 
 #include <utils/Errors.h>
-#include <utils/SortedVector.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -117,7 +118,6 @@
     ~EventThread();
 
     sp<BnDisplayEventConnection> createEventConnection() const override;
-    status_t registerDisplayEventConnection(const sp<Connection>& connection);
 
     void setVsyncRate(uint32_t count, const sp<Connection>& connection);
     void requestNextVsync(const sp<Connection>& connection);
@@ -143,9 +143,11 @@
                 ResyncWithRateLimitCallback resyncWithRateLimitCallback,
                 InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
 
+    status_t registerDisplayEventConnection(const sp<Connection>& connection);
+
     void threadMain();
-    Vector<sp<EventThread::Connection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
-                                                           DisplayEventReceiver::Event* event)
+    std::vector<sp<EventThread::Connection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
+                                                                DisplayEventReceiver::Event* event)
             REQUIRES(mMutex);
 
     void removeDisplayEventConnectionLocked(const wp<Connection>& connection) REQUIRES(mMutex);
@@ -167,8 +169,8 @@
     mutable std::condition_variable mCondition;
 
     // protected by mLock
-    SortedVector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
-    Vector<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
+    std::vector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
+    std::queue<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
     std::array<DisplayEventReceiver::Event, 2> mVSyncEvent GUARDED_BY(mMutex);
     bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
     bool mVsyncEnabled GUARDED_BY(mMutex) = false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9410cdb..37b32ed 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1528,6 +1528,18 @@
                 getBE().mHwc->hasClientComposition(display->getId());
     }
 
+    // Setup RenderEngine sync fences if native sync is supported.
+    if (getBE().mRenderEngine->useNativeFenceSync()) {
+        if (mHadClientComposition) {
+            base::unique_fd flushFence(getRenderEngine().flush());
+            ALOGE_IF(flushFence < 0, "Failed to flush RenderEngine!");
+            getBE().flushFence = new Fence(std::move(flushFence));
+        } else {
+            // Cleanup for hygiene.
+            getBE().flushFence = Fence::NO_FENCE;
+        }
+    }
+
     mVsyncModulator.onRefreshed(mHadClientComposition);
 
     getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
@@ -1604,6 +1616,11 @@
                 layer->forceClientComposition(displayId);
             }
 
+            // TODO(b/111562338) remove when composer 2.3 is shipped.
+            if (layer->hasColorTransform()) {
+                layer->forceClientComposition(displayId);
+            }
+
             if (layer->getForceClientComposition(displayId)) {
                 ALOGV("[%s] Requesting Client composition", layer->getName().string());
                 layer->setCompositionType(displayId, HWC2::Composition::Client);
@@ -2141,6 +2158,8 @@
     ALOGE_IF(error != HWC2::Error::None,
             "[SF] Failed to set surface damage: %s (%d)",
             to_string(error).c_str(), static_cast<int32_t>(error));
+
+    error = (compositionInfo.hwc.hwcLayer)->setColorTransform(compositionInfo.hwc.colorTransform);
 }
 
 void SurfaceFlinger::configureDeviceComposition(const CompositionInfo& compositionInfo) const
@@ -3031,7 +3050,7 @@
     });
 
     for (auto& layer : mLayersWithQueuedFrames) {
-        const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
+        const Region dirty(layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence));
         layer->useSurfaceDamage();
         invalidateLayerStack(layer, dirty);
         if (layer->isBufferLatched()) {
@@ -3039,6 +3058,11 @@
         }
     }
 
+    // Clear the renderengine fence here...
+    // downstream code assumes that a cleared fence == NO_FENCE, so reassign to
+    // clear instead of sp::clear.
+    getBE().flushFence = Fence::NO_FENCE;
+
     mVisibleRegionsDirty |= visibleRegions;
 
     // If we will need to wake up at some time in the future to deal with a
@@ -3091,6 +3115,7 @@
     const bool hasClientComposition = getBE().mHwc->hasClientComposition(displayId);
     ATRACE_INT("hasClientComposition", hasClientComposition);
 
+    mat4 colorMatrix;
     bool applyColorMatrix = false;
     bool needsEnhancedColorMatrix = false;
 
@@ -3109,7 +3134,7 @@
         const bool skipClientColorTransform = getBE().mHwc->hasCapability(
             HWC2::Capability::SkipClientColorTransform);
 
-        mat4 colorMatrix;
+        // Compute the global color transform matrix.
         applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
         if (applyColorMatrix) {
             colorMatrix = mDrawingState.colorMatrix;
@@ -3125,8 +3150,6 @@
             colorMatrix *= mEnhancedSaturationMatrix;
         }
 
-        getRenderEngine().setupColorTransform(colorMatrix);
-
         if (!display->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
                   display->getDisplayName().c_str());
@@ -3205,6 +3228,19 @@
                     break;
                 }
                 case HWC2::Composition::Client: {
+                    if (layer->hasColorTransform()) {
+                        mat4 tmpMatrix;
+                        if (applyColorMatrix) {
+                            tmpMatrix = mDrawingState.colorMatrix;
+                        }
+                        tmpMatrix *= layer->getColorTransform();
+                        if (needsEnhancedColorMatrix) {
+                            tmpMatrix *= mEnhancedSaturationMatrix;
+                        }
+                        getRenderEngine().setColorTransform(tmpMatrix);
+                    } else {
+                        getRenderEngine().setColorTransform(colorMatrix);
+                    }
                     layer->draw(renderArea, clip);
                     break;
                 }
@@ -3217,9 +3253,8 @@
         firstLayer = false;
     }
 
-    if (applyColorMatrix || needsEnhancedColorMatrix) {
-        getRenderEngine().setupColorTransform(mat4());
-    }
+    // Clear color transform matrix at the end of the frame.
+    getRenderEngine().setColorTransform(mat4());
 
     // disable scissor at the end of the frame
     getBE().mRenderEngine->disableScissor();
@@ -3596,6 +3631,11 @@
         if (layer->setColor(s.color))
             flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eColorTransformChanged) {
+        if (layer->setColorTransform(s.colorTransform)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     if (what & layer_state_t::eMatrixChanged) {
         // TODO: b/109894387
         //
@@ -5441,7 +5481,9 @@
     engine.clearWithColor(0, 0, 0, alpha);
 
     traverseLayers([&](Layer* layer) {
+        engine.setColorTransform(layer->getColorTransform());
         layer->draw(renderArea, useIdentityTransform);
+        engine.setColorTransform(mat4());
     });
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b77bf48..a0f7c75 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -191,6 +191,9 @@
     nsecs_t mTotalTime;
     std::atomic<nsecs_t> mLastSwapTime;
 
+    // Synchronization fence from a GL composition.
+    sp<Fence> flushFence = Fence::NO_FENCE;
+
     // Double- vs. triple-buffering stats
     struct BufferingStats {
         BufferingStats()
@@ -454,7 +457,6 @@
     status_t getCompositionPreference(ui::Dataspace* outDataSpace,
                                       ui::PixelFormat* outPixelFormat) const override;
 
-
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
      */
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index d77a324..0bc1c0a 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -32,11 +32,8 @@
 namespace android {
 
 TimeStats& TimeStats::getInstance() {
-    static std::unique_ptr<TimeStats> sInstance;
-    static std::once_flag sOnceFlag;
-
-    std::call_once(sOnceFlag, [] { sInstance.reset(new TimeStats); });
-    return *sInstance.get();
+    static TimeStats sInstance;
+    return sInstance;
 }
 
 void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, size_t& index,
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 3af98e5..3166a8c 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2064,6 +2064,34 @@
     Transaction().setSidebandStream(layer, nullptr).apply();
 }
 
+TEST_F(LayerTransactionTest, SetColorTransformBasic) {
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(
+            colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+
+    Transaction().setLayer(colorLayer, mLayerZBase + 1).apply();
+    {
+        SCOPED_TRACE("default color");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+    const Color expected = {90, 90, 90, 255};
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+    mat3 matrix;
+    matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
+    matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
+    matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
+    Transaction().setColor(colorLayer, color)
+        .setColorTransform(colorLayer, matrix, vec3()).apply();
+    {
+        SCOPED_TRACE("new color");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+    }
+}
+
 class LayerUpdateTest : public LayerTransactionTest {
 protected:
     virtual void SetUp() {
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 52e64d8..7b79fbd 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -325,7 +325,7 @@
         EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
         EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
                 .Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setupColorTransform(_)).Times(2);
+        EXPECT_CALL(*test->mRenderEngine, setColorTransform(_)).Times(2);
         // These expectations retire on saturation as the code path these
         // expectations are for appears to make an extra call to them.
         // TODO: Investigate this extra call
@@ -478,11 +478,8 @@
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
         EXPECT_CALL(*test->mRenderEngine, createImage())
                 .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
-        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, checkErrors()).Times(1);
-        EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, false)).WillOnce(Return(true));
         bool ignoredRecomputeVisibleRegions;
-        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, Fence::NO_FENCE);
         Mock::VerifyAndClear(test->mRenderEngine);
         Mock::VerifyAndClear(test->mReImage);
     }
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index c29452c..6813cda 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -62,7 +62,7 @@
     MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
     MOCK_METHOD0(setupLayerBlackedOut, void());
     MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
-    MOCK_METHOD1(setupColorTransform, void(const mat4&));
+    MOCK_METHOD1(setColorTransform, void(const mat4&));
     MOCK_METHOD1(setSaturationMatrix, void(const mat4&));
     MOCK_METHOD0(disableTexturing, void());
     MOCK_METHOD0(disableBlending, void());
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index def15f1..4ff9890 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -1,28 +1,58 @@
 #include <stdio.h>
 
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
 #include <log/log.h>
 #include <private/dvr/buffer_hub_binder.h>
 
 namespace android {
 namespace dvr {
 
-status_t BufferHubBinderService::start() {
-  ProcessState::self()->startThreadPool();
+status_t BufferHubBinderService::start(
+    const std::shared_ptr<BufferHubService> &pdx_service) {
   IPCThreadState::self()->disableBackgroundScheduling(true);
-  status_t result = BinderService<BufferHubBinderService>::publish();
-  if (result != OK) {
+
+  BufferHubBinderService* service = new BufferHubBinderService();
+  service->pdx_service_ = pdx_service;
+
+  // Not using BinderService::publish because need to get an instance of this
+  // class (above). Following code is the same as
+  // BinderService::publishAndJoinThreadPool
+  sp<IServiceManager> sm = defaultServiceManager();
+  status_t result = sm->addService(String16(getServiceName()), service,
+      /*allowIsolated =*/ false,
+      /*dump flags =*/ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+  if (result != NO_ERROR) {
     ALOGE("Publishing bufferhubd failed with error %d", result);
     return result;
   }
 
+  sp<ProcessState> process_self(ProcessState::self());
+  process_self->startThreadPool();
+  process_self->giveThreadPoolName();
+  IPCThreadState::self()->joinThreadPool();
+
   return result;
 }
 
-status_t BufferHubBinderService::dump(int fd, const Vector<String16> & /* args */) {
-  // TODO(b/115435506): not implemented yet
+status_t BufferHubBinderService::dump(int fd, const Vector<String16> &args) {
   FILE *out = fdopen(dup(fd), "w");
 
-  fprintf(out, "BufferHubBinderService::dump(): Not Implemented.\n");
+  // Currently not supporting args, so notify the user.
+  if (!args.isEmpty()){
+    fprintf(out, "Note: dumpsys bufferhubd currently does not support args."
+        "Input arguments are ignored.\n");
+  }
+
+  // TODO(b/116526156): output real data in this class once we have it
+  if (pdx_service_){
+    // BufferHubService::Dumpstate(size_t) is not actually using the param
+    // So just using 0 as the length
+    fprintf(out, "%s", pdx_service_->DumpState(0).c_str());
+  } else {
+    fprintf(out, "PDX service not registered or died.\n");
+  }
 
   fclose(out);
   return NO_ERROR;
@@ -30,4 +60,4 @@
 
 
 }  // namespace dvr
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp
index 0ca7edc..3e10b26 100644
--- a/services/vr/bufferhubd/bufferhubd.cpp
+++ b/services/vr/bufferhubd/bufferhubd.cpp
@@ -10,7 +10,7 @@
 
 int main(int, char**) {
   int ret = -1;
-  std::shared_ptr<android::pdx::Service> service;
+  std::shared_ptr<android::dvr::BufferHubService> pdx_service;
   std::unique_ptr<android::pdx::ServiceDispatcher> dispatcher;
 
   // We need to be able to create endpoints with full perms.
@@ -33,15 +33,16 @@
   else
     ALOGI("New nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max);
 
-  CHECK_ERROR(android::dvr::BufferHubBinderService::start() != android::OK,
-              error, "Failed to create bufferhub binder service\n");
-
   dispatcher = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n");
 
-  service = android::dvr::BufferHubService::Create();
-  CHECK_ERROR(!service, error, "Failed to create bufferhubd service\n");
-  dispatcher->AddService(service);
+  pdx_service = android::dvr::BufferHubService::Create();
+  CHECK_ERROR(!pdx_service, error, "Failed to create bufferhub pdx service\n");
+  dispatcher->AddService(pdx_service);
+
+  ret = android::dvr::BufferHubBinderService::start(pdx_service);
+  CHECK_ERROR(ret != android::NO_ERROR, error,
+              "Failed to create bufferhub binder service\n");
 
   ret = dvrSetSchedulerClass(0, "graphics");
   CHECK_ERROR(ret < 0, error, "Failed to set thread priority");
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index c0281fd..07f05cc 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -2,6 +2,7 @@
 #define ANDROID_DVR_BUFFER_HUB_BINDER_H
 
 #include <binder/BinderService.h>
+#include <private/dvr/buffer_hub.h>
 
 #include "android/dvr/BnBufferHub.h"
 
@@ -10,14 +11,17 @@
 
 class BufferHubBinderService : public BinderService<BufferHubBinderService>, public BnBufferHub {
  public:
-  static status_t start();
+  static status_t start(const std::shared_ptr<BufferHubService> &pdx_service);
   static const char* getServiceName() { return "bufferhubd"; }
   // Dump bufferhub related information to given fd (usually stdout)
   // usage: adb shell dumpsys bufferhubd
   virtual status_t dump(int fd, const Vector<String16> &args) override;
+
+ private:
+  std::shared_ptr<BufferHubService> pdx_service_;
 };
 
 }  // namespace dvr
 }  // namespace android
 
-#endif // ANDROID_DVR_BUFFER_HUB_BINDER_H
\ No newline at end of file
+#endif // ANDROID_DVR_BUFFER_HUB_BINDER_H
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index 4d1d43f..92bda78 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -6,11 +6,18 @@
         "-DTRACE=0",
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
-    static_libs: ["libbufferhubd"],
+    header_libs: ["libdvr_headers"],
+    static_libs: [
+        "libbufferhub",
+        "libbufferhubd",
+        "libgmock",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
         "liblog",
+        "libpdx_default_transport",
+        "libui",
         "libutils",
     ],
 }
\ No newline at end of file
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index e3f2825..0b64cf0 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -1,6 +1,7 @@
-#include <private/dvr/buffer_hub_binder.h>
-
+#include <binder/IServiceManager.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <private/dvr/buffer_hub_binder.h>
 
 namespace android {
 namespace dvr {
@@ -12,8 +13,12 @@
 };
 
 TEST_F(BufferHubBinderServiceTest, TestInitialize) {
-  // Test if start binder server returns OK
-  EXPECT_EQ(BufferHubBinderService::start(), OK);
+  // Create a new service will kill the current one.
+  // So just check if Binder service is running
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<IBinder> service = sm->checkService(
+      String16(BufferHubBinderService::getServiceName()));
+  EXPECT_THAT(service, ::testing::Ne(nullptr));
 }
 
 }  // namespace
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index fa63fbd..5722810 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 1
-define VERSION_PATCH 85
+define VERSION_PATCH 86
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -45,6 +45,10 @@
 define VK_QUEUE_FAMILY_EXTERNAL         -2
 @extension("VK_EXT_queue_family_foreign")
 define VK_QUEUE_FAMILY_FOREIGN_EXT      -3
+@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197
+define VK_MAX_DRIVER_NAME_SIZE_KHR      256
+@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197
+define VK_MAX_DRIVER_INFO_SIZE_KHR      256
 
 // API keywords
 define VK_TRUE        1
@@ -545,6 +549,10 @@
 @extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1
 @extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker"
 
+// 181
+@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1
+@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64"
+
 // 186
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
@@ -553,6 +561,10 @@
 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
 
+// 197
+@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1
+@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties"
+
 // 199
 @extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1
 @extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned"
@@ -1763,6 +1775,12 @@
     VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT                    = 1000178001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT   = 1000178002,
 
+    //@extension("VK_KHR_shader_atomic_int64") // 181
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR  = 1000180000,
+
+    //@extension("VK_KHR_driver_properties") // 197
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR             = 1000196000,
+
     //@extension("VK_AMD_shader_core_properties") // 186
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD        = 1000185000,
 
@@ -2264,6 +2282,19 @@
     VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT                   = 1024,
 }
 
+@extension("VK_KHR_driver_properties") // 197
+enum VkDriverIdKHR {
+    VK_DRIVER_ID_AMD_PROPRIETARY_KHR                        = 1,
+    VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR                        = 2,
+    VK_DRIVER_ID_MESA_RADV_KHR                              = 3,
+    VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR                     = 4,
+    VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR              = 5,
+    VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR                 = 6,
+    VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR                = 7,
+    VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR                   = 8,
+    VK_DRIVER_ID_ARM_PROPRIETARY_KHR                        = 9,
+}
+
 /////////////////
 //  Bitfields  //
 /////////////////
@@ -7214,6 +7245,14 @@
     VkDeviceSize                                    minImportedHostPointerAlignment
 }
 
+@extension("VK_KHR_shader_atomic_int64") // 181
+class VkPhysicalDeviceShaderAtomicInt64FeaturesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        shaderBufferInt64Atomics
+    VkBool32                                        shaderSharedInt64Atomics
+}
+
 @extension("VK_AMD_shader_core_properties") // 186
 class VkPhysicalDeviceShaderCorePropertiesAMD {
     VkStructureType                                 sType
@@ -7263,6 +7302,24 @@
     VkBool32                                        vertexAttributeInstanceRateZeroDivisor
 }
 
+@extension("VK_KHR_driver_properties") // 197
+class VkConformanceVersionKHR {
+    u8                                              major
+    u8                                              minor
+    u8                                              subminor
+    u8                                              patch
+}
+
+@extension("VK_KHR_driver_properties") // 197
+class VkPhysicalDeviceDriverPropertiesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             driverID
+    char[VK_MAX_DRIVER_NAME_SIZE_KHR]               driverName
+    char[VK_MAX_DRIVER_INFO_SIZE_KHR]               driverInfo
+    VkConformanceVersionKHR                         conformanceVersion
+}
+
 @extension("VK_NV_compute_shader_derivatives") // 202
 class VkPhysicalDeviceComputeShaderDerivativesFeaturesNV {
     VkStructureType                                 sType
@@ -11168,42 +11225,42 @@
 
 @extension("VK_NVX_raytracing") // 166
 cmd void vkCmdBuildAccelerationStructureNVX(
-        VkCommandBuffer                         cmdBuf,
-        VkAccelerationStructureTypeNVX          type,
-        u32                                     instanceCount,
-        VkBuffer                                instanceData,
-        VkDeviceSize                            instanceOffset,
-        u32                                     geometryCount,
-        const VkGeometryNVX*                    pGeometries,
-        VkBuildAccelerationStructureFlagsNVX    flags,
-        VkBool32                                update,
-        VkAccelerationStructureNVX              dst,
-        VkAccelerationStructureNVX              src,
-        VkBuffer                                scratch,
-        VkDeviceSize                            scratchOffset) {
+        VkCommandBuffer                             commandBuffer,
+        VkAccelerationStructureTypeNVX              type,
+        u32                                         instanceCount,
+        VkBuffer                                    instanceData,
+        VkDeviceSize                                instanceOffset,
+        u32                                         geometryCount,
+        const VkGeometryNVX*                        pGeometries,
+        VkBuildAccelerationStructureFlagsNVX        flags,
+        VkBool32                                    update,
+        VkAccelerationStructureNVX                  dst,
+        VkAccelerationStructureNVX                  src,
+        VkBuffer                                    scratch,
+        VkDeviceSize                                scratchOffset) {
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd void vkCmdCopyAccelerationStructureNVX(
-        VkCommandBuffer                         cmdBuf,
-        VkAccelerationStructureNVX              dst,
-        VkAccelerationStructureNVX              src,
-        VkCopyAccelerationStructureModeNVX      mode) {
+        VkCommandBuffer                             commandBuffer,
+        VkAccelerationStructureNVX                  dst,
+        VkAccelerationStructureNVX                  src,
+        VkCopyAccelerationStructureModeNVX          mode) {
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd void vkCmdTraceRaysNVX(
-        VkCommandBuffer                         cmdBuf,
-        VkBuffer                                raygenShaderBindingTableBuffer,
-        VkDeviceSize                            raygenShaderBindingOffset,
-        VkBuffer                                missShaderBindingTableBuffer,
-        VkDeviceSize                            missShaderBindingOffset,
-        VkDeviceSize                            missShaderBindingStride,
-        VkBuffer                                hitShaderBindingTableBuffer,
-        VkDeviceSize                            hitShaderBindingOffset,
-        VkDeviceSize                            hitShaderBindingStride,
-        u32                                     width,
-        u32                                     height) {
+        VkCommandBuffer                             commandBuffer,
+        VkBuffer                                    raygenShaderBindingTableBuffer,
+        VkDeviceSize                                raygenShaderBindingOffset,
+        VkBuffer                                    missShaderBindingTableBuffer,
+        VkDeviceSize                                missShaderBindingOffset,
+        VkDeviceSize                                missShaderBindingStride,
+        VkBuffer                                    hitShaderBindingTableBuffer,
+        VkDeviceSize                                hitShaderBindingOffset,
+        VkDeviceSize                                hitShaderBindingStride,
+        u32                                         width,
+        u32                                         height) {
 }
 
 @extension("VK_NVX_raytracing") // 166
@@ -11219,38 +11276,38 @@
 
 @extension("VK_NVX_raytracing") // 166
 cmd VkResult vkGetRaytracingShaderHandlesNVX(
-        VkDevice                                device,
-        VkPipeline                              pipeline,
-        u32                                     firstGroup,
-        u32                                     groupCount,
-        platform.size_t                         dataSize,
-        void*                                   pData) {
+        VkDevice                                    device,
+        VkPipeline                                  pipeline,
+        u32                                         firstGroup,
+        u32                                         groupCount,
+        platform.size_t                             dataSize,
+        void*                                       pData) {
     return ?
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd VkResult vkGetAccelerationStructureHandleNVX(
-        VkDevice                                device,
-        VkAccelerationStructureNVX              accelerationStructure,
-        platform.size_t                         dataSize,
-        void*                                   pData) {
+        VkDevice                                    device,
+        VkAccelerationStructureNVX                  accelerationStructure,
+        platform.size_t                             dataSize,
+        void*                                       pData) {
     return ?
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd void vkCmdWriteAccelerationStructurePropertiesNVX(
-        VkCommandBuffer                         cmdBuf,
-        VkAccelerationStructureNVX              accelerationStructure,
-        VkQueryType                             queryType,
-        VkQueryPool                             queryPool,
-        u32                                     query) {
+        VkCommandBuffer                             commandBuffer,
+        VkAccelerationStructureNVX                  accelerationStructure,
+        VkQueryType                                 queryType,
+        VkQueryPool                                 queryPool,
+        u32                                         query) {
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd VkResult vkCompileDeferredNVX(
-        VkDevice                                device,
-        VkPipeline                              pipeline,
-        u32                                     shader) {
+        VkDevice                                    device,
+        VkPipeline                                  pipeline,
+        u32                                         shader) {
     return ?
 }
 
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index 2d1b3f5..39f4dc6 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,7 +43,7 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 85
+#define VK_HEADER_VERSION 86
 
 
 #define VK_NULL_HANDLE 0
@@ -427,10 +427,12 @@
     VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000,
     VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001,
@@ -6044,6 +6046,60 @@
 
 
 
+#define VK_KHR_shader_atomic_int64 1
+#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1
+#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64"
+
+typedef struct VkPhysicalDeviceShaderAtomicInt64FeaturesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           shaderBufferInt64Atomics;
+    VkBool32           shaderSharedInt64Atomics;
+} VkPhysicalDeviceShaderAtomicInt64FeaturesKHR;
+
+
+
+#define VK_KHR_driver_properties 1
+#define VK_MAX_DRIVER_NAME_SIZE_KHR       256
+#define VK_MAX_DRIVER_INFO_SIZE_KHR       256
+#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1
+#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties"
+
+
+typedef enum VkDriverIdKHR {
+    VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1,
+    VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2,
+    VK_DRIVER_ID_MESA_RADV_KHR = 3,
+    VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4,
+    VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5,
+    VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6,
+    VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7,
+    VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8,
+    VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9,
+    VK_DRIVER_ID_BEGIN_RANGE_KHR = VK_DRIVER_ID_AMD_PROPRIETARY_KHR,
+    VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_ARM_PROPRIETARY_KHR,
+    VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_ARM_PROPRIETARY_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1),
+    VK_DRIVER_ID_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkDriverIdKHR;
+
+typedef struct VkConformanceVersionKHR {
+    uint8_t    major;
+    uint8_t    minor;
+    uint8_t    subminor;
+    uint8_t    patch;
+} VkConformanceVersionKHR;
+
+typedef struct VkPhysicalDeviceDriverPropertiesKHR {
+    VkStructureType            sType;
+    void*                      pNext;
+    uint32_t                   driverID;
+    char                       driverName[VK_MAX_DRIVER_NAME_SIZE_KHR];
+    char                       driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR];
+    VkConformanceVersionKHR    conformanceVersion;
+} VkPhysicalDeviceDriverPropertiesKHR;
+
+
+
 #define VK_KHR_vulkan_memory_model 1
 #define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
 #define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
@@ -8044,13 +8100,13 @@
 typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
 typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureScratchMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
 typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNVX)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
-typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
-typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer cmdBuf, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
+typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
+typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
 typedef VkResult (VKAPI_PTR *PFN_vkCreateRaytracingPipelinesNVX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
 typedef VkResult (VKAPI_PTR *PFN_vkGetRaytracingShaderHandlesNVX)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
 typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, size_t dataSize, void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
+typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
 typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNVX)(VkDevice device, VkPipeline pipeline, uint32_t shader);
 
 #ifndef VK_NO_PROTOTYPES
@@ -8081,7 +8137,7 @@
     const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
 
 VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNVX(
-    VkCommandBuffer                             cmdBuf,
+    VkCommandBuffer                             commandBuffer,
     VkAccelerationStructureTypeNVX              type,
     uint32_t                                    instanceCount,
     VkBuffer                                    instanceData,
@@ -8096,13 +8152,13 @@
     VkDeviceSize                                scratchOffset);
 
 VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNVX(
-    VkCommandBuffer                             cmdBuf,
+    VkCommandBuffer                             commandBuffer,
     VkAccelerationStructureNVX                  dst,
     VkAccelerationStructureNVX                  src,
     VkCopyAccelerationStructureModeNVX          mode);
 
 VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNVX(
-    VkCommandBuffer                             cmdBuf,
+    VkCommandBuffer                             commandBuffer,
     VkBuffer                                    raygenShaderBindingTableBuffer,
     VkDeviceSize                                raygenShaderBindingOffset,
     VkBuffer                                    missShaderBindingTableBuffer,
@@ -8137,7 +8193,7 @@
     void*                                       pData);
 
 VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructurePropertiesNVX(
-    VkCommandBuffer                             cmdBuf,
+    VkCommandBuffer                             commandBuffer,
     VkAccelerationStructureNVX                  accelerationStructure,
     VkQueryType                                 queryType,
     VkQueryPool                                 queryPool,
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index b32977a..009b257 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -78,7 +78,7 @@
           native_bridge_(false),
           refcount_(0) {}
 
-    LayerLibrary(LayerLibrary&& other)
+    LayerLibrary(LayerLibrary&& other) noexcept
         : path_(std::move(other.path_)),
           filename_(std::move(other.filename_)),
           dlhandle_(other.dlhandle_),
@@ -545,7 +545,7 @@
     }
 }
 
-LayerRef::LayerRef(LayerRef&& other) : layer_(other.layer_) {
+LayerRef::LayerRef(LayerRef&& other) noexcept : layer_(other.layer_) {
     other.layer_ = nullptr;
 }
 
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 07ac1a3..1dae456 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -27,7 +27,7 @@
 class LayerRef {
    public:
     explicit LayerRef(const Layer* layer);
-    LayerRef(LayerRef&& other);
+    LayerRef(LayerRef&& other) noexcept;
     ~LayerRef();
     LayerRef(const LayerRef&) = delete;
     LayerRef& operator=(const LayerRef&) = delete;