Merge "[RenderEngine] Support extended SRGB transform."
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index b850390..bb84a18 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -18,8 +18,6 @@
         "libcutils",
         "libz",
         "libbase",
-    ],
-    static_libs: [
         "libpdx_default_transport",
     ],
 
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 90c7da4..352cf0a 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -92,4 +92,28 @@
     ],
 }
 
+//
+// Static library for otapreopt used in testing
+//
+cc_library_static {
+    name: "libotapreoptparameters",
+    cflags: [
+        "-Wall",
+        "-Werror"
+    ],
+    clang: true,
+
+    srcs: [
+        "otapreopt_parameters.cpp"],
+
+    export_include_dirs: ["."],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+}
+
 subdirs = ["tests"]
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index b3dc5ec..a4f95da 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA)
 LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA)
 
-LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp
+LOCAL_SRC_FILES := otapreopt.cpp otapreopt_parameters.cpp globals.cpp utils.cpp dexopt.cpp
 LOCAL_HEADER_LIBRARIES := dex2oat_headers
 LOCAL_SHARED_LIBRARIES := \
     libbase \
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a2c8542..0d50b9b 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1895,13 +1895,18 @@
     return ok();
 }
 
+static const char* getCStr(const std::unique_ptr<std::string>& data,
+        const char* default_value = nullptr) {
+    return data == nullptr ? default_value : data->c_str();
+}
 binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
         const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
         int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
         const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
         const std::unique_ptr<std::string>& classLoaderContext,
         const std::unique_ptr<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
-        const std::unique_ptr<std::string>& profileName) {
+        const std::unique_ptr<std::string>& profileName,
+        const std::unique_ptr<std::string>& dexMetadataPath) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     if (packageName && *packageName != "*") {
@@ -1910,17 +1915,18 @@
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
-    const char* pkgname = packageName ? packageName->c_str() : "*";
+    const char* pkgname = getCStr(packageName, "*");
     const char* instruction_set = instructionSet.c_str();
-    const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
+    const char* oat_dir = getCStr(outputPath);
     const char* compiler_filter = compilerFilter.c_str();
-    const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
-    const char* class_loader_context = classLoaderContext ? classLoaderContext->c_str() : nullptr;
-    const char* se_info = seInfo ? seInfo->c_str() : nullptr;
-    const char* profile_name = profileName ? profileName->c_str() : nullptr;
+    const char* volume_uuid = getCStr(uuid);
+    const char* class_loader_context = getCStr(classLoaderContext);
+    const char* se_info = getCStr(seInfo);
+    const char* profile_name = getCStr(profileName);
+    const char* dm_path = getCStr(dexMetadataPath);
     int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
             oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
-            downgrade, targetSdkVersion, profile_name);
+            downgrade, targetSdkVersion, profile_name, dm_path);
     return res ? error(res, "Failed to dexopt") : ok();
 }
 
@@ -2356,8 +2362,8 @@
     __u8 root_hash[64];
 };
 
-#define FS_IOC_MEASURE_FSVERITY        _IOW('f', 2733, struct fsverity_root_hash)
-#define FS_IOC_SET_FSVERITY            _IOW('f', 2734, struct fsverity_set)
+#define FS_IOC_MEASURE_FSVERITY        _IOW('f', 133, struct fsverity_root_hash)
+#define FS_IOC_SET_FSVERITY            _IOW('f', 134, struct fsverity_set)
 
 #define FSVERITY_FLAG_ENABLED          0x0001
 #endif
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5bf8ae2..22b1d12 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -85,7 +85,8 @@
             const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
             const std::unique_ptr<std::string>& classLoaderContext,
             const std::unique_ptr<std::string>& seInfo, bool downgrade,
-            int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName);
+            int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName,
+            const std::unique_ptr<std::string>& dexMetadataPath);
 
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 3133b4f..e07c847 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -52,7 +52,8 @@
             @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
             @nullable @utf8InCpp String sharedLibraries,
             @nullable @utf8InCpp String seInfo, boolean downgrade, int targetSdkVersion,
-            @nullable @utf8InCpp String profileName);
+            @nullable @utf8InCpp String profileName,
+            @nullable @utf8InCpp String dexMetadataPath);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index abbd62d..b456507 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -223,7 +223,8 @@
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
         bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
-        const char* class_loader_context, int target_sdk_version, bool disable_hidden_api_checks) {
+        const char* class_loader_context, int target_sdk_version, bool disable_hidden_api_checks,
+        int dex_metadata_fd) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -420,6 +421,7 @@
         sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
     }
 
+    std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
 
     ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
 
@@ -450,7 +452,8 @@
                      + (disable_cdex ? 1 : 0)
                      + (generate_minidebug_info ? 1 : 0)
                      + (target_sdk_version != 0 ? 2 : 0)
-                     + (disable_hidden_api_checks ? 2 : 0)];
+                     + (disable_hidden_api_checks ? 2 : 0)
+                     + (dex_metadata_fd > -1 ? 1 : 0)];
     int i = 0;
     argv[i++] = dex2oat_bin;
     argv[i++] = zip_fd_arg;
@@ -529,6 +532,9 @@
         argv[i++] = "-Xno-hidden-api-checks";
     }
 
+    if (dex_metadata_fd > -1) {
+        argv[i++] = dex_metadata_fd_arg.c_str();
+    }
     // Do not add after dex2oat_flags, they should override others for debugging.
     argv[i] = NULL;
 
@@ -715,13 +721,20 @@
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
-static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
-        const unique_fd& reference_profile_fd, const std::vector<unique_fd>* apk_fds = nullptr) {
+static void run_profman(const std::vector<unique_fd>& profile_fds,
+                        const unique_fd& reference_profile_fd,
+                        const std::vector<unique_fd>* apk_fds,
+                        bool copy_and_update) {
     const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
 
-    std::vector<std::string> profile_args(profiles_fd.size());
-    for (size_t k = 0; k < profiles_fd.size(); k++) {
-        profile_args[k] = "--profile-file-fd=" + std::to_string(profiles_fd[k].get());
+    if (copy_and_update) {
+        CHECK_EQ(1u, profile_fds.size());
+        CHECK(apk_fds != nullptr);
+        CHECK_EQ(1u, apk_fds->size());
+    }
+    std::vector<std::string> profile_args(profile_fds.size());
+    for (size_t k = 0; k < profile_fds.size(); k++) {
+        profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
     }
     std::string reference_profile_arg = "--reference-profile-file-fd="
             + std::to_string(reference_profile_fd.get());
@@ -734,7 +747,7 @@
     }
 
     // program name, reference profile fd, the final NULL and the profile fds
-    const char* argv[3 + profile_args.size() + apk_args.size()];
+    const char* argv[3 + profile_args.size() + apk_args.size() + (copy_and_update ? 1 : 0)];
     int i = 0;
     argv[i++] = profman_bin;
     argv[i++] = reference_profile_arg.c_str();
@@ -744,6 +757,9 @@
     for (size_t k = 0; k < apk_args.size(); k++) {
         argv[i++] = apk_args[k].c_str();
     }
+    if (copy_and_update) {
+        argv[i++] = "--copy-and-update-profile-key";
+    }
     // Do not add after dex2oat_flags, they should override others for debugging.
     argv[i] = NULL;
 
@@ -752,6 +768,25 @@
     exit(68);   /* only get here on exec failure */
 }
 
+
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+                              const unique_fd& reference_profile_fd,
+                              const std::vector<unique_fd>* apk_fds = nullptr) {
+    run_profman(profiles_fd, reference_profile_fd, apk_fds, /*copy_and_update*/false);
+}
+
+
+static void run_profman_copy_and_update(unique_fd&& profile_fd,
+                                        unique_fd&& reference_profile_fd,
+                                        unique_fd&& apk_fd) {
+    std::vector<unique_fd> profiles_fd;
+    profiles_fd.push_back(std::move(profile_fd));
+    std::vector<unique_fd> apk_fds;
+    apk_fds.push_back(std::move(apk_fd));
+
+    run_profman(profiles_fd, reference_profile_fd, &apk_fds, /*copy_and_update*/true);
+}
+
 // Decides if profile guided compilation is needed or not based on existing profiles.
 // The location is the package name for primary apks or the dex path for secondary dex files.
 // Returns true if there is enough information in the current profiles that makes it
@@ -1292,9 +1327,21 @@
 Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
         const std::string& dex_path, const char* profile_name, bool profile_guided,
         bool is_public, int uid, bool is_secondary_dex) {
-    // Public apps should not be compiled with profile information ever. Same goes for the special
-    // package '*' used for the system server.
-    if (!profile_guided || is_public || (pkgname[0] == '*')) {
+    // If we are not profile guided compilation, or we are compiling system server
+    // do not bother to open the profiles; we won't be using them.
+    if (!profile_guided || (pkgname[0] == '*')) {
+        return Dex2oatFileWrapper();
+    }
+
+    // If this is a secondary dex path which is public do not open the profile.
+    // We cannot compile public secondary dex paths with profiles. That's because
+    // it will expose how the dex files are used by their owner.
+    //
+    // Note that the PackageManager is responsible to set the is_public flag for
+    // primary apks and we do not check it here. In some cases, e.g. when
+    // compiling with a public profile from the .dm file the PackageManager will
+    // set is_public toghether with the profile guided compilation.
+    if (is_secondary_dex && is_public) {
         return Dex2oatFileWrapper();
     }
 
@@ -1817,7 +1864,8 @@
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
-        bool downgrade, int target_sdk_version, const char* profile_name) {
+        bool downgrade, int target_sdk_version, const char* profile_name,
+        const char* dex_metadata_path) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
     if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
@@ -1908,6 +1956,14 @@
     Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
             pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);
 
+    unique_fd dex_metadata_fd;
+    if (dex_metadata_path != nullptr) {
+        dex_metadata_fd.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)));
+        if (dex_metadata_fd.get() < 0) {
+            PLOG(ERROR) << "Failed to open dex metadata file " << dex_metadata_path;
+        }
+    }
+
     ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
 
     pid_t pid = fork();
@@ -1937,7 +1993,8 @@
                     reference_profile_fd.get(),
                     class_loader_context,
                     target_sdk_version,
-                    disable_hidden_api_checks);
+                    disable_hidden_api_checks,
+                    dex_metadata_fd.get());
         _exit(68);   /* only get here on exec failure */
     } else {
         int res = wait_child(pid);
@@ -2610,7 +2667,7 @@
                          userid_t user_id,
                          appid_t app_id,
                          const std::string& profile_name,
-                         const std::string& code_path ATTRIBUTE_UNUSED,
+                         const std::string& code_path,
                          const std::unique_ptr<std::string>& dex_metadata) {
     // Prepare the current profile.
     std::string cur_profile  = create_current_profile_path(user_id, package_name, profile_name,
@@ -2631,8 +2688,11 @@
             /*read_write*/ true, /*is_secondary_dex*/ false);
     unique_fd dex_metadata_fd(TEMP_FAILURE_RETRY(
             open(dex_metadata->c_str(), O_RDONLY | O_NOFOLLOW)));
-    std::vector<unique_fd> profiles_fd;
-    profiles_fd.push_back(std::move(dex_metadata_fd));
+    unique_fd apk_fd(TEMP_FAILURE_RETRY(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW)));
+    if (apk_fd < 0) {
+        PLOG(ERROR) << "Could not open code path " << code_path;
+        return false;
+    }
 
     pid_t pid = fork();
     if (pid == 0) {
@@ -2640,10 +2700,10 @@
         gid_t app_shared_gid = multiuser_get_shared_gid(user_id, app_id);
         drop_capabilities(app_shared_gid);
 
-        // TODO(calin): the dex metadata profile might embed different names for the
-        // same code path (e.g. YouTube.apk or base.apk, depending on how the initial
-        // profile was captured). We should pass the code path to adjust the names in the profile.
-        run_profman_merge(profiles_fd, ref_profile_fd);
+        // The copy and update takes ownership over the fds.
+        run_profman_copy_and_update(std::move(dex_metadata_fd),
+                                    std::move(ref_profile_fd),
+                                    std::move(apk_fd));
         exit(42);   /* only get here on exec failure */
     }
 
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 93cf545..ae1412e 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -105,7 +105,8 @@
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
-        bool downgrade, int target_sdk_version, const char* profile_name);
+        bool downgrade, int target_sdk_version, const char* profile_name,
+        const char* dexMetadataPath);
 
 bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
         const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 74dca72..72d01a5 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -43,6 +43,7 @@
 #include "globals.h"
 #include "installd_constants.h"
 #include "installd_deps.h"  // Need to fill in requirements of commands.
+#include "otapreopt_parameters.h"
 #include "otapreopt_utils.h"
 #include "system_properties.h"
 #include "utils.h"
@@ -158,32 +159,15 @@
     }
 
     std::string GetOTADataDirectory() const {
-        return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), target_slot_.c_str());
+        return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), GetTargetSlot().c_str());
     }
 
     const std::string& GetTargetSlot() const {
-        return target_slot_;
+        return parameters_.target_slot;
     }
 
 private:
 
-    struct Parameters {
-        const char *apk_path;
-        uid_t uid;
-        const char *pkgName;
-        const char *instruction_set;
-        int dexopt_needed;
-        const char* oat_dir;
-        int dexopt_flags;
-        const char* compiler_filter;
-        const char* volume_uuid;
-        const char* shared_libraries;
-        const char* se_info;
-        bool downgrade;
-        int target_sdk_version;
-        const char* profile_name;
-    };
-
     bool ReadSystemProperties() {
         static constexpr const char* kPropertyFiles[] = {
                 "/default.prop", "/system/build.prop"
@@ -307,546 +291,7 @@
     }
 
     bool ReadArguments(int argc, char** argv) {
-        // Expected command line:
-        //   target-slot [version] dexopt {DEXOPT_PARAMETERS}
-
-        const char* target_slot_arg = argv[1];
-        if (target_slot_arg == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        // Sanitize value. Only allow (a-zA-Z0-9_)+.
-        target_slot_ = target_slot_arg;
-        if (!ValidateTargetSlotSuffix(target_slot_)) {
-            LOG(ERROR) << "Target slot suffix not legal: " << target_slot_;
-            return false;
-        }
-
-        // Check for version or "dexopt" next.
-        if (argv[2] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-
-        if (std::string("dexopt").compare(argv[2]) == 0) {
-            // This is version 1 (N) or pre-versioning version 2.
-            constexpr int kV2ArgCount =   1   // "otapreopt"
-                                        + 1   // slot
-                                        + 1   // "dexopt"
-                                        + 1   // apk_path
-                                        + 1   // uid
-                                        + 1   // pkg
-                                        + 1   // isa
-                                        + 1   // dexopt_needed
-                                        + 1   // oat_dir
-                                        + 1   // dexopt_flags
-                                        + 1   // filter
-                                        + 1   // volume
-                                        + 1   // libs
-                                        + 1;  // seinfo
-            if (argc == kV2ArgCount) {
-                return ReadArgumentsV2(argc, argv, false);
-            } else {
-                return ReadArgumentsV1(argc, argv);
-            }
-        }
-
-        uint32_t version;
-        if (!ParseUInt(argv[2], &version)) {
-            LOG(ERROR) << "Could not parse version: " << argv[2];
-            return false;
-        }
-
-        switch (version) {
-            case 2:
-                return ReadArgumentsV2(argc, argv, true);
-            case 3:
-                return ReadArgumentsV3(argc, argv);
-            case 4:
-                return ReadArgumentsV4(argc, argv);
-            case 5:
-                return ReadArgumentsV5(argc, argv);
-
-            default:
-                LOG(ERROR) << "Unsupported version " << version;
-                return false;
-        }
-    }
-
-    bool ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, char** argv, bool versioned) {
-        size_t dexopt_index = versioned ? 3 : 2;
-
-        // Check for "dexopt".
-        if (argv[dexopt_index] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
-            LOG(ERROR) << "Expected \"dexopt\"";
-            return false;
-        }
-
-        size_t param_index = 0;
-        for (;; ++param_index) {
-            const char* param = argv[dexopt_index + 1 + param_index];
-            if (param == nullptr) {
-                break;
-            }
-
-            switch (param_index) {
-                case 0:
-                    package_parameters_.apk_path = param;
-                    break;
-
-                case 1:
-                    package_parameters_.uid = atoi(param);
-                    break;
-
-                case 2:
-                    package_parameters_.pkgName = param;
-                    break;
-
-                case 3:
-                    package_parameters_.instruction_set = param;
-                    break;
-
-                case 4:
-                    package_parameters_.dexopt_needed = atoi(param);
-                    break;
-
-                case 5:
-                    package_parameters_.oat_dir = param;
-                    break;
-
-                case 6:
-                    package_parameters_.dexopt_flags = atoi(param);
-                    break;
-
-                case 7:
-                    package_parameters_.compiler_filter = param;
-                    break;
-
-                case 8:
-                    package_parameters_.volume_uuid = ParseNull(param);
-                    break;
-
-                case 9:
-                    package_parameters_.shared_libraries = ParseNull(param);
-                    break;
-
-                case 10:
-                    package_parameters_.se_info = ParseNull(param);
-                    break;
-
-                default:
-                    LOG(ERROR) << "Too many arguments, got " << param;
-                    return false;
-            }
-        }
-
-        // Set downgrade to false. It is only relevant when downgrading compiler
-        // filter, which is not the case during ota.
-        package_parameters_.downgrade = false;
-
-        // Set target_sdk_version to 0, ie the platform SDK version. This is
-        // conservative and may force some classes to verify at runtime.
-        package_parameters_.target_sdk_version = 0;
-
-        // Set the profile name to the primary apk profile.
-        package_parameters_.profile_name = "primary.prof";
-
-        if (param_index != 11) {
-            LOG(ERROR) << "Not enough parameters";
-            return false;
-        }
-
-        return true;
-    }
-
-    bool ReadArgumentsV3(int argc ATTRIBUTE_UNUSED, char** argv) {
-        size_t dexopt_index = 3;
-
-        // Check for "dexopt".
-        if (argv[dexopt_index] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
-            LOG(ERROR) << "Expected \"dexopt\"";
-            return false;
-        }
-
-        size_t param_index = 0;
-        for (;; ++param_index) {
-            const char* param = argv[dexopt_index + 1 + param_index];
-            if (param == nullptr) {
-                break;
-            }
-
-            switch (param_index) {
-                case 0:
-                    package_parameters_.apk_path = param;
-                    break;
-
-                case 1:
-                    package_parameters_.uid = atoi(param);
-                    break;
-
-                case 2:
-                    package_parameters_.pkgName = param;
-                    break;
-
-                case 3:
-                    package_parameters_.instruction_set = param;
-                    break;
-
-                case 4:
-                    package_parameters_.dexopt_needed = atoi(param);
-                    break;
-
-                case 5:
-                    package_parameters_.oat_dir = param;
-                    break;
-
-                case 6:
-                    package_parameters_.dexopt_flags = atoi(param);
-                    break;
-
-                case 7:
-                    package_parameters_.compiler_filter = param;
-                    break;
-
-                case 8:
-                    package_parameters_.volume_uuid = ParseNull(param);
-                    break;
-
-                case 9:
-                    package_parameters_.shared_libraries = ParseNull(param);
-                    break;
-
-                case 10:
-                    package_parameters_.se_info = ParseNull(param);
-                    break;
-
-                case 11:
-                    package_parameters_.downgrade = ParseBool(param);
-                    break;
-
-                default:
-                    LOG(ERROR) << "Too many arguments, got " << param;
-                    return false;
-            }
-        }
-
-        // Set target_sdk_version to 0, ie the platform SDK version. This is
-        // conservative and may force some classes to verify at runtime.
-        package_parameters_.target_sdk_version = 0;
-
-        // Set the profile name to the primary apk profile.
-        package_parameters_.profile_name = "primary.prof";
-
-        if (param_index != 12) {
-            LOG(ERROR) << "Not enough parameters";
-            return false;
-        }
-
-        return true;
-    }
-
-    bool ReadArgumentsV4(int argc ATTRIBUTE_UNUSED, char** argv) {
-        size_t dexopt_index = 3;
-
-        // Check for "dexopt".
-        if (argv[dexopt_index] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
-            LOG(ERROR) << "Expected \"dexopt\"";
-            return false;
-        }
-
-        size_t param_index = 0;
-        for (;; ++param_index) {
-            const char* param = argv[dexopt_index + 1 + param_index];
-            if (param == nullptr) {
-                break;
-            }
-
-            switch (param_index) {
-                case 0:
-                    package_parameters_.apk_path = param;
-                    break;
-
-                case 1:
-                    package_parameters_.uid = atoi(param);
-                    break;
-
-                case 2:
-                    package_parameters_.pkgName = param;
-                    break;
-
-                case 3:
-                    package_parameters_.instruction_set = param;
-                    break;
-
-                case 4:
-                    package_parameters_.dexopt_needed = atoi(param);
-                    break;
-
-                case 5:
-                    package_parameters_.oat_dir = param;
-                    break;
-
-                case 6:
-                    package_parameters_.dexopt_flags = atoi(param);
-                    break;
-
-                case 7:
-                    package_parameters_.compiler_filter = param;
-                    break;
-
-                case 8:
-                    package_parameters_.volume_uuid = ParseNull(param);
-                    break;
-
-                case 9:
-                    package_parameters_.shared_libraries = ParseNull(param);
-                    break;
-
-                case 10:
-                    package_parameters_.se_info = ParseNull(param);
-                    break;
-
-                case 11:
-                    package_parameters_.downgrade = ParseBool(param);
-                    break;
-
-                case 12:
-                    package_parameters_.target_sdk_version = atoi(param);
-                    break;
-
-                default:
-                    LOG(ERROR) << "Too many arguments, got " << param;
-                    return false;
-            }
-        }
-
-        // Set the profile name to the primary apk profile.
-        package_parameters_.profile_name = "primary.prof";
-
-        if (param_index != 13) {
-            LOG(ERROR) << "Not enough parameters";
-            return false;
-        }
-
-        return true;
-    }
-
-    // TODO: this pattern does not scale and result in a lot of code duplication.
-    // Either find a better pattern or refactor the code to eliminate the duplication.
-    bool ReadArgumentsV5(int argc ATTRIBUTE_UNUSED, char** argv) {
-        size_t dexopt_index = 3;
-
-        // Check for "dexopt".
-        if (argv[dexopt_index] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
-            LOG(ERROR) << "Expected \"dexopt\"";
-            return false;
-        }
-
-        size_t param_index = 0;
-        for (;; ++param_index) {
-            const char* param = argv[dexopt_index + 1 + param_index];
-            if (param == nullptr) {
-                break;
-            }
-
-            switch (param_index) {
-                case 0:
-                    package_parameters_.apk_path = param;
-                    break;
-
-                case 1:
-                    package_parameters_.uid = atoi(param);
-                    break;
-
-                case 2:
-                    package_parameters_.pkgName = param;
-                    break;
-
-                case 3:
-                    package_parameters_.instruction_set = param;
-                    break;
-
-                case 4:
-                    package_parameters_.dexopt_needed = atoi(param);
-                    break;
-
-                case 5:
-                    package_parameters_.oat_dir = param;
-                    break;
-
-                case 6:
-                    package_parameters_.dexopt_flags = atoi(param);
-                    break;
-
-                case 7:
-                    package_parameters_.compiler_filter = param;
-                    break;
-
-                case 8:
-                    package_parameters_.volume_uuid = ParseNull(param);
-                    break;
-
-                case 9:
-                    package_parameters_.shared_libraries = ParseNull(param);
-                    break;
-
-                case 10:
-                    package_parameters_.se_info = ParseNull(param);
-                    break;
-
-                case 11:
-                    package_parameters_.downgrade = ParseBool(param);
-                    break;
-
-                case 12:
-                    package_parameters_.target_sdk_version = atoi(param);
-                    break;
-
-                case 13:
-                    package_parameters_.profile_name = ParseNull(param);
-                    break;
-
-                default:
-                    LOG(ERROR) << "Too many arguments, got " << param;
-                    return false;
-            }
-        }
-
-        if (param_index != 14) {
-            LOG(ERROR) << "Not enough parameters";
-            return false;
-        }
-
-        return true;
-    }
-
-    static int ReplaceMask(int input, int old_mask, int new_mask) {
-        return (input & old_mask) != 0 ? new_mask : 0;
-    }
-
-    bool ReadArgumentsV1(int argc ATTRIBUTE_UNUSED, char** argv) {
-        // Check for "dexopt".
-        if (argv[2] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        if (std::string("dexopt").compare(argv[2]) != 0) {
-            LOG(ERROR) << "Expected \"dexopt\"";
-            return false;
-        }
-
-        size_t param_index = 0;
-        for (;; ++param_index) {
-            const char* param = argv[3 + param_index];
-            if (param == nullptr) {
-                break;
-            }
-
-            switch (param_index) {
-                case 0:
-                    package_parameters_.apk_path = param;
-                    break;
-
-                case 1:
-                    package_parameters_.uid = atoi(param);
-                    break;
-
-                case 2:
-                    package_parameters_.pkgName = param;
-                    break;
-
-                case 3:
-                    package_parameters_.instruction_set = param;
-                    break;
-
-                case 4: {
-                    // Version 1 had:
-                    //   DEXOPT_DEX2OAT_NEEDED       = 1
-                    //   DEXOPT_PATCHOAT_NEEDED      = 2
-                    //   DEXOPT_SELF_PATCHOAT_NEEDED = 3
-                    // We will simply use DEX2OAT_FROM_SCRATCH.
-                    package_parameters_.dexopt_needed = DEX2OAT_FROM_SCRATCH;
-                    break;
-                }
-
-                case 5:
-                    package_parameters_.oat_dir = param;
-                    break;
-
-                case 6: {
-                    // Version 1 had:
-                    constexpr int OLD_DEXOPT_PUBLIC         = 1 << 1;
-                    // Note: DEXOPT_SAFEMODE has been removed.
-                    // constexpr int OLD_DEXOPT_SAFEMODE       = 1 << 2;
-                    constexpr int OLD_DEXOPT_DEBUGGABLE     = 1 << 3;
-                    constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
-                    constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
-                    constexpr int OLD_DEXOPT_OTA            = 1 << 6;
-                    int input = atoi(param);
-                    package_parameters_.dexopt_flags =
-                            ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
-                            ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
-                            ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
-                            ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
-                            ReplaceMask(input, OLD_DEXOPT_OTA, 0);
-                    break;
-                }
-
-                case 7:
-                    package_parameters_.compiler_filter = param;
-                    break;
-
-                case 8:
-                    package_parameters_.volume_uuid = ParseNull(param);
-                    break;
-
-                case 9:
-                    package_parameters_.shared_libraries = ParseNull(param);
-                    break;
-
-                default:
-                    LOG(ERROR) << "Too many arguments, got " << param;
-                    return false;
-            }
-        }
-
-        if (param_index != 10) {
-            LOG(ERROR) << "Not enough parameters";
-            return false;
-        }
-
-        // Set se_info to null. It is only relevant for secondary dex files, which we won't
-        // receive from a v1 A side.
-        package_parameters_.se_info = nullptr;
-
-        // Set downgrade to false. It is only relevant when downgrading compiler
-        // filter, which is not the case during ota.
-        package_parameters_.downgrade = false;
-
-        // Set target_sdk_version to 0, ie the platform SDK version. This is
-        // conservative and may force some classes to verify at runtime.
-        package_parameters_.target_sdk_version = 0;
-
-        // Set the profile name to the primary apk profile.
-        package_parameters_.profile_name = "primary.prof";
-
-        return true;
+        return parameters_.ReadArguments(argc, const_cast<const char**>(argv));
     }
 
     void PrepareEnvironment() {
@@ -862,11 +307,11 @@
     // Ensure that we have the right boot image. The first time any app is
     // compiled, we'll try to generate it.
     bool PrepareBootImage(bool force) const {
-        if (package_parameters_.instruction_set == nullptr) {
+        if (parameters_.instruction_set == nullptr) {
             LOG(ERROR) << "Instruction set missing.";
             return false;
         }
-        const char* isa = package_parameters_.instruction_set;
+        const char* isa = parameters_.instruction_set;
 
         // Check whether the file exists where expected.
         std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
@@ -1090,9 +535,9 @@
         //       jar content must be exactly the same).
 
         //       (This is ugly as it's the only thing where we need to understand the contents
-        //        of package_parameters_, but it beats postponing the decision or using the call-
+        //        of parameters_, but it beats postponing the decision or using the call-
         //        backs to do weird things.)
-        const char* apk_path = package_parameters_.apk_path;
+        const char* apk_path = parameters_.apk_path;
         CHECK(apk_path != nullptr);
         if (StartsWith(apk_path, android_root_)) {
             const char* last_slash = strrchr(apk_path, '/');
@@ -1120,23 +565,24 @@
         return false;
     }
 
-    // Run dexopt with the parameters of package_parameters_.
+    // Run dexopt with the parameters of parameters_.
     // TODO(calin): embed the profile name in the parameters.
     int Dexopt() {
-        return dexopt(package_parameters_.apk_path,
-                      package_parameters_.uid,
-                      package_parameters_.pkgName,
-                      package_parameters_.instruction_set,
-                      package_parameters_.dexopt_needed,
-                      package_parameters_.oat_dir,
-                      package_parameters_.dexopt_flags,
-                      package_parameters_.compiler_filter,
-                      package_parameters_.volume_uuid,
-                      package_parameters_.shared_libraries,
-                      package_parameters_.se_info,
-                      package_parameters_.downgrade,
-                      package_parameters_.target_sdk_version,
-                      package_parameters_.profile_name);
+        return dexopt(parameters_.apk_path,
+                      parameters_.uid,
+                      parameters_.pkgName,
+                      parameters_.instruction_set,
+                      parameters_.dexopt_needed,
+                      parameters_.oat_dir,
+                      parameters_.dexopt_flags,
+                      parameters_.compiler_filter,
+                      parameters_.volume_uuid,
+                      parameters_.shared_libraries,
+                      parameters_.se_info,
+                      parameters_.downgrade,
+                      parameters_.target_sdk_version,
+                      parameters_.profile_name,
+                      parameters_.dex_metadata_path);
     }
 
     int RunPreopt() {
@@ -1167,12 +613,12 @@
 
         // If this was a profile-guided run, we may have profile version issues. Try to downgrade,
         // if possible.
-        if ((package_parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
+        if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
             return dexopt_result;
         }
 
         LOG(WARNING) << "Downgrading compiler filter in an attempt to progress compilation";
-        package_parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
+        parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
         return Dexopt();
     }
 
@@ -1297,13 +743,12 @@
     SystemProperties system_properties_;
 
     // Some select properties that are always needed.
-    std::string target_slot_;
     std::string android_root_;
     std::string android_data_;
     std::string boot_classpath_;
     std::string asec_mountpoint_;
 
-    Parameters package_parameters_;
+    OTAPreoptParameters parameters_;
 
     // Store environment values we need to set.
     std::vector<std::string> environ_;
diff --git a/cmds/installd/otapreopt_parameters.cpp b/cmds/installd/otapreopt_parameters.cpp
new file mode 100644
index 0000000..5b5f522
--- /dev/null
+++ b/cmds/installd/otapreopt_parameters.cpp
@@ -0,0 +1,347 @@
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "otapreopt_parameters.h"
+
+#include <android-base/logging.h>
+
+#include "dexopt.h"
+#include "installd_constants.h"
+#include "otapreopt_utils.h"
+
+#ifndef LOG_TAG
+#define LOG_TAG "otapreopt"
+#endif
+
+namespace android {
+namespace installd {
+
+static bool ParseBool(const char* in) {
+    if (strcmp(in, "true") == 0) {
+        return true;
+    }
+    return false;
+}
+
+static const char* ParseNull(const char* arg) {
+    return (strcmp(arg, "!") == 0) ? nullptr : arg;
+}
+
+static bool ParseUInt(const char* in, uint32_t* out) {
+    char* end;
+    long long int result = strtoll(in, &end, 0);
+    if (in == end || *end != '\0') {
+        return false;
+    }
+    if (result < std::numeric_limits<uint32_t>::min() ||
+            std::numeric_limits<uint32_t>::max() < result) {
+        return false;
+    }
+    *out = static_cast<uint32_t>(result);
+    return true;
+}
+
+bool OTAPreoptParameters::ReadArguments(int argc, const char** argv) {
+    // Expected command line:
+    //   target-slot [version] dexopt {DEXOPT_PARAMETERS}
+
+    const char* target_slot_arg = argv[1];
+    if (target_slot_arg == nullptr) {
+        LOG(ERROR) << "Missing parameters";
+        return false;
+    }
+    // Sanitize value. Only allow (a-zA-Z0-9_)+.
+    target_slot = target_slot_arg;
+    if (!ValidateTargetSlotSuffix(target_slot)) {
+        LOG(ERROR) << "Target slot suffix not legal: " << target_slot;
+        return false;
+    }
+
+    // Check for version or "dexopt" next.
+    if (argv[2] == nullptr) {
+        LOG(ERROR) << "Missing parameters";
+        return false;
+    }
+
+    if (std::string("dexopt").compare(argv[2]) == 0) {
+        // This is version 1 (N) or pre-versioning version 2.
+        constexpr int kV2ArgCount =   1   // "otapreopt"
+                                    + 1   // slot
+                                    + 1   // "dexopt"
+                                    + 1   // apk_path
+                                    + 1   // uid
+                                    + 1   // pkg
+                                    + 1   // isa
+                                    + 1   // dexopt_needed
+                                    + 1   // oat_dir
+                                    + 1   // dexopt_flags
+                                    + 1   // filter
+                                    + 1   // volume
+                                    + 1   // libs
+                                    + 1;  // seinfo
+        if (argc == kV2ArgCount) {
+            return ReadArgumentsPostV1(2, argv, false);
+        } else {
+            return ReadArgumentsV1(argv);
+        }
+    }
+
+    uint32_t version;
+    if (!ParseUInt(argv[2], &version)) {
+        LOG(ERROR) << "Could not parse version: " << argv[2];
+        return false;
+    }
+
+    return ReadArgumentsPostV1(version, argv, true);
+}
+
+static int ReplaceMask(int input, int old_mask, int new_mask) {
+    return (input & old_mask) != 0 ? new_mask : 0;
+}
+
+bool OTAPreoptParameters::ReadArgumentsV1(const char** argv) {
+    // Check for "dexopt".
+    if (argv[2] == nullptr) {
+        LOG(ERROR) << "Missing parameters";
+        return false;
+    }
+    if (std::string("dexopt").compare(argv[2]) != 0) {
+        LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[2];
+        return false;
+    }
+
+    size_t param_index = 0;
+    for (;; ++param_index) {
+        const char* param = argv[3 + param_index];
+        if (param == nullptr) {
+            break;
+        }
+
+        switch (param_index) {
+            case 0:
+                apk_path = param;
+                break;
+
+            case 1:
+                uid = atoi(param);
+                break;
+
+            case 2:
+                pkgName = param;
+                break;
+
+            case 3:
+                instruction_set = param;
+                break;
+
+            case 4: {
+                // Version 1 had:
+                //   DEXOPT_DEX2OAT_NEEDED       = 1
+                //   DEXOPT_PATCHOAT_NEEDED      = 2
+                //   DEXOPT_SELF_PATCHOAT_NEEDED = 3
+                // We will simply use DEX2OAT_FROM_SCRATCH.
+                dexopt_needed = DEX2OAT_FROM_SCRATCH;
+                break;
+            }
+
+            case 5:
+                oat_dir = param;
+                break;
+
+            case 6: {
+                // Version 1 had:
+                constexpr int OLD_DEXOPT_PUBLIC         = 1 << 1;
+                // Note: DEXOPT_SAFEMODE has been removed.
+                // constexpr int OLD_DEXOPT_SAFEMODE       = 1 << 2;
+                constexpr int OLD_DEXOPT_DEBUGGABLE     = 1 << 3;
+                constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
+                constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
+                constexpr int OLD_DEXOPT_OTA            = 1 << 6;
+                int input = atoi(param);
+                dexopt_flags =
+                        ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
+                        ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
+                        ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
+                        ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
+                        ReplaceMask(input, OLD_DEXOPT_OTA, 0);
+                break;
+            }
+
+            case 7:
+                compiler_filter = param;
+                break;
+
+            case 8:
+                volume_uuid = ParseNull(param);
+                break;
+
+            case 9:
+                shared_libraries = ParseNull(param);
+                break;
+
+            default:
+                LOG(ERROR) << "Too many arguments, got " << param;
+                return false;
+        }
+    }
+
+    if (param_index != 10) {
+        LOG(ERROR) << "Not enough parameters";
+        return false;
+    }
+
+    // Set se_info to null. It is only relevant for secondary dex files, which we won't
+    // receive from a v1 A side.
+    se_info = nullptr;
+
+    // Set downgrade to false. It is only relevant when downgrading compiler
+    // filter, which is not the case during ota.
+    downgrade = false;
+
+    // Set target_sdk_version to 0, ie the platform SDK version. This is
+    // conservative and may force some classes to verify at runtime.
+    target_sdk_version = 0;
+
+    // Set the profile name to the primary apk profile.
+    profile_name = "primary.prof";
+
+    return true;
+}
+
+bool OTAPreoptParameters::ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned) {
+    size_t num_args_expected = 0;
+    switch (version) {
+        case 2: num_args_expected = 11; break;
+        case 3: num_args_expected = 12; break;
+        case 4: num_args_expected = 13; break;
+        case 5: num_args_expected = 14; break;
+        case 6: num_args_expected = 15; break;
+        default:
+            LOG(ERROR) << "Don't know how to read arguments for version " << version;
+            return false;
+    }
+    size_t dexopt_index = versioned ? 3 : 2;
+
+    // Check for "dexopt".
+    if (argv[dexopt_index] == nullptr) {
+        LOG(ERROR) << "Missing parameters";
+        return false;
+    }
+    if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+        LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[dexopt_index];
+        return false;
+    }
+
+    // Validate the number of arguments.
+    size_t num_args_actual = 0;
+    while (argv[dexopt_index + 1 + num_args_actual] != nullptr) {
+        num_args_actual++;
+    }
+
+    if (num_args_actual != num_args_expected) {
+        LOG(ERROR) << "Invalid number of arguments. expected="
+                << num_args_expected << " actual=" << num_args_actual;
+        return false;
+    }
+
+    // The number of arguments is OK.
+    // Configure the default values for the parameters that were added after V1.
+    // The default values will be overwritten in case they are passed as arguments.
+
+    // Set downgrade to false. It is only relevant when downgrading compiler
+    // filter, which is not the case during ota.
+    downgrade = false;
+
+    // Set target_sdk_version to 0, ie the platform SDK version. This is
+    // conservative and may force some classes to verify at runtime.
+    target_sdk_version = 0;
+
+    // Set the profile name to the primary apk profile.
+    profile_name = "primary.prof";
+
+    for (size_t param_index = 0; param_index < num_args_actual; ++param_index) {
+        const char* param = argv[dexopt_index + 1 + param_index];
+        switch (param_index) {
+            case 0:
+                apk_path = param;
+                break;
+
+            case 1:
+                uid = atoi(param);
+                break;
+
+            case 2:
+                pkgName = param;
+                break;
+
+            case 3:
+                instruction_set = param;
+                break;
+
+            case 4:
+                dexopt_needed = atoi(param);
+                break;
+
+            case 5:
+                oat_dir = param;
+                break;
+
+            case 6:
+                dexopt_flags = atoi(param);
+                break;
+
+            case 7:
+                compiler_filter = param;
+                break;
+
+            case 8:
+                volume_uuid = ParseNull(param);
+                break;
+
+            case 9:
+                shared_libraries = ParseNull(param);
+                break;
+
+            case 10:
+                se_info = ParseNull(param);
+                break;
+
+            case 11:
+                downgrade = ParseBool(param);
+                break;
+
+            case 12:
+                target_sdk_version = atoi(param);
+                break;
+
+            case 13:
+                profile_name = ParseNull(param);
+                break;
+
+            case 14:
+                 dex_metadata_path = ParseNull(param);
+
+            default:
+                CHECK(false) << "Should not get here. Did you call ReadArguments "
+                        << "with the right expectation?";
+        }
+    }
+
+    return true;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/otapreopt_parameters.h b/cmds/installd/otapreopt_parameters.h
new file mode 100644
index 0000000..0f3bb8c
--- /dev/null
+++ b/cmds/installd/otapreopt_parameters.h
@@ -0,0 +1,59 @@
+/*
+ ** Copyright 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 OTAPREOPT_PARAMETERS_H_
+#define OTAPREOPT_PARAMETERS_H_
+
+#include <string>
+#include <sys/types.h>
+
+namespace android {
+namespace installd {
+
+class OTAPreoptParameters {
+  public:
+    bool ReadArguments(int argc, const char** argv);
+
+  private:
+    bool ReadArgumentsV1(const char** argv);
+    bool ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned);
+
+    const char* apk_path;
+    uid_t uid;
+    const char* pkgName;
+    const char* instruction_set;
+    int dexopt_needed;
+    const char* oat_dir;
+    int dexopt_flags;
+    const char* compiler_filter;
+    const char* volume_uuid;
+    const char* shared_libraries;
+    const char* se_info;
+    bool downgrade;
+    int target_sdk_version;
+    const char* profile_name;
+    const char* dex_metadata_path;
+
+    std::string target_slot;
+
+    friend class OTAPreoptService;
+    friend class OTAPreoptTest;
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  //  OTAPREOPT_PARAMETERS_H_
\ No newline at end of file
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 47346fb..7438d3d 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -78,3 +78,20 @@
         "liblogwrap",
     ],
 }
+
+cc_test {
+    name: "installd_otapreopt_test",
+    clang: true,
+    srcs: ["installd_otapreopt_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libutils",
+    ],
+    static_libs: [
+        "liblog",
+        "libotapreoptparameters"
+    ],
+}
+
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 052fcfc..e176871 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -263,6 +263,7 @@
         bool downgrade = false;
         int32_t target_sdk_version = 0;  // default
         std::unique_ptr<std::string> profile_name_ptr = nullptr;
+        std::unique_ptr<std::string> dm_path_ptr = nullptr;
 
         binder::Status result = service_->dexopt(path,
                                                  uid,
@@ -277,7 +278,8 @@
                                                  se_info_ptr,
                                                  downgrade,
                                                  target_sdk_version,
-                                                 profile_name_ptr);
+                                                 profile_name_ptr,
+                                                 dm_path_ptr);
         ASSERT_EQ(should_binder_call_succeed, result.isOk());
         int expected_access = should_dex_be_compiled ? 0 : -1;
         std::string odex = GetSecondaryDexArtifact(path, "odex");
@@ -331,9 +333,10 @@
                              const char* oat_dir,
                              int32_t uid,
                              int32_t dexopt_needed,
+                             const char* dm_path = nullptr,
                              bool downgrade = false) {
         return CompilePrimaryDex(
-                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, true);
+                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, true);
     }
 
     void CompilePrimaryDexFail(std::string compiler_filter,
@@ -341,9 +344,10 @@
                                const char* oat_dir,
                                int32_t uid,
                                int32_t dexopt_needed,
+                               const char* dm_path = nullptr,
                                bool downgrade = false) {
         return CompilePrimaryDex(
-                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, false);
+                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, false);
     }
 
     void CompilePrimaryDex(std::string compiler_filter,
@@ -351,6 +355,7 @@
                            const char* oat_dir,
                            int32_t uid,
                            int32_t dexopt_needed,
+                           const char* dm_path,
                            bool downgrade,
                            bool should_binder_call_succeed) {
         std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
@@ -360,6 +365,10 @@
         std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
         int32_t target_sdk_version = 0;  // default
         std::unique_ptr<std::string> profile_name_ptr(new std::string("primary.prof"));
+        std::unique_ptr<std::string> dm_path_ptr = nullptr;
+        if (dm_path != nullptr) {
+            dm_path_ptr.reset(new std::string(dm_path));
+        }
 
         bool prof_result;
         binder::Status prof_binder_result = service_->prepareAppProfile(
@@ -382,7 +391,8 @@
                                                  se_info_ptr,
                                                  downgrade,
                                                  target_sdk_version,
-                                                 profile_name_ptr);
+                                                 profile_name_ptr,
+                                                 dm_path_ptr);
         ASSERT_EQ(should_binder_call_succeed, result.isOk());
 
         if (!should_binder_call_succeed) {
@@ -395,15 +405,14 @@
         std::string vdex = GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex");
         std::string art = GetPrimaryDexArtifact(oat_dir, apk_path_, "art");
 
-        mode_t mode = S_IFREG | (compiler_filter == "speed-profile" ? 0640 : 0644);
+        bool is_public = (dex_flags & DEXOPT_PUBLIC) != 0;
+        mode_t mode = S_IFREG | (is_public ? 0644 : 0640);
         CheckFileAccess(odex, kSystemUid, uid, mode);
         CheckFileAccess(vdex, kSystemUid, uid, mode);
-        CheckFileAccess(odex, kSystemUid, uid, mode);
 
-        // empty profiles do not generate an image.
-        // todo: add tests with non-empty profiles.
-        struct stat st;
-        ASSERT_EQ(-1, stat(art.c_str(), &st));
+        if (compiler_filter == "speed-profile") {
+            CheckFileAccess(art, kSystemUid, uid, mode);
+        }
     }
 
     std::string GetPrimaryDexArtifact(const char* oat_dir,
@@ -480,10 +489,19 @@
                         DEX2OAT_FROM_SCRATCH);
 }
 
+TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) {
+    LOG(INFO) << "DexoptPrimaryFailedInvalidFilter";
+    CompilePrimaryDexFail("awesome-filter",
+                          DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC,
+                          app_oat_dir_.c_str(),
+                          kTestAppGid,
+                          DEX2OAT_FROM_SCRATCH);
+}
+
 TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {
     LOG(INFO) << "DexoptPrimaryProfileNonPublic";
     CompilePrimaryDexOk("speed-profile",
-                        DEXOPT_BOOTCOMPLETE,
+                        DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED,
                         app_oat_dir_.c_str(),
                         kTestAppGid,
                         DEX2OAT_FROM_SCRATCH);
@@ -491,8 +509,8 @@
 
 TEST_F(DexoptTest, DexoptPrimaryProfilePublic) {
     LOG(INFO) << "DexoptPrimaryProfilePublic";
-    CompilePrimaryDexOk("verify",
-                        DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+    CompilePrimaryDexOk("speed-profile",
+                        DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_PUBLIC,
                         app_oat_dir_.c_str(),
                         kTestAppGid,
                         DEX2OAT_FROM_SCRATCH);
@@ -501,21 +519,12 @@
 TEST_F(DexoptTest, DexoptPrimaryBackgroundOk) {
     LOG(INFO) << "DexoptPrimaryBackgroundOk";
     CompilePrimaryDexOk("speed-profile",
-                        DEXOPT_IDLE_BACKGROUND_JOB,
+                        DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED,
                         app_oat_dir_.c_str(),
                         kTestAppGid,
                         DEX2OAT_FROM_SCRATCH);
 }
 
-TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) {
-    LOG(INFO) << "DexoptPrimaryFailedInvalidFilter";
-    CompilePrimaryDexFail("awesome-filter",
-                          DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC,
-                          app_oat_dir_.c_str(),
-                          kTestAppGid,
-                          DEX2OAT_FROM_SCRATCH);
-}
-
 class PrimaryDexReCompilationTest : public DexoptTest {
   public:
     virtual void SetUp() {
diff --git a/cmds/installd/tests/installd_otapreopt_test.cpp b/cmds/installd/tests/installd_otapreopt_test.cpp
new file mode 100644
index 0000000..1e8ae42
--- /dev/null
+++ b/cmds/installd/tests/installd_otapreopt_test.cpp
@@ -0,0 +1,210 @@
+/**
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+#include "otapreopt_parameters.h"
+
+namespace android {
+namespace installd {
+
+static bool ParseBool(const char* in) {
+    if (strcmp(in, "true") == 0) {
+        return true;
+    }
+    return false;
+}
+
+static const char* ParseNull(const char* arg) {
+    return (strcmp(arg, "!") == 0) ? nullptr : arg;
+}
+
+class OTAPreoptTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+    }
+
+    void verifyPackageParameters(const OTAPreoptParameters& params,
+                                 uint32_t version,
+                                 bool versioned,
+                                 const char** args) {
+        //  otapreopt target-slot [version] dexopt {DEXOPT_PARAMETERS}
+        int i = 0;
+        if (version > 2 || (version == 2 && versioned)) {
+            i += 4;
+        } else {
+            i += 3;
+        }
+        ASSERT_STREQ(params.target_slot.c_str(), args[1]);
+        ASSERT_STREQ(params.apk_path, args[i++]);
+        ASSERT_EQ(params.uid, static_cast<uid_t>(atoi(args[i++])));
+        ASSERT_STREQ(params.pkgName, args[i++]);
+        ASSERT_STREQ(params.instruction_set, args[i++]);
+        ASSERT_EQ(params.dexopt_needed, atoi(args[i++]));
+        ASSERT_STREQ(params.oat_dir, args[i++]);
+        ASSERT_EQ(params.dexopt_flags, atoi(args[i++]));
+        ASSERT_STREQ(params.compiler_filter, args[i++]);
+        ASSERT_STREQ(params.volume_uuid, ParseNull(args[i++]));
+        ASSERT_STREQ(params.shared_libraries, ParseNull(args[i++]));
+        if (version > 1) {
+            ASSERT_STREQ(params.se_info, ParseNull(args[i++]));
+        } else {
+            ASSERT_STREQ(params.se_info, nullptr);
+        }
+        if (version > 2) {
+            ASSERT_EQ(params.downgrade, ParseBool(args[i++]));
+        } else {
+            ASSERT_FALSE(params.downgrade);
+        }
+        if (version > 3) {
+            ASSERT_EQ(params.target_sdk_version, atoi(args[i++]));
+        } else {
+             ASSERT_EQ(params.target_sdk_version, 0);
+        }
+        if (version > 4) {
+            ASSERT_STREQ(params.profile_name, ParseNull(args[i++]));
+        } else {
+            ASSERT_STREQ(params.profile_name, "primary.prof");
+        }
+        if (version > 5) {
+            ASSERT_STREQ(params.dex_metadata_path, ParseNull(args[i++]));
+        } else {
+            ASSERT_STREQ(params.dex_metadata_path, nullptr);
+        }
+    }
+
+    const char* getVersionCStr(uint32_t version) {
+        switch (version) {
+            case 1: return "1";
+            case 2: return "2";
+            case 3: return "3";
+            case 4: return "4";
+            case 5: return "5";
+            case 6: return "6";
+        }
+        return nullptr;
+    }
+
+    std::vector<const char*> getArgs(uint32_t version, bool versioned) {
+        std::vector<const char*> args;
+        args.push_back("otapreopt");  // "otapreopt"
+        args.push_back("a");  // slot
+        if (versioned) {
+            args.push_back(getVersionCStr(version));
+        }
+        args.push_back("dexopt");  // "dexopt"
+        args.push_back("foo.apk");  // apk_path
+        args.push_back("123");  // uid
+        args.push_back("pkgname");  // pkg
+        args.push_back("arm");  // isa
+        args.push_back("1");  // dexopt_needed (DEX2OAT_FROM_SCRATCH)
+        args.push_back("oat_dir");  // oat_dir
+        args.push_back("0");  // dexopt_flags
+        args.push_back("speed");  // filter
+        args.push_back("!");  // volume
+        args.push_back("shared.lib");  // libs
+
+        if (version > 1) {
+            args.push_back("!");  // seinfo
+        }
+        if (version > 2) {
+            args.push_back("true");  // downgrade
+        }
+        if (version > 3) {
+            args.push_back("28");  // sdk_version
+        }
+        if (version > 4) {
+            args.push_back("split_a.prof");  // profile_name
+        }
+        if (version > 5) {
+            args.push_back("dex_metadata.dm");  // dex_metadata_path
+        }
+        args.push_back(nullptr);  // we have to end with null.
+        return args;
+    }
+
+    void VerifyReadArguments(uint32_t version, bool versioned) {
+        OTAPreoptParameters params;
+        std::vector<const char*> args = getArgs(version, versioned);
+        ASSERT_TRUE(params.ReadArguments(args.size() - 1, args.data()));
+        verifyPackageParameters(params, version, versioned, args.data());
+    }
+};
+
+TEST_F(OTAPreoptTest, ReadArgumentsV1) {
+    VerifyReadArguments(1, false);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV2Unversioned) {
+    VerifyReadArguments(2, false);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV2) {
+    VerifyReadArguments(2, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV3) {
+    VerifyReadArguments(3, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV4) {
+    VerifyReadArguments(4, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV5) {
+    VerifyReadArguments(5, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV6) {
+    VerifyReadArguments(6, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailToManyArgs) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(5, true);
+    args[2] = "3";  // pretend it's version 3. It should fail since there are too many args.
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInsufficientArgs) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(4, true);
+    args[2] = "5";  // pretend it's version 5. It should fail since there are insufficient args.
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInvalidDexopt) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(4, true);
+    args[3] = "dexopt-invalid";
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInvalidSlot) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(3, true);
+    args[1] = "invalid-slot???";
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 0ec4551..efa639d 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -1580,20 +1580,20 @@
 # evaluate all C-preprocessor directives found in the sources and include
 # files.
 
-ENABLE_PREPROCESSING   = NO
+ENABLE_PREPROCESSING   = YES
 
 # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
 # names in the source code. If set to NO (the default) only conditional
 # compilation will be performed. Macro expansion can be done in a controlled
 # way by setting EXPAND_ONLY_PREDEF to YES.
 
-MACRO_EXPANSION        = NO
+MACRO_EXPANSION        = YES
 
 # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
 # then the macro expansion is limited to the macros specified with the
 # PREDEFINED and EXPAND_AS_DEFINED tags.
 
-EXPAND_ONLY_PREDEF     = NO
+EXPAND_ONLY_PREDEF     = YES
 
 # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
 # pointed to by INCLUDE_PATH will be searched when a #include is found.
@@ -1621,7 +1621,7 @@
 # undefined via #undef or recursively expanded use the := operator
 # instead of the = operator.
 
-PREDEFINED             =
+PREDEFINED             = __attribute__(x)=
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
 # this tag can be used to specify a list of macro names that should be expanded.
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
new file mode 100644
index 0000000..56b3342
--- /dev/null
+++ b/include/android/surface_texture.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup SurfaceTexture
+ * @{
+ */
+
+/**
+ * @file surface_texture.h
+ */
+
+#ifndef ANDROID_NATIVE_SURFACE_TEXTURE_H
+#define ANDROID_NATIVE_SURFACE_TEXTURE_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+#include <stdint.h>
+
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+struct ASurfaceTexture;
+
+/**
+ * {@link ASurfaceTexture} is an opaque type to manage SurfaceTexture from native code
+ *
+ * {@link ASurfaceTexture} can be obtained from an android.graphics.SurfaceTexture object using
+ * ASurfaceTexture_fromSurfaceTexture().
+ */
+typedef struct ASurfaceTexture ASurfaceTexture;
+
+/**
+ * Release the reference to the native ASurfaceTexture acquired with
+ * ASurfaceTexture_fromSurfaceTexture().
+ * Failing to do so will result in leaked memory and graphic resources.
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ */
+void ASurfaceTexture_release(ASurfaceTexture* st);
+
+/**
+ * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture.
+ * This is equivalent to Java's: Surface sur = new Surface(surfaceTexture);
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * @return A reference to an ANativeWindow. This reference MUST BE released when no longer needed
+ * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is
+ * returned if \st is null or if it's not an instance of android.graphics.SurfaceTexture
+ */
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st);
+
+/**
+ * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread.  A
+ * new OpenGL ES texture object is created and populated with the SurfaceTexture image frame
+ * that was current at the time of the last call to {@link #detachFromGLContext}.  This new
+ * texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target.
+ *
+ * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
+ * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
+ * context at a time.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \param texName The name of the OpenGL ES texture that will be created.  This texture name
+ * must be unusued in the OpenGL ES context that is current on the calling thread.
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName);
+
+/**
+ * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object.
+ * This call must be made with the OpenGL ES context current on the calling thread.  The OpenGL
+ * ES texture object will be deleted as a result of this call.  After calling this method all
+ * calls to {@link #updateTexImage} will fail until a successful call to {@link #attachToGLContext}
+ * is made.
+ *
+ * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
+ * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
+ * context at a time.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st);
+
+/**
+ * Update the texture image to the most recent frame from the image stream.  This may only be
+ * called while the OpenGL ES context that owns the texture is current on the calling thread.
+ * It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st);
+
+/**
+ * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
+ * the most recent call to updateTexImage.
+ *
+ * This transform matrix maps 2D homogeneous texture coordinates of the form (s, t, 0, 1) with s
+ * and t in the inclusive range [0, 1] to the texture coordinate that should be used to sample
+ * that location from the texture.  Sampling the texture outside of the range of this transform
+ * is undefined.
+ *
+ * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via
+ * the glLoadMatrixf or glUniformMatrix4fv functions.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \param mtx the array into which the 4x4 matrix will be stored.  The array must have exactly
+ *     16 elements.
+ */
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]);
+
+/**
+ * Retrieve the timestamp associated with the texture image set by the most recent call to
+ * updateTexImage.
+ *
+ * This timestamp is in nanoseconds, and is normally monotonically increasing. The timestamp
+ * should be unaffected by time-of-day adjustments, and for a camera should be strictly
+ * monotonic but for a MediaPlayer may be reset when the position is set.  The
+ * specific meaning and zero point of the timestamp depends on the source providing images to
+ * the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot
+ * generally be compared across SurfaceTexture instances, or across multiple program
+ * invocations. It is mostly useful for determining time offsets between subsequent frames.
+ *
+ * For EGL/Vulkan producers, this timestamp is the desired present time set with the
+ * EGL_ANDROID_presentation_time or VK_GOOGLE_display_timing extensions
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ */
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st);
+
+__END_DECLS
+
+#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_H */
diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h
new file mode 100644
index 0000000..b0e1edd
--- /dev/null
+++ b/include/android/surface_texture_jni.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup SurfaceTexture
+ * @{
+ */
+
+/**
+ * @file surface_texture_jni.h
+ */
+
+#ifndef ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H
+#define ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H
+
+#include <android/surface_texture.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+/**
+ * Get a reference to the native ASurfaceTexture from the corresponding java object.
+ *
+ * The caller must keep a reference to the Java SurfaceTexture during the lifetime of the returned
+ * ASurfaceTexture. Failing to do so could result in the ASurfaceTexture to stop functioning
+ * properly once the Java object gets finalized.
+ * However, this will not result in program termination.
+ *
+ * \param env JNI environment
+ * \param surfacetexture Instance of Java SurfaceTexture object
+ * \return native ASurfaceTexture reference or nullptr if the java object is not a SurfaceTexture.
+ *         The returned reference MUST BE released when it's no longer needed using
+ *         ASurfaceTexture_release().
+ */
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture);
+
+__END_DECLS
+
+#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H */
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index ad04d03..065d44d 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -120,6 +120,8 @@
     shared_libs: [
         "libsync",
         "libbinder",
+        "libbufferhubqueue",  // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
+        "libpdx_default_transport",
         "libcutils",
         "libEGL",
         "libGLESv2",
@@ -135,13 +137,6 @@
         "android.hardware.configstore-utils",
     ],
 
-    // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
-    static_libs: [
-        "libbufferhub",
-        "libbufferhubqueue",
-        "libpdx_default_transport",
-    ],
-
     header_libs: [
         "libdvr_headers",
         "libnativebase_headers",
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 7ea37a7..39814cc 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -22,10 +22,6 @@
     "include",
 ]
 
-staticLibraries = [
-    "libpdx_default_transport",
-]
-
 sharedLibraries = [
     "libbase",
     "libbinder",
@@ -34,7 +30,8 @@
     "liblog",
     "libui",
     "libutils",
-    "libnativewindow"
+    "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
@@ -52,7 +49,6 @@
         "-Werror",
     ],
     export_include_dirs: localIncludeFiles,
-    static_libs: staticLibraries,
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
     name: "libbufferhub",
@@ -68,7 +64,7 @@
 cc_test {
     tags: ["optional"],
     srcs: ["buffer_hub-test.cpp"],
-    static_libs: ["libbufferhub"] + staticLibraries,
+    static_libs: ["libbufferhub"],
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
     name: "buffer_hub-test",
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 84e7427..eeec9ec 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -23,7 +23,6 @@
 
 staticLibraries = [
     "libbufferhub",
-    "libpdx_default_transport",
 ]
 
 sharedLibraries = [
@@ -34,6 +33,7 @@
     "liblog",
     "libui",
     "libutils",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
@@ -41,7 +41,7 @@
     "libnativebase_headers",
 ]
 
-cc_library {
+cc_library_shared {
     name: "libbufferhubqueue",
     cflags: [
         "-DLOG_TAG=\"libbufferhubqueue\"",
@@ -65,4 +65,4 @@
     },
 }
 
-subdirs = ["tests"]
+subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
new file mode 100644
index 0000000..8ae7a0b
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
@@ -0,0 +1,27 @@
+
+cc_benchmark {
+    srcs: ["buffer_transport_benchmark.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libdvr",
+        "libgui",
+        "liblog",
+        "libhardware",
+        "libui",
+        "libutils",
+        "libnativewindow",
+        "libbufferhubqueue",
+        "libpdx_default_transport",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"buffer_transport_benchmark\"",
+        "-DTRACE=0",
+        "-O2",
+        "-Wall",
+        "-Werror",
+    ],
+    name: "buffer_transport_benchmark",
+    tags: ["optional"],
+}
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
similarity index 76%
rename from libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
rename to libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
index 73932c2..4ca8671 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
+++ b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
@@ -1,14 +1,13 @@
-#include <android/native_window.h>
 #include <android-base/logging.h>
+#include <android/native_window.h>
 #include <benchmark/benchmark.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <dvr/dvr_api.h>
-#include <dvr/performance_client_api.h>
-#include <gui/BufferHubProducer.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
+#include <private/dvr/epoll_file_descriptor.h>
 #include <utils/Trace.h>
 
 #include <chrono>
@@ -17,7 +16,9 @@
 #include <thread>
 #include <vector>
 
+#include <dlfcn.h>
 #include <poll.h>
+#include <sys/epoll.h>
 #include <sys/wait.h>
 
 // Use ALWAYS at the tag level. Control is performed manually during command
@@ -28,7 +29,6 @@
 #define ATRACE_TAG ATRACE_TAG_ALWAYS
 
 using namespace android;
-using namespace android::dvr;
 using ::benchmark::State;
 
 static const String16 kBinderService = String16("bufferTransport");
@@ -37,9 +37,11 @@
 static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
 static const uint64_t kBufferUsage =
     GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+static const uint32_t kBufferLayer = 1;
 static const int kMaxAcquiredImages = 1;
 static const int kQueueDepth = 2;  // We are double buffering for this test.
 static const size_t kMaxQueueCounts = 128;
+static const int kInvalidFence = -1;
 
 enum BufferTransportServiceCode {
   CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
@@ -62,7 +64,7 @@
       case CREATE_BUFFER_QUEUE: {
         auto new_queue = std::make_shared<BufferQueueHolder>(this);
         reply->writeStrongBinder(
-            IGraphicBufferProducer::asBinder(new_queue->producer_));
+            IGraphicBufferProducer::asBinder(new_queue->producer));
         buffer_queues_.push_back(new_queue);
         return NO_ERROR;
       }
@@ -109,18 +111,20 @@
 
   struct BufferQueueHolder {
     explicit BufferQueueHolder(BufferTransportService* service) {
-      BufferQueue::createBufferQueue(&producer_, &consumer_);
+      BufferQueue::createBufferQueue(&producer, &consumer);
 
       sp<BufferItemConsumer> buffer_item_consumer =
-          new BufferItemConsumer(consumer_, kBufferUsage, kMaxAcquiredImages,
+          new BufferItemConsumer(consumer, kBufferUsage, kMaxAcquiredImages,
                                  /*controlledByApp=*/true);
       buffer_item_consumer->setName(String8("BinderBufferTransport"));
       frame_listener_ = new FrameListener(service, buffer_item_consumer);
       buffer_item_consumer->setFrameAvailableListener(frame_listener_);
     }
 
-    sp<IGraphicBufferProducer> producer_;
-    sp<IGraphicBufferConsumer> consumer_;
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+
+   private:
     sp<FrameListener> frame_listener_;
   };
 
@@ -199,6 +203,28 @@
   sp<IBinder> service_;
 };
 
+class DvrApi {
+ public:
+  DvrApi() {
+    handle_ = dlopen("libdvr.so", RTLD_NOW | RTLD_LOCAL);
+    CHECK(handle_);
+
+    auto dvr_get_api =
+        reinterpret_cast<decltype(&dvrGetApi)>(dlsym(handle_, "dvrGetApi"));
+    int ret = dvr_get_api(&api_, sizeof(api_), /*version=*/1);
+
+    CHECK(ret == 0);
+  }
+
+  ~DvrApi() { dlclose(handle_); }
+
+  const DvrApi_v1& Api() { return api_; }
+
+ private:
+  void* handle_ = nullptr;
+  DvrApi_v1 api_;
+};
+
 // BufferHub/PDX-based buffer transport.
 //
 // On Start() a new thread will be swapned to run an epoll polling thread which
@@ -227,16 +253,9 @@
 
     // Create the reader thread.
     reader_thread_ = std::thread([this]() {
-      int ret = dvrSetSchedulerClass(0, "graphics");
+      int ret = dvr_.Api().PerformanceSetSchedulerPolicy(0, "graphics");
       if (ret < 0) {
-        LOG(ERROR) << "Failed to set thread priority";
-        return;
-      }
-
-
-      ret = dvrSetCpuPartition(0, "/system/performance");
-      if (ret < 0) {
-        LOG(ERROR) << "Failed to set thread cpu partition";
+        LOG(ERROR) << "Failed to set scheduler policy, ret=" << ret;
         return;
       }
 
@@ -259,8 +278,9 @@
 
         const int num_events = ret;
         for (int i = 0; i < num_events; i++) {
-          uint32_t surface_index = events[i].data.u32;
-          buffer_queues_[surface_index]->consumer_queue_->HandleQueueEvents();
+          uint32_t index = events[i].data.u32;
+          dvr_.Api().ReadBufferQueueHandleEvents(
+              buffer_queues_[index]->GetReadQueue());
         }
       }
 
@@ -272,89 +292,123 @@
 
   sp<Surface> CreateSurface() override {
     auto new_queue = std::make_shared<BufferQueueHolder>();
-    if (new_queue->producer_ == nullptr) {
-      LOG(ERROR) << "Failed to create buffer producer.";
+    if (!new_queue->IsReady()) {
+      LOG(ERROR) << "Failed to create BufferHub-based BufferQueue.";
       return nullptr;
     }
 
-    sp<Surface> surface =
-        new Surface(new_queue->producer_, /*controlledByApp=*/true);
-
     // Set buffer dimension.
-    ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
-    ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight,
-                                     kBufferFormat);
+    ANativeWindow_setBuffersGeometry(new_queue->GetSurface(), kBufferWidth,
+                                     kBufferHeight, kBufferFormat);
 
     // Use the next position as buffer_queue index.
     uint32_t index = buffer_queues_.size();
     epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}};
-    const int ret = epoll_fd_.Control(
-        EPOLL_CTL_ADD, new_queue->consumer_queue_->queue_fd(), &event);
+    int queue_fd =
+        dvr_.Api().ReadBufferQueueGetEventFd(new_queue->GetReadQueue());
+    const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, queue_fd, &event);
     if (ret < 0) {
       LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret)
-                 << ", consumer queue fd: "
-                 << new_queue->consumer_queue_->queue_fd();
+                 << ", consumer queue fd: " << queue_fd;
       return nullptr;
     }
 
-    new_queue->queue_index_ = index;
     buffer_queues_.push_back(new_queue);
-    return surface;
+    ANativeWindow_acquire(new_queue->GetSurface());
+    return static_cast<Surface*>(new_queue->GetSurface());
   }
 
  private:
   struct BufferQueueHolder {
     BufferQueueHolder() {
-      ProducerQueueConfigBuilder config_builder;
-      producer_queue_ =
-          ProducerQueue::Create(config_builder.SetDefaultWidth(kBufferWidth)
-                                    .SetDefaultHeight(kBufferHeight)
-                                    .SetDefaultFormat(kBufferFormat)
-                                    .SetMetadata<DvrNativeBufferMetadata>()
-                                    .Build(),
-                                UsagePolicy{});
-      consumer_queue_ = producer_queue_->CreateConsumerQueue();
-      consumer_queue_->SetBufferAvailableCallback([this]() {
-        size_t index = 0;
-        pdx::LocalHandle fence;
-        DvrNativeBufferMetadata meta;
-        pdx::Status<std::shared_ptr<BufferConsumer>> status;
+      int ret = 0;
+      ret = dvr_.Api().WriteBufferQueueCreate(
+          kBufferWidth, kBufferHeight, kBufferFormat, kBufferLayer,
+          kBufferUsage, 0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create write buffer queue, ret=" << ret;
+        return;
+      }
 
-        {
-          ATRACE_NAME("AcquireBuffer");
-          status = consumer_queue_->Dequeue(0, &index, &meta, &fence);
-        }
-        if (!status.ok()) {
-          LOG(ERROR) << "Failed to dequeue consumer buffer, error: "
-                     << status.GetErrorMessage().c_str();
-          return;
-        }
+      ret = dvr_.Api().WriteBufferQueueCreateReadQueue(write_queue_,
+                                                       &read_queue_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create read buffer queue, ret=" << ret;
+        return;
+      }
 
-        auto buffer = status.take();
+      ret = dvr_.Api().ReadBufferQueueSetBufferAvailableCallback(
+          read_queue_, BufferAvailableCallback, this);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create buffer available callback, ret=" << ret;
+        return;
+      }
 
-        if (buffer) {
-          ATRACE_NAME("ReleaseBuffer");
-          buffer->ReleaseAsync();
-        }
-      });
-
-      producer_ = BufferHubProducer::Create(producer_queue_);
+      ret =
+          dvr_.Api().WriteBufferQueueGetANativeWindow(write_queue_, &surface_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create surface, ret=" << ret;
+        return;
+      }
     }
 
-    int count_ = 0;
-    int queue_index_;
-    std::shared_ptr<ProducerQueue> producer_queue_;
-    std::shared_ptr<ConsumerQueue> consumer_queue_;
-    sp<IGraphicBufferProducer> producer_;
+    static void BufferAvailableCallback(void* context) {
+      BufferQueueHolder* thiz = static_cast<BufferQueueHolder*>(context);
+      thiz->HandleBufferAvailable();
+    }
+
+    DvrReadBufferQueue* GetReadQueue() { return read_queue_; }
+
+    ANativeWindow* GetSurface() { return surface_; }
+
+    bool IsReady() {
+      return write_queue_ != nullptr && read_queue_ != nullptr &&
+             surface_ != nullptr;
+    }
+
+    void HandleBufferAvailable() {
+      int ret = 0;
+      DvrNativeBufferMetadata meta;
+      DvrReadBuffer* buffer = nullptr;
+      DvrNativeBufferMetadata metadata;
+      int acquire_fence = kInvalidFence;
+
+      {
+        ATRACE_NAME("AcquireBuffer");
+        ret = dvr_.Api().ReadBufferQueueAcquireBuffer(
+            read_queue_, 0, &buffer, &metadata, &acquire_fence);
+      }
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to acquire consumer buffer, error: " << ret;
+        return;
+      }
+
+      if (buffer != nullptr) {
+        ATRACE_NAME("ReleaseBuffer");
+        ret = dvr_.Api().ReadBufferQueueReleaseBuffer(read_queue_, buffer,
+                                                      &meta, kInvalidFence);
+      }
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to release consumer buffer, error: " << ret;
+      }
+    }
+
+   private:
+    DvrWriteBufferQueue* write_queue_ = nullptr;
+    DvrReadBufferQueue* read_queue_ = nullptr;
+    ANativeWindow* surface_ = nullptr;
   };
 
+  static DvrApi dvr_;
   std::atomic<bool> stopped_;
   std::thread reader_thread_;
 
-  EpollFileDescriptor epoll_fd_;
+  dvr::EpollFileDescriptor epoll_fd_;
   std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
 };
 
+DvrApi BufferHubTransport::dvr_ = {};
+
 enum TransportType {
   kBinderBufferTransport,
   kBufferHubTransport,
@@ -508,8 +562,7 @@
   for (int i = 1; i < argc; i++) {
     if (std::string(argv[i]) == "--help") {
       std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
-      std::cout << "\t--trace: Enable systrace logging."
-                << std::endl;
+      std::cout << "\t--trace: Enable systrace logging." << std::endl;
       return 0;
     }
     if (std::string(argv[i]) == "--trace") {
@@ -524,7 +577,7 @@
 
   pid_t pid = fork();
   if (pid == 0) {
-    // parent, i.e. the client side.
+    // Child, i.e. the client side.
     ProcessState::self()->startThreadPool();
 
     ::benchmark::Initialize(&argc, argv);
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index 5eba913..ca1e7bd 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -6,6 +6,7 @@
 shared_libraries = [
     "libbase",
     "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libgui",
     "liblog",
@@ -13,14 +14,12 @@
     "libui",
     "libutils",
     "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 static_libraries = [
-    "libbufferhubqueue",
-    "libbufferhub",
     "libchrome",
     "libdvrcommon",
-    "libpdx_default_transport",
     "libperformance",
 ]
 
@@ -58,19 +57,3 @@
     name: "buffer_hub_queue_producer-test",
     tags: ["optional"],
 }
-
-cc_benchmark {
-    srcs: ["buffer_transport_benchmark.cpp"],
-    static_libs: static_libraries,
-    shared_libs: shared_libraries,
-    header_libs: header_libraries,
-    cflags: [
-        "-DLOG_TAG=\"buffer_transport_benchmark\"",
-        "-DTRACE=0",
-        "-O2",
-        "-Wall",
-        "-Werror",
-    ],
-    name: "buffer_transport_benchmark",
-    tags: ["optional"],
-}
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index 69dbc84..192fb5d 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -27,6 +27,7 @@
 sharedLibraries = [
     "libbase",
     "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "liblog",
     "libutils",
@@ -35,14 +36,12 @@
     "libhardware",
     "libsync",
     "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 staticLibraries = [
     "libdvrcommon",
-    "libbufferhubqueue",
-    "libbufferhub",
     "libbroadcastring",
-    "libpdx_default_transport",
 ]
 
 headerLibraries = [
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 4f0e561..d0e34ee 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -44,8 +44,6 @@
 
 static_libs = [
     "libbroadcastring",
-    "libbufferhub",
-    "libbufferhubqueue",
     "libvrsensor",
     "libdisplay",
     "libvirtualtouchpadclient",
@@ -53,13 +51,13 @@
     "libvr_hwc-binder",
     "libgrallocusage",
     "libperformance",
-    "libpdx_default_transport",
 ]
 
 shared_libs = [
     "android.hardware.graphics.bufferqueue@1.0",
     "android.hidl.token@1.0-utils",
     "libbase",
+    "libbufferhubqueue",
     "libbinder",
     "liblog",
     "libcutils",
@@ -67,6 +65,7 @@
     "libnativewindow",
     "libgui",
     "libui",
+    "libpdx_default_transport",
 ]
 
 cc_library_shared {
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 887766a..e8aa6b7 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -15,6 +15,7 @@
 shared_libraries = [
     "libbase",
     "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libgui",
     "liblog",
@@ -22,16 +23,14 @@
     "libui",
     "libutils",
     "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 static_libraries = [
     "libdvr_static",
-    "libbufferhubqueue",
-    "libbufferhub",
     "libchrome",
     "libdvrcommon",
     "libdisplay",
-    "libpdx_default_transport",
     "libbroadcastring",
 ]
 
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index c7d808b..32b793a 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -26,9 +26,10 @@
     "libui",
     "libgui",
     "libhardware",
+    "libpdx_default_transport",
 ]
 
-staticLibraries = ["libpdx_default_transport", "libbroadcastring"]
+staticLibraries = ["libbroadcastring"]
 
 headerLibraries = [
     "libeigen",
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 779e3a1..475eb50 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -30,13 +30,25 @@
     whole_static_libs: ["libpdx_uds"],
 }
 
-cc_library_static {
+cc_library_shared {
     name: "libpdx_default_transport",
     defaults: [
         "pdx_default_transport_compiler_defaults",
         "pdx_default_transport_lib_defaults",
         "pdx_use_transport_uds",
     ],
+    vendor_available: false,
+    vndk: {
+        enabled: true,
+    },
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libcrypto",
+    ],
 }
 
 cc_binary {
@@ -49,8 +61,6 @@
         "libbinder",
         "libcutils",
         "liblog",
-    ],
-    static_libs: [
         "libpdx_default_transport",
     ],
 }
@@ -69,8 +79,6 @@
         "libcutils",
         "liblog",
         "libutils",
-    ],
-    static_libs: [
         "libpdx_default_transport",
     ],
 }
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 7c32dbb..35d3dea 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -19,14 +19,13 @@
 
 includeFiles = [ "include" ]
 
-staticLibraries = ["libpdx_default_transport"]
-
 sharedLibraries = [
     "libbase",
     "libbinder",
     "libcutils",
     "liblog",
     "libutils",
+    "libpdx_default_transport",
 ]
 
 cc_library {
@@ -38,7 +37,6 @@
         "-Werror",
     ],
     export_include_dirs: includeFiles,
-    static_libs: staticLibraries,
     shared_libs: sharedLibraries,
     name: "libperformance",
 }
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 9b6f0c5..23a9853 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -26,14 +26,11 @@
 includeFiles = [ "include" ]
 
 staticLibraries = [
-    "libbufferhub",
-    "libbufferhubqueue",
     "libdisplay",
     "libdvrcommon",
     "libperformance",
     "libvrsensor",
     "libbroadcastring",
-    "libpdx_default_transport",
     "libvr_manager",
     "libbroadcastring",
 ]
@@ -44,6 +41,7 @@
     "android.hardware.graphics.composer@2.1",
     "libbinder",
     "libbase",
+    "libbufferhubqueue",
     "libcutils",
     "liblog",
     "libhardware",
@@ -59,6 +57,7 @@
     "libhidlbase",
     "libhidltransport",
     "libfmq",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index fe54b4b..8542790 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -23,21 +23,20 @@
 
 staticLibraries = [
     "libdisplay",
-    "libbufferhub",
-    "libbufferhubqueue",
     "libdvrcommon",
     "libbroadcastring",
-    "libpdx_default_transport",
 ]
 
 sharedLibraries = [
     "libbase",
     "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libhardware",
     "liblog",
     "libutils",
     "libui",
+    "libpdx_default_transport",
 ]
 
 cc_library {
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 26ae13d..b00602c 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -479,8 +479,8 @@
 // Return true if we stripped any EGL_GL_COLORSPACE_KHR or HDR metadata attributes.
 // Protect devices from attributes they don't recognize that are  managed by Android
 static EGLBoolean stripAttributes(egl_display_ptr dp, const EGLint* attrib_list,
-                                           EGLint format,
-                                           std::vector<EGLint>& stripped_attrib_list) {
+                                  EGLint format,
+                                  std::vector<EGLint>& stripped_attrib_list) {
     std::vector<EGLint> allowedColorSpaces;
     switch (format) {
         case HAL_PIXEL_FORMAT_RGBA_8888:
@@ -712,7 +712,8 @@
         cta8613 |= s->setCta8613Attribute(attr[0], attr[1]);
     }
     if (smpte2086) {
-        int err = native_window_set_buffers_smpte2086_metadata(window, s->getSmpte2086Metadata());
+        android_smpte2086_metadata metadata = s->getSmpte2086Metadata();
+        int err = native_window_set_buffers_smpte2086_metadata(window, &metadata);
         if (err != 0) {
             ALOGE("error setting native window smpte2086 metadata: %s (%d)",
                   strerror(-err), err);
@@ -721,7 +722,8 @@
         }
     }
     if (cta8613) {
-        int err = native_window_set_buffers_cta861_3_metadata(window, s->getCta8613Metadata());
+        android_cta861_3_metadata metadata = s->getCta8613Metadata();
+        int err = native_window_set_buffers_cta861_3_metadata(window, &metadata);
         if (err != 0) {
             ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
                   strerror(-err), err);
@@ -1578,7 +1580,11 @@
         return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
 
-    if (s->cnx->egl.eglSurfaceAttrib) {
+    if (s->setSmpte2086Attribute(attribute, value)) {
+        return EGL_TRUE;
+    } else if (s->setCta8613Attribute(attribute, value)) {
+        return EGL_TRUE;
+    } else if (s->cnx->egl.eglSurfaceAttrib) {
         return s->cnx->egl.eglSurfaceAttrib(
                 dp->disp.dpy, s->surface, attribute, value);
     }
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 13b94b6..b68fd61 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -64,8 +64,8 @@
         cnx(cnx),
         connected(true),
         colorSpace(colorSpace),
-        smpte2086_metadata({}),
-        cta861_3_metadata({}) {
+        egl_smpte2086_metadata({}),
+        egl_cta861_3_metadata({}) {
     if (win) {
         win->incStrong(this);
     }
@@ -90,36 +90,35 @@
 
 EGLBoolean egl_surface_t::setSmpte2086Attribute(EGLint attribute, EGLint value) {
     switch (attribute) {
-            break;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
-            smpte2086_metadata.displayPrimaryRed.x = value;
+            egl_smpte2086_metadata.displayPrimaryRed.x = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
-            smpte2086_metadata.displayPrimaryRed.y = value;
+            egl_smpte2086_metadata.displayPrimaryRed.y = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
-            smpte2086_metadata.displayPrimaryGreen.x = value;
+            egl_smpte2086_metadata.displayPrimaryGreen.x = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
-            smpte2086_metadata.displayPrimaryGreen.y = value;
+            egl_smpte2086_metadata.displayPrimaryGreen.y = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
-            smpte2086_metadata.displayPrimaryBlue.x = value;
+            egl_smpte2086_metadata.displayPrimaryBlue.x = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
-            smpte2086_metadata.displayPrimaryBlue.y = value;
+            egl_smpte2086_metadata.displayPrimaryBlue.y = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_WHITE_POINT_X_EXT:
-            smpte2086_metadata.whitePoint.x = value;
+            egl_smpte2086_metadata.whitePoint.x = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
-            smpte2086_metadata.whitePoint.y = value;
+            egl_smpte2086_metadata.whitePoint.y = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
-            smpte2086_metadata.maxLuminance = value;
+            egl_smpte2086_metadata.maxLuminance = value;
             return EGL_TRUE;
         case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
-            smpte2086_metadata.minLuminance = value;
+            egl_smpte2086_metadata.minLuminance = value;
             return EGL_TRUE;
     }
     return EGL_FALSE;
@@ -128,15 +127,39 @@
 EGLBoolean egl_surface_t::setCta8613Attribute(EGLint attribute, EGLint value) {
     switch (attribute) {
         case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
-            cta861_3_metadata.maxContentLightLevel = value;
+            egl_cta861_3_metadata.maxContentLightLevel = value;
             return EGL_TRUE;
         case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
-            cta861_3_metadata.maxFrameAverageLightLevel = value;
+            egl_cta861_3_metadata.maxFrameAverageLightLevel = value;
             return EGL_TRUE;
     }
     return EGL_FALSE;
 }
 
+const android_smpte2086_metadata egl_surface_t::getSmpte2086Metadata() {
+    android_smpte2086_metadata metadata;
+    metadata.displayPrimaryRed.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryRed.x) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryRed.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryRed.y) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryGreen.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryGreen.x) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryGreen.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryGreen.y) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryBlue.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryBlue.x) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryBlue.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryBlue.y) / EGL_METADATA_SCALING_EXT;
+    metadata.whitePoint.x = static_cast<float>(egl_smpte2086_metadata.whitePoint.x) / EGL_METADATA_SCALING_EXT;
+    metadata.whitePoint.y = static_cast<float>(egl_smpte2086_metadata.whitePoint.y) / EGL_METADATA_SCALING_EXT;
+    metadata.maxLuminance = static_cast<float>(egl_smpte2086_metadata.maxLuminance) / EGL_METADATA_SCALING_EXT;
+    metadata.minLuminance = static_cast<float>(egl_smpte2086_metadata.minLuminance) / EGL_METADATA_SCALING_EXT;
+
+    return metadata;
+}
+
+const android_cta861_3_metadata egl_surface_t::getCta8613Metadata() {
+    android_cta861_3_metadata metadata;
+    metadata.maxContentLightLevel = static_cast<float>(egl_cta861_3_metadata.maxContentLightLevel) / EGL_METADATA_SCALING_EXT;
+    metadata.maxFrameAverageLightLevel = static_cast<float>(egl_cta861_3_metadata.maxFrameAverageLightLevel) / EGL_METADATA_SCALING_EXT;
+    return metadata;
+}
+
+
 EGLBoolean egl_surface_t::getColorSpaceAttribute(EGLint attribute, EGLint* value) const {
     if (attribute == EGL_GL_COLORSPACE_KHR) {
         *value = colorSpace;
@@ -148,43 +171,43 @@
 EGLBoolean egl_surface_t::getSmpte2086Attribute(EGLint attribute, EGLint *value) const {
     switch (attribute) {
         case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryRed.x);
+            *value = egl_smpte2086_metadata.displayPrimaryRed.x;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryRed.y);
+            *value = egl_smpte2086_metadata.displayPrimaryRed.y;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryGreen.x);
+            *value = egl_smpte2086_metadata.displayPrimaryGreen.x;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryGreen.y);
+            *value = egl_smpte2086_metadata.displayPrimaryGreen.y;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryBlue.x);
+            *value = egl_smpte2086_metadata.displayPrimaryBlue.x;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryBlue.y);
+            *value = egl_smpte2086_metadata.displayPrimaryBlue.y;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_WHITE_POINT_X_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.whitePoint.x);
+            *value = egl_smpte2086_metadata.whitePoint.x;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.whitePoint.y);
+            *value = egl_smpte2086_metadata.whitePoint.y;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.maxLuminance);
+            *value = egl_smpte2086_metadata.maxLuminance;
             return EGL_TRUE;
             break;
         case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
-            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.minLuminance);
+            *value = egl_smpte2086_metadata.minLuminance;
             return EGL_TRUE;
             break;
     }
@@ -194,11 +217,11 @@
 EGLBoolean egl_surface_t::getCta8613Attribute(EGLint attribute, EGLint *value) const {
     switch (attribute) {
         case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
-            *value = *reinterpret_cast<const int*>(&cta861_3_metadata.maxContentLightLevel);
+            *value = egl_cta861_3_metadata.maxContentLightLevel;
             return EGL_TRUE;
             break;
         case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
-            *value = *reinterpret_cast<const int*>(&cta861_3_metadata.maxFrameAverageLightLevel);
+            *value = egl_cta861_3_metadata.maxFrameAverageLightLevel;
             return EGL_TRUE;
             break;
     }
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index a9020a1..bda91bb 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -142,8 +142,8 @@
     EGLBoolean getColorSpaceAttribute(EGLint attribute, EGLint* value) const;
     EGLBoolean getSmpte2086Attribute(EGLint attribute, EGLint* value) const;
     EGLBoolean getCta8613Attribute(EGLint attribute, EGLint* value) const;
-    const android_smpte2086_metadata* getSmpte2086Metadata() const { return &smpte2086_metadata; }
-    const android_cta861_3_metadata* getCta8613Metadata() const { return &cta861_3_metadata; }
+    const android_smpte2086_metadata getSmpte2086Metadata();
+    const android_cta861_3_metadata getCta8613Metadata();
 
     // Try to keep the order of these fields and size unchanged. It's not public API, but
     // it's not hard to imagine native games accessing them.
@@ -157,8 +157,27 @@
     bool connected;
     void disconnect();
     EGLint colorSpace;
-    android_smpte2086_metadata smpte2086_metadata;
-    android_cta861_3_metadata cta861_3_metadata;
+
+    struct egl_xy_color {
+        EGLint x;
+        EGLint y;
+    };
+
+    struct egl_smpte2086_metadata {
+        struct egl_xy_color displayPrimaryRed;
+        struct egl_xy_color displayPrimaryGreen;
+        struct egl_xy_color displayPrimaryBlue;
+        struct egl_xy_color whitePoint;
+        EGLint maxLuminance;
+        EGLint minLuminance;
+    };
+
+    struct egl_cta861_3_metadata {
+        EGLint maxContentLightLevel;
+        EGLint maxFrameAverageLightLevel;
+    };
+    egl_smpte2086_metadata egl_smpte2086_metadata;
+    egl_cta861_3_metadata egl_cta861_3_metadata;
 };
 
 class egl_context_t: public egl_object_t {
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 8bb74a2..9ffe036 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -50,17 +50,14 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
+#define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
+
 static bool hasWideColorDisplay =
         getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
 static bool hasHdrDisplay =
         getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
 
-union FlexAttribute {
-    EGLint uint_value;
-    float float_value;
-};
-
 class EGLTest : public ::testing::Test {
 public:
     void get8BitConfig(EGLConfig& config);
@@ -425,108 +422,81 @@
 }
 
 void EGLTest::addOptionalWindowMetadata(std::vector<EGLint>& attrs) {
-    FlexAttribute data;
     if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
         attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT);
-        data.float_value = 0.640;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.640));
         attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT);
-        data.float_value = 0.330;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.330));
         attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT);
-        data.float_value = 0.290;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.290));
         attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT);
-        data.float_value = 0.600;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.600));
         attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT);
-        data.float_value = 0.150;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.150));
         attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT);
-        data.float_value = 0.060;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.060));
         attrs.push_back(EGL_SMPTE2086_WHITE_POINT_X_EXT);
-        data.float_value = 0.3127;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.3127));
         attrs.push_back(EGL_SMPTE2086_WHITE_POINT_Y_EXT);
-        data.float_value = 0.3290;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.3290));
         attrs.push_back(EGL_SMPTE2086_MAX_LUMINANCE_EXT);
-        data.float_value = 300.0;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(300));
         attrs.push_back(EGL_SMPTE2086_MIN_LUMINANCE_EXT);
-        data.float_value = 0.7;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(0.7));
     }
 
     if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
         attrs.push_back(EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT);
-        data.float_value = 300.0;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(300));
         attrs.push_back(EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT);
-        data.float_value = 75.0;
-        attrs.push_back(data.uint_value);
+        attrs.push_back(METADATA_SCALE(75));
     }
 }
 
 void EGLTest::checkOptionalWindowMetadata(EGLSurface eglSurface) {
     EGLBoolean success;
     EGLint value;
-    FlexAttribute expected;
 
     if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.640;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(0.640), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.330;
-        ASSERT_EQ(expected.uint_value, value);
-        ASSERT_EQ(0, value);
+        ASSERT_EQ(METADATA_SCALE(0.330), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.290;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(0.290), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.600;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(0.600), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.150;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(0.150), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.060;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(0.060), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_WHITE_POINT_X_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.3127;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(0.3127), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.3290;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(0.3290), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 300.0;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(300.0), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 0.7;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(0.7), value);
     }
 
     if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 300.0;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(300.0), value);
         success = eglQuerySurface(mEglDisplay, eglSurface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT, &value);
         ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
-        expected.float_value = 75.0;
-        ASSERT_EQ(expected.uint_value, value);
+        ASSERT_EQ(METADATA_SCALE(75.0), value);
     }
 }
 
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 9f3189a..ae34d34 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -4,6 +4,7 @@
         "-DLOG_TAG=\"SurfaceFlinger\"",
         "-Wall",
         "-Werror",
+        "-Wthread-safety",
         "-Wunused",
         "-Wunreachable-code",
     ],
@@ -26,6 +27,7 @@
         "android.hardware.power@1.0",
         "libbase",
         "libbinder",
+        "libbufferhubqueue",
         "libcutils",
         "libdl",
         "libEGL",
@@ -39,6 +41,7 @@
         "libhwbinder",
         "liblayers_proto",
         "liblog",
+        "libpdx_default_transport",
         "libprotobuf-cpp-lite",
         "libsync",
         "libui",
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bef12ea..9e01fd0 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -33,8 +33,8 @@
 #include <ui/FenceTime.h>
 
 #include "DispSync.h"
-#include "SurfaceFlinger.h"
 #include "EventLog/EventLog.h"
+#include "SurfaceFlinger.h"
 
 using std::max;
 using std::min;
@@ -53,15 +53,14 @@
 // needed to re-synchronize the software vsync model with the hardware.  The
 // error metric used is the mean of the squared difference between each
 // present time and the nearest software-predicted vsync.
-static const nsecs_t kErrorThreshold = 160000000000;    // 400 usec squared
+static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
 
 #undef LOG_TAG
 #define LOG_TAG "DispSyncThread"
-class DispSyncThread: public Thread {
+class DispSyncThread : public Thread {
 public:
-
-    explicit DispSyncThread(const char* name):
-            mName(name),
+    explicit DispSyncThread(const char* name)
+          : mName(name),
             mStop(false),
             mPeriod(0),
             mPhase(0),
@@ -78,8 +77,8 @@
         mPhase = phase;
         mReferenceTime = referenceTime;
         ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
-                " mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
-                ns2us(mPhase), ns2us(mReferenceTime));
+              " mReferenceTime = %" PRId64,
+              mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
         mCond.signal();
     }
 
@@ -115,8 +114,7 @@
                 if (mPeriod == 0) {
                     err = mCond.wait(mMutex);
                     if (err != NO_ERROR) {
-                        ALOGE("error waiting for new events: %s (%d)",
-                                strerror(-err), err);
+                        ALOGE("error waiting for new events: %s (%d)", strerror(-err), err);
                         return false;
                     }
                     continue;
@@ -133,16 +131,14 @@
                         ALOGV("[%s] Waiting forever", mName);
                         err = mCond.wait(mMutex);
                     } else {
-                        ALOGV("[%s] Waiting until %" PRId64, mName,
-                                ns2us(targetTime));
+                        ALOGV("[%s] Waiting until %" PRId64, mName, ns2us(targetTime));
                         err = mCond.waitRelative(mMutex, targetTime - now);
                     }
 
                     if (err == TIMED_OUT) {
                         isWakeup = true;
                     } else if (err != NO_ERROR) {
-                        ALOGE("error waiting for next event: %s (%d)",
-                                strerror(-err), err);
+                        ALOGE("error waiting for next event: %s (%d)", strerror(-err), err);
                         return false;
                     }
                 }
@@ -153,8 +149,7 @@
                 static const nsecs_t kMaxWakeupLatency = us2ns(1500);
 
                 if (isWakeup) {
-                    mWakeupLatency = ((mWakeupLatency * 63) +
-                            (now - targetTime)) / 64;
+                    mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64;
                     mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
                     if (kTraceDetailedInfo) {
                         ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
@@ -173,8 +168,7 @@
         return false;
     }
 
-    status_t addEventListener(const char* name, nsecs_t phase,
-            const sp<DispSync::Callback>& callback) {
+    status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback) {
         if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
@@ -191,8 +185,7 @@
 
         // We want to allow the firstmost future event to fire without
         // allowing any past events to fire
-        listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase -
-                mWakeupLatency;
+        listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;
 
         mEventListeners.push(listener);
 
@@ -201,7 +194,7 @@
         return NO_ERROR;
     }
 
-    status_t removeEventListener(const sp<DispSync::Callback>& callback) {
+    status_t removeEventListener(DispSync::Callback* callback) {
         if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
@@ -225,16 +218,15 @@
     }
 
 private:
-
     struct EventListener {
         const char* mName;
         nsecs_t mPhase;
         nsecs_t mLastEventTime;
-        sp<DispSync::Callback> mCallback;
+        DispSync::Callback* mCallback;
     };
 
     struct CallbackInvocation {
-        sp<DispSync::Callback> mCallback;
+        DispSync::Callback* mCallback;
         nsecs_t mEventTime;
     };
 
@@ -243,8 +235,7 @@
         ALOGV("[%s] computeNextEventTimeLocked", mName);
         nsecs_t nextEventTime = INT64_MAX;
         for (size_t i = 0; i < mEventListeners.size(); i++) {
-            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
-                    now);
+            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], now);
 
             if (t < nextEventTime) {
                 nextEventTime = t;
@@ -257,22 +248,19 @@
 
     Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
         if (kTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName,
-                ns2us(now));
+        ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
 
         Vector<CallbackInvocation> callbackInvocations;
         nsecs_t onePeriodAgo = now - mPeriod;
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
-            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
-                    onePeriodAgo);
+            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], onePeriodAgo);
 
             if (t < now) {
                 CallbackInvocation ci;
                 ci.mCallback = mEventListeners[i].mCallback;
                 ci.mEventTime = t;
-                ALOGV("[%s] [%s] Preparing to fire", mName,
-                        mEventListeners[i].mName);
+                ALOGV("[%s] [%s] Preparing to fire", mName, mEventListeners[i].mName);
                 callbackInvocations.push(ci);
                 mEventListeners.editItemAt(i).mLastEventTime = t;
             }
@@ -281,18 +269,16 @@
         return callbackInvocations;
     }
 
-    nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener,
-            nsecs_t baseTime) {
+    nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) {
         if (kTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")",
-                mName, listener.mName, ns2us(baseTime));
+        ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName,
+              ns2us(baseTime));
 
         nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
         ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime));
         if (baseTime < lastEventTime) {
             baseTime = lastEventTime;
-            ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName,
-                    ns2us(baseTime));
+            ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName, ns2us(baseTime));
         }
 
         baseTime -= mReferenceTime;
@@ -374,11 +360,8 @@
     bool mParity;
 };
 
-DispSync::DispSync(const char* name) :
-        mName(name),
-        mRefreshSkipCount(0),
-        mThread(new DispSyncThread(name)) {
-}
+DispSync::DispSync(const char* name)
+      : mName(name), mRefreshSkipCount(0), mThread(new DispSyncThread(name)) {}
 
 DispSync::~DispSync() {}
 
@@ -404,7 +387,8 @@
         // not needed because any time there is an event registered we will
         // turn on the HW vsync events.
         if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {
-            addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());
+            mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
+            addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
         }
     }
 }
@@ -451,8 +435,8 @@
         mPhase = 0;
         mReferenceTime = timestamp;
         ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
-                "mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
-                ns2us(mReferenceTime));
+              "mReferenceTime = %" PRId64,
+              mName, ns2us(mPeriod), ns2us(mReferenceTime));
         mThread->updateModel(mPeriod, mPhase, mReferenceTime);
     }
 
@@ -480,16 +464,13 @@
     // Check against kErrorThreshold / 2 to add some hysteresis before having to
     // resync again
     bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
-    ALOGV("[%s] addResyncSample returning %s", mName,
-            modelLocked ? "locked" : "unlocked");
+    ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
     return !modelLocked;
 }
 
-void DispSync::endResync() {
-}
+void DispSync::endResync() {}
 
-status_t DispSync::addEventListener(const char* name, nsecs_t phase,
-        const sp<Callback>& callback) {
+status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback) {
     Mutex::Autolock lock(mMutex);
     return mThread->addEventListener(name, phase, callback);
 }
@@ -501,7 +482,7 @@
     updateModelLocked();
 }
 
-status_t DispSync::removeEventListener(const sp<Callback>& callback) {
+status_t DispSync::removeEventListener(Callback* callback) {
     Mutex::Autolock lock(mMutex);
     return mThread->removeEventListener(callback);
 }
@@ -597,8 +578,7 @@
         // call getSignalTime() periodically so the cache is updated when the
         // fence signals.
         nsecs_t time = mPresentFences[i]->getCachedSignalTime();
-        if (time == Fence::SIGNAL_TIME_PENDING ||
-                time == Fence::SIGNAL_TIME_INVALID) {
+        if (time == Fence::SIGNAL_TIME_PENDING || time == Fence::SIGNAL_TIME_INVALID) {
             continue;
         }
 
@@ -622,9 +602,8 @@
         mError = 0;
         // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
         mZeroErrSamplesCount++;
-        ALOGE_IF(
-                (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
-                "No present times for model error.");
+        ALOGE_IF((mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
+                 "No present times for model error.");
     }
 
     if (kTraceDetailedInfo) {
@@ -650,17 +629,14 @@
 
 void DispSync::dump(String8& result) const {
     Mutex::Autolock lock(mMutex);
-    result.appendFormat("present fences are %s\n",
-            mIgnorePresentFences ? "ignored" : "used");
-    result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n",
-            mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount);
+    result.appendFormat("present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
+    result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod,
+                        1000000000.0 / mPeriod, mRefreshSkipCount);
     result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
-    result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n",
-            mError, sqrt(mError));
+    result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError));
     result.appendFormat("mNumResyncSamplesSincePresent: %d (limit %d)\n",
-            mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
-    result.appendFormat("mNumResyncSamples: %zd (max %d)\n",
-            mNumResyncSamples, MAX_RESYNC_SAMPLES);
+                        mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
+    result.appendFormat("mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples, MAX_RESYNC_SAMPLES);
 
     result.appendFormat("mResyncSamples:\n");
     nsecs_t previous = -1;
@@ -670,14 +646,13 @@
         if (i == 0) {
             result.appendFormat("  %" PRId64 "\n", sampleTime);
         } else {
-            result.appendFormat("  %" PRId64 " (+%" PRId64 ")\n",
-                    sampleTime, sampleTime - previous);
+            result.appendFormat("  %" PRId64 " (+%" PRId64 ")\n", sampleTime,
+                                sampleTime - previous);
         }
         previous = sampleTime;
     }
 
-    result.appendFormat("mPresentFences [%d]:\n",
-            NUM_PRESENT_SAMPLES);
+    result.appendFormat("mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES);
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     previous = Fence::SIGNAL_TIME_INVALID;
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
@@ -685,17 +660,16 @@
         nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
         if (presentTime == Fence::SIGNAL_TIME_PENDING) {
             result.appendFormat("  [unsignaled fence]\n");
-        } else if(presentTime == Fence::SIGNAL_TIME_INVALID) {
+        } else if (presentTime == Fence::SIGNAL_TIME_INVALID) {
             result.appendFormat("  [invalid fence]\n");
         } else if (previous == Fence::SIGNAL_TIME_PENDING ||
-                previous == Fence::SIGNAL_TIME_INVALID) {
+                   previous == Fence::SIGNAL_TIME_INVALID) {
             result.appendFormat("  %" PRId64 "  (%.3f ms ago)\n", presentTime,
-                    (now - presentTime) / 1000000.0);
+                                (now - presentTime) / 1000000.0);
         } else {
-            result.appendFormat("  %" PRId64 " (+%" PRId64 " / %.3f)  (%.3f ms ago)\n",
-                    presentTime, presentTime - previous,
-                    (presentTime - previous) / (double) mPeriod,
-                    (now - presentTime) / 1000000.0);
+            result.appendFormat("  %" PRId64 " (+%" PRId64 " / %.3f)  (%.3f ms ago)\n", presentTime,
+                                presentTime - previous, (presentTime - previous) / (double)mPeriod,
+                                (now - presentTime) / 1000000.0);
         }
         previous = presentTime;
     }
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 880a24d..9336f4d 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -20,8 +20,8 @@
 #include <stddef.h>
 
 #include <utils/Mutex.h>
-#include <utils/Timers.h>
 #include <utils/RefBase.h>
+#include <utils/Timers.h>
 
 #include <ui/FenceTime.h>
 
@@ -47,12 +47,10 @@
 // false to indicate that a resynchronization (via addResyncSample) is not
 // needed.
 class DispSync {
-
 public:
-
-    class Callback: public virtual RefBase {
+    class Callback {
     public:
-        virtual ~Callback() {};
+        virtual ~Callback(){};
         virtual void onDispSyncEvent(nsecs_t when) = 0;
     };
 
@@ -108,13 +106,12 @@
     // given phase offset from the hardware vsync events.  The callback is
     // called from a separate thread and it should return reasonably quickly
     // (i.e. within a few hundred microseconds).
-    status_t addEventListener(const char* name, nsecs_t phase,
-            const sp<Callback>& callback);
+    status_t addEventListener(const char* name, nsecs_t phase, Callback* callback);
 
     // removeEventListener removes an already-registered event callback.  Once
     // this method returns that callback will no longer be called by the
     // DispSync object.
-    status_t removeEventListener(const sp<Callback>& callback);
+    status_t removeEventListener(Callback* callback);
 
     // computeNextRefresh computes when the next refresh is expected to begin.
     // The periodOffset value can be used to move forward or backward; an
@@ -126,7 +123,6 @@
     void dump(String8& result) const;
 
 private:
-
     void updateModelLocked();
     void updateErrorLocked();
     void resetErrorLocked();
@@ -174,8 +170,7 @@
 
     // These member variables store information about the present fences used
     // to validate the currently computed model.
-    std::shared_ptr<FenceTime>
-            mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE};
+    std::shared_ptr<FenceTime> mPresentFences[NUM_PRESENT_SAMPLES]{FenceTime::NO_FENCE};
     size_t mPresentSampleOffset;
 
     int mRefreshSkipCount;
@@ -193,8 +188,10 @@
     // Ignore present (retire) fences if the device doesn't have support for the
     // sync framework
     bool mIgnorePresentFences;
+
+    std::unique_ptr<Callback> mZeroPhaseTracer;
 };
 
-}
+} // namespace android
 
 #endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp
index 02eea47..ac54059 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -14,50 +14,57 @@
  * limitations under the License.
  */
 
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <cutils/sched_policy.h>
+#include <log/log.h>
+#include <system/thread_defs.h>
+
 #include "EventControlThread.h"
-#include "SurfaceFlinger.h"
 
 namespace android {
 
-EventControlThread::EventControlThread(const sp<SurfaceFlinger>& flinger):
-        mFlinger(flinger),
-        mVsyncEnabled(false) {
+EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
+      : mSetVSyncEnabled(function) {
+    pthread_setname_np(mThread.native_handle(), "EventControlThread");
+
+    pid_t tid = pthread_gettid_np(mThread.native_handle());
+    setpriority(PRIO_PROCESS, tid, ANDROID_PRIORITY_URGENT_DISPLAY);
+    set_sched_policy(tid, SP_FOREGROUND);
+}
+
+EventControlThread::~EventControlThread() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mKeepRunning = false;
+        mCondition.notify_all();
+    }
+    mThread.join();
 }
 
 void EventControlThread::setVsyncEnabled(bool enabled) {
-    Mutex::Autolock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
     mVsyncEnabled = enabled;
-    mCond.signal();
+    mCondition.notify_all();
 }
 
-bool EventControlThread::threadLoop() {
-    enum class VsyncState {Unset, On, Off};
-    auto currentVsyncState = VsyncState::Unset;
+// Unfortunately std::unique_lock gives warnings with -Wthread-safety
+void EventControlThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
+    auto keepRunning = true;
+    auto currentVsyncEnabled = false;
 
-    while (true) {
-        auto requestedVsyncState = VsyncState::On;
-        {
-            Mutex::Autolock lock(mMutex);
-            requestedVsyncState =
-                    mVsyncEnabled ? VsyncState::On : VsyncState::Off;
-            while (currentVsyncState == requestedVsyncState) {
-                status_t err = mCond.wait(mMutex);
-                if (err != NO_ERROR) {
-                    ALOGE("error waiting for new events: %s (%d)",
-                          strerror(-err), err);
-                    return false;
-                }
-                requestedVsyncState =
-                        mVsyncEnabled ? VsyncState::On : VsyncState::Off;
-            }
-        }
+    while (keepRunning) {
+        mSetVSyncEnabled(currentVsyncEnabled);
 
-        bool enable = requestedVsyncState == VsyncState::On;
-        mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable);
-        currentVsyncState = requestedVsyncState;
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondition.wait(lock, [this, currentVsyncEnabled, keepRunning]() NO_THREAD_SAFETY_ANALYSIS {
+            return currentVsyncEnabled != mVsyncEnabled || keepRunning != mKeepRunning;
+        });
+        currentVsyncEnabled = mVsyncEnabled;
+        keepRunning = mKeepRunning;
     }
-
-    return false;
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h
index 1b1ef75..321fb79 100644
--- a/services/surfaceflinger/EventControlThread.h
+++ b/services/surfaceflinger/EventControlThread.h
@@ -14,35 +14,41 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_EVENTCONTROLTHREAD_H
-#define ANDROID_EVENTCONTROLTHREAD_H
+#pragma once
 
-#include <stddef.h>
+#include <cstddef>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <thread>
 
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
+#include <android-base/thread_annotations.h>
 
 namespace android {
 
 class SurfaceFlinger;
 
-class EventControlThread: public Thread {
+class EventControlThread {
 public:
+    using SetVSyncEnabledFunction = std::function<void(bool)>;
 
-    explicit EventControlThread(const sp<SurfaceFlinger>& flinger);
-    virtual ~EventControlThread() {}
+    explicit EventControlThread(SetVSyncEnabledFunction function);
+    ~EventControlThread();
 
     void setVsyncEnabled(bool enabled);
-    virtual bool threadLoop();
 
 private:
-    sp<SurfaceFlinger> mFlinger;
-    bool mVsyncEnabled;
+    void threadMain();
 
-    Mutex mMutex;
-    Condition mCond;
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+
+    const SetVSyncEnabledFunction mSetVSyncEnabled;
+    bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+    bool mKeepRunning GUARDED_BY(mMutex) = true;
+
+    // Must be last so that everything is initialized before the thread starts.
+    std::thread mThread{&EventControlThread::threadMain, this};
 };
 
-}
-
-#endif // ANDROID_EVENTCONTROLTHREAD_H
+} // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 5c0e3b3..53d95e2 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -16,13 +16,17 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <stdint.h>
+#include <pthread.h>
+#include <sched.h>
 #include <sys/types.h>
+#include <chrono>
+#include <cstdint>
 
 #include <cutils/compiler.h>
+#include <cutils/sched_policy.h>
 
-#include <gui/IDisplayEventConnection.h>
 #include <gui/DisplayEventReceiver.h>
+#include <gui/IDisplayEventConnection.h>
 
 #include <utils/Errors.h>
 #include <utils/String8.h>
@@ -31,109 +35,126 @@
 #include "EventThread.h"
 #include "SurfaceFlinger.h"
 
+using namespace std::chrono_literals;
+
 // ---------------------------------------------------------------------------
+
 namespace android {
+
 // ---------------------------------------------------------------------------
 
-EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs)
-    : mVSyncSource(src),
-      mFlinger(flinger),
-      mUseSoftwareVSync(false),
-      mVsyncEnabled(false),
-      mDebugVsyncEnabled(false),
-      mInterceptVSyncs(interceptVSyncs) {
-
-    for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
-        mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-        mVSyncEvent[i].header.id = 0;
-        mVSyncEvent[i].header.timestamp = 0;
-        mVSyncEvent[i].vsync.count =  0;
+EventThread::EventThread(VSyncSource* src, SurfaceFlinger& flinger, bool interceptVSyncs,
+                         const char* threadName)
+      : mVSyncSource(src), mFlinger(flinger), mInterceptVSyncs(interceptVSyncs) {
+    for (auto& event : mVSyncEvent) {
+        event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+        event.header.id = 0;
+        event.header.timestamp = 0;
+        event.vsync.count = 0;
     }
+
+    mThread = std::thread(&EventThread::threadMain, this);
+
+    pthread_setname_np(mThread.native_handle(), threadName);
+
+    pid_t tid = pthread_gettid_np(mThread.native_handle());
+
+    // Use SCHED_FIFO to minimize jitter
+    constexpr int EVENT_THREAD_PRIORITY = 2;
+    struct sched_param param = {0};
+    param.sched_priority = EVENT_THREAD_PRIORITY;
+    if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for EventThread");
+    }
+
+    set_sched_policy(tid, SP_FOREGROUND);
+}
+
+EventThread::~EventThread() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mKeepRunning = false;
+        mCondition.notify_all();
+    }
+    mThread.join();
 }
 
 void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     mVSyncSource->setPhaseOffset(phaseOffset);
 }
 
-void EventThread::onFirstRef() {
-    run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
-}
-
 sp<EventThread::Connection> EventThread::createEventConnection() const {
     return new Connection(const_cast<EventThread*>(this));
 }
 
 status_t EventThread::registerDisplayEventConnection(
         const sp<EventThread::Connection>& connection) {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     mDisplayEventConnections.add(connection);
-    mCondition.broadcast();
+    mCondition.notify_all();
     return NO_ERROR;
 }
 
-void EventThread::removeDisplayEventConnection(
-        const wp<EventThread::Connection>& connection) {
-    Mutex::Autolock _l(mLock);
+void EventThread::removeDisplayEventConnection(const wp<EventThread::Connection>& connection) {
+    std::lock_guard<std::mutex> lock(mMutex);
     mDisplayEventConnections.remove(connection);
 }
 
-void EventThread::setVsyncRate(uint32_t count,
-        const sp<EventThread::Connection>& connection) {
+void EventThread::setVsyncRate(uint32_t count, const sp<EventThread::Connection>& connection) {
     if (int32_t(count) >= 0) { // server must protect against bad params
-        Mutex::Autolock _l(mLock);
+        std::lock_guard<std::mutex> lock(mMutex);
         const int32_t new_count = (count == 0) ? -1 : count;
         if (connection->count != new_count) {
             connection->count = new_count;
-            mCondition.broadcast();
+            mCondition.notify_all();
         }
     }
 }
 
-void EventThread::requestNextVsync(
-        const sp<EventThread::Connection>& connection) {
-    Mutex::Autolock _l(mLock);
+void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) {
+    std::lock_guard<std::mutex> lock(mMutex);
 
     mFlinger.resyncWithRateLimit();
 
     if (connection->count < 0) {
         connection->count = 0;
-        mCondition.broadcast();
+        mCondition.notify_all();
     }
 }
 
 void EventThread::onScreenReleased() {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     if (!mUseSoftwareVSync) {
         // disable reliance on h/w vsync
         mUseSoftwareVSync = true;
-        mCondition.broadcast();
+        mCondition.notify_all();
     }
 }
 
 void EventThread::onScreenAcquired() {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     if (mUseSoftwareVSync) {
         // resume use of h/w vsync
         mUseSoftwareVSync = false;
-        mCondition.broadcast();
+        mCondition.notify_all();
     }
 }
 
 void EventThread::onVSyncEvent(nsecs_t timestamp) {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
     mVSyncEvent[0].header.id = 0;
     mVSyncEvent[0].header.timestamp = timestamp;
     mVSyncEvent[0].vsync.count++;
-    mCondition.broadcast();
+    mCondition.notify_all();
 }
 
 void EventThread::onHotplugReceived(int type, bool connected) {
     ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
-            "received hotplug event for an invalid display (id=%d)", type);
+             "received hotplug event for an invalid display (id=%d)", type);
 
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
         DisplayEventReceiver::Event event;
         event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
@@ -141,54 +162,54 @@
         event.header.timestamp = systemTime();
         event.hotplug.connected = connected;
         mPendingEvents.add(event);
-        mCondition.broadcast();
+        mCondition.notify_all();
     }
 }
 
-bool EventThread::threadLoop() {
-    DisplayEventReceiver::Event event;
-    Vector< sp<EventThread::Connection> > signalConnections;
-    signalConnections = waitForEvent(&event);
+void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
+    std::unique_lock<std::mutex> lock(mMutex);
+    while (mKeepRunning) {
+        DisplayEventReceiver::Event event;
+        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]);
-        // now see if we still need to report this event
-        status_t err = conn->postEvent(event);
-        if (err == -EAGAIN || err == -EWOULDBLOCK) {
-            // The destination doesn't accept events anymore, it's probably
-            // full. For now, we just drop the events on the floor.
-            // FIXME: Note that some events cannot be dropped and would have
-            // to be re-sent later.
-            // Right-now we don't have the ability to do this.
-            ALOGW("EventThread: dropping event (%08x) for connection %p",
-                    event.header.type, conn.get());
-        } else if (err < 0) {
-            // 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.
-            removeDisplayEventConnection(signalConnections[i]);
+        // dispatch events to listeners...
+        const size_t count = signalConnections.size();
+        for (size_t i = 0; i < count; i++) {
+            const sp<Connection>& conn(signalConnections[i]);
+            // now see if we still need to report this event
+            status_t err = conn->postEvent(event);
+            if (err == -EAGAIN || err == -EWOULDBLOCK) {
+                // The destination doesn't accept events anymore, it's probably
+                // full. For now, we just drop the events on the floor.
+                // FIXME: Note that some events cannot be dropped and would have
+                // to be re-sent later.
+                // Right-now we don't have the ability to do this.
+                ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type,
+                      conn.get());
+            } else if (err < 0) {
+                // 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.
+                removeDisplayEventConnection(signalConnections[i]);
+            }
         }
     }
-    return true;
 }
 
 // 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::waitForEvent(
-        DisplayEventReceiver::Event* event)
-{
-    Mutex::Autolock _l(mLock);
-    Vector< sp<EventThread::Connection> > signalConnections;
+Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(
+        std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* event) {
+    Vector<sp<EventThread::Connection> > signalConnections;
 
-    do {
+    while (signalConnections.isEmpty() && mKeepRunning) {
         bool eventPending = false;
         bool waitForVSync = false;
 
         size_t vsyncCount = 0;
         nsecs_t timestamp = 0;
-        for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
+        for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {
             timestamp = mVSyncEvent[i].header.timestamp;
             if (timestamp) {
                 // we have a vsync event to dispatch
@@ -214,7 +235,7 @@
 
         // find out connections waiting for events
         size_t count = mDisplayEventConnections.size();
-        for (size_t i=0 ; i<count ; ) {
+        for (size_t i = 0; i < count;) {
             sp<Connection> connection(mDisplayEventConnections[i].promote());
             if (connection != nullptr) {
                 bool added = false;
@@ -231,7 +252,7 @@
                             signalConnections.add(connection);
                             added = true;
                         } else if (connection->count == 1 ||
-                                (vsyncCount % connection->count) == 0) {
+                                   (vsyncCount % connection->count) == 0) {
                             // continuous event, and time to report it
                             signalConnections.add(connection);
                             added = true;
@@ -285,8 +306,8 @@
                 // use a (long) timeout when waiting for h/w vsync, and
                 // generate fake events when necessary.
                 bool softwareSync = mUseSoftwareVSync;
-                nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
-                if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
+                auto timeout = softwareSync ? 16ms : 1000ms;
+                if (mCondition.wait_for(*lock, timeout) == std::cv_status::timeout) {
                     if (!softwareSync) {
                         ALOGW("Timed out waiting for hw vsync; faking it");
                     }
@@ -302,10 +323,10 @@
                 // h/w vsync should be disabled, so this will wait until we
                 // get a new connection, or an existing connection becomes
                 // interested in receiving vsync again.
-                mCondition.wait(mLock);
+                mCondition.wait(*lock);
             }
         }
-    } while (signalConnections.isEmpty());
+    }
 
     // here we're guaranteed to have a timestamp and some connections to signal
     // (The connections might have dropped out of mDisplayEventConnections
@@ -318,7 +339,7 @@
         // never enable h/w VSYNC when screen is off
         if (!mVsyncEnabled) {
             mVsyncEnabled = true;
-            mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
+            mVSyncSource->setCallback(this);
             mVSyncSource->setVSyncEnabled(true);
         }
     }
@@ -334,29 +355,23 @@
 }
 
 void EventThread::dump(String8& result) const {
-    Mutex::Autolock _l(mLock);
-    result.appendFormat("VSYNC state: %s\n",
-            mDebugVsyncEnabled?"enabled":"disabled");
-    result.appendFormat("  soft-vsync: %s\n",
-            mUseSoftwareVSync?"enabled":"disabled");
+    std::lock_guard<std::mutex> lock(mMutex);
+    result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
+    result.appendFormat("  soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
     result.appendFormat("  numListeners=%zu,\n  events-delivered: %u\n",
-            mDisplayEventConnections.size(),
-            mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
-    for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
-        sp<Connection> connection =
-                mDisplayEventConnections.itemAt(i).promote();
-        result.appendFormat("    %p: count=%d\n",
-                connection.get(), connection != nullptr ? connection->count : 0);
+                        mDisplayEventConnections.size(),
+                        mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
+    for (size_t i = 0; i < mDisplayEventConnections.size(); i++) {
+        sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
+        result.appendFormat("    %p: count=%d\n", connection.get(),
+                            connection != nullptr ? connection->count : 0);
     }
 }
 
 // ---------------------------------------------------------------------------
 
-EventThread::Connection::Connection(
-        const sp<EventThread>& eventThread)
-    : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize)
-{
-}
+EventThread::Connection::Connection(EventThread* eventThread)
+      : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
 
 EventThread::Connection::~Connection() {
     // do nothing here -- clean-up will happen automatically
@@ -382,12 +397,11 @@
     mEventThread->requestNextVsync(this);
 }
 
-status_t EventThread::Connection::postEvent(
-        const DisplayEventReceiver::Event& event) {
+status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) {
     ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 0823839..9ae8fb2 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -14,18 +14,21 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SURFACE_FLINGER_EVENT_THREAD_H
-#define ANDROID_SURFACE_FLINGER_EVENT_THREAD_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
 
-#include <private/gui/BitTube.h>
+#include <android-base/thread_annotations.h>
+
 #include <gui/DisplayEventReceiver.h>
 #include <gui/IDisplayEventConnection.h>
+#include <private/gui/BitTube.h>
 
 #include <utils/Errors.h>
-#include <utils/threads.h>
 #include <utils/SortedVector.h>
 
 #include "DisplayDevice.h"
@@ -39,10 +42,9 @@
 
 // ---------------------------------------------------------------------------
 
-
-class VSyncSource : public virtual RefBase {
+class VSyncSource {
 public:
-    class Callback: public virtual RefBase {
+    class Callback {
     public:
         virtual ~Callback() {}
         virtual void onVSyncEvent(nsecs_t when) = 0;
@@ -50,14 +52,14 @@
 
     virtual ~VSyncSource() {}
     virtual void setVSyncEnabled(bool enable) = 0;
-    virtual void setCallback(const sp<Callback>& callback) = 0;
+    virtual void setCallback(Callback* callback) = 0;
     virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
 };
 
-class EventThread : public Thread, private VSyncSource::Callback {
+class EventThread : private VSyncSource::Callback {
     class Connection : public BnDisplayEventConnection {
     public:
-        explicit Connection(const sp<EventThread>& eventThread);
+        explicit Connection(EventThread* eventThread);
         status_t postEvent(const DisplayEventReceiver::Event& event);
 
         // count >= 1 : continuous event. count is the vsync rate
@@ -70,14 +72,15 @@
         virtual void onFirstRef();
         status_t stealReceiveChannel(gui::BitTube* outChannel) override;
         status_t setVsyncRate(uint32_t count) override;
-        void requestNextVsync() override;    // asynchronous
-        sp<EventThread> const mEventThread;
+        void requestNextVsync() override; // asynchronous
+        EventThread* const mEventThread;
         gui::BitTube mChannel;
     };
 
 public:
-
-    EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs);
+    EventThread(VSyncSource* src, SurfaceFlinger& flinger, bool interceptVSyncs,
+                const char* threadName);
+    ~EventThread();
 
     sp<Connection> createEventConnection() const;
     status_t registerDisplayEventConnection(const sp<Connection>& connection);
@@ -94,47 +97,46 @@
     // called when receiving a hotplug event
     void onHotplugReceived(int type, bool connected);
 
-    Vector< sp<EventThread::Connection> > waitForEvent(
-            DisplayEventReceiver::Event* event);
-
     void dump(String8& result) const;
 
     void setPhaseOffset(nsecs_t phaseOffset);
 
 private:
-    virtual bool        threadLoop();
-    virtual void        onFirstRef();
-
-    virtual void onVSyncEvent(nsecs_t timestamp);
+    void threadMain();
+    Vector<sp<EventThread::Connection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
+                                                           DisplayEventReceiver::Event* event)
+            REQUIRES(mMutex);
 
     void removeDisplayEventConnection(const wp<Connection>& connection);
-    void enableVSyncLocked();
-    void disableVSyncLocked();
+    void enableVSyncLocked() REQUIRES(mMutex);
+    void disableVSyncLocked() REQUIRES(mMutex);
+
+    // Implements VSyncSource::Callback
+    void onVSyncEvent(nsecs_t timestamp) override;
 
     // constants
-    sp<VSyncSource> mVSyncSource;
+    VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
     SurfaceFlinger& mFlinger;
 
-    mutable Mutex mLock;
-    mutable Condition mCondition;
+    std::thread mThread;
+    mutable std::mutex mMutex;
+    mutable std::condition_variable mCondition;
 
     // protected by mLock
-    SortedVector< wp<Connection> > mDisplayEventConnections;
-    Vector< DisplayEventReceiver::Event > mPendingEvents;
-    DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
-    bool mUseSoftwareVSync;
-    bool mVsyncEnabled;
+    SortedVector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
+    Vector<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
+    DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES] GUARDED_BY(
+            mMutex);
+    bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
+    bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+    bool mKeepRunning GUARDED_BY(mMutex) = true;
 
     // for debugging
-    bool mDebugVsyncEnabled;
+    bool mDebugVsyncEnabled GUARDED_BY(mMutex) = false;
 
-    const bool mInterceptVSyncs;
+    const bool mInterceptVSyncs = false;
 };
 
 // ---------------------------------------------------------------------------
 
 }; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif /* ANDROID_SURFACE_FLINGER_EVENT_THREAD_H */
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index 0b1199c..5a6ff4d 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -14,32 +14,29 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
 #include <errno.h>
+#include <stdint.h>
 #include <sys/types.h>
 
 #include <binder/IPCThreadState.h>
 
-#include <utils/threads.h>
-#include <utils/Timers.h>
 #include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
 
 #include <gui/IDisplayEventConnection.h>
 
-#include "MessageQueue.h"
 #include "EventThread.h"
+#include "MessageQueue.h"
 #include "SurfaceFlinger.h"
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
-MessageBase::MessageBase()
-    : MessageHandler() {
-}
+MessageBase::MessageBase() : MessageHandler() {}
 
-MessageBase::~MessageBase() {
-}
+MessageBase::~MessageBase() {}
 
 void MessageBase::handleMessage(const Message&) {
     this->handler();
@@ -75,22 +72,17 @@
 
 // ---------------------------------------------------------------------------
 
-MessageQueue::MessageQueue()
-{
-}
+MessageQueue::MessageQueue() {}
 
-MessageQueue::~MessageQueue() {
-}
+MessageQueue::~MessageQueue() {}
 
-void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
-{
+void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
     mFlinger = flinger;
     mLooper = new Looper(true);
     mHandler = new Handler(*this);
 }
 
-void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
-{
+void MessageQueue::setEventThread(EventThread* eventThread) {
     if (mEventThread == eventThread) {
         return;
     }
@@ -102,8 +94,8 @@
     mEventThread = eventThread;
     mEvents = eventThread->createEventConnection();
     mEvents->stealReceiveChannel(&mEventTube);
-    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT,
-            MessageQueue::cb_eventReceiver, this);
+    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
+                   this);
 }
 
 void MessageQueue::waitMessage() {
@@ -128,9 +120,7 @@
     } while (true);
 }
 
-status_t MessageQueue::postMessage(
-        const sp<MessageBase>& messageHandler, nsecs_t relTime)
-{
+status_t MessageQueue::postMessage(const sp<MessageBase>& messageHandler, nsecs_t relTime) {
     const Message dummyMessage;
     if (relTime > 0) {
         mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
@@ -140,7 +130,6 @@
     return NO_ERROR;
 }
 
-
 void MessageQueue::invalidate() {
     mEvents->requestNextVsync();
 }
@@ -150,7 +139,7 @@
 }
 
 int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
-    MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
+    MessageQueue* queue = reinterpret_cast<MessageQueue*>(data);
     return queue->eventReceiver(fd, events);
 }
 
@@ -158,7 +147,7 @@
     ssize_t n;
     DisplayEventReceiver::Event buffer[8];
     while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
-        for (int i=0 ; i<n ; i++) {
+        for (int i = 0; i < n; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                 mHandler->dispatchInvalidate();
                 break;
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 14f50bb..dcfc716 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -17,16 +17,16 @@
 #ifndef ANDROID_MESSAGE_QUEUE_H
 #define ANDROID_MESSAGE_QUEUE_H
 
-#include <stdint.h>
 #include <errno.h>
+#include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/threads.h>
-#include <utils/Timers.h>
 #include <utils/Looper.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
 
-#include <private/gui/BitTube.h>
 #include <gui/DisplayEventReceiver.h>
+#include <private/gui/BitTube.h>
 
 #include "Barrier.h"
 
@@ -40,11 +40,10 @@
 
 // ---------------------------------------------------------------------------
 
-class MessageBase : public MessageHandler
-{
+class MessageBase : public MessageHandler {
 public:
     MessageBase();
-    
+
     // return true if message has a handler
     virtual bool handler() = 0;
 
@@ -79,15 +78,12 @@
 
 class MessageQueue {
     class Handler : public MessageHandler {
-        enum {
-            eventMaskInvalidate     = 0x1,
-            eventMaskRefresh        = 0x2,
-            eventMaskTransaction    = 0x4
-        };
+        enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
         MessageQueue& mQueue;
         int32_t mEventMask;
+
     public:
-        explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+        explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
         virtual void handleMessage(const Message& message);
         void dispatchRefresh();
         void dispatchInvalidate();
@@ -97,28 +93,27 @@
 
     sp<SurfaceFlinger> mFlinger;
     sp<Looper> mLooper;
-    sp<EventThread> mEventThread;
+    EventThread* mEventThread;
     sp<IDisplayEventConnection> mEvents;
     gui::BitTube mEventTube;
     sp<Handler> mHandler;
 
-
     static int cb_eventReceiver(int fd, int events, void* data);
     int eventReceiver(int fd, int events);
 
 public:
     enum {
-        INVALIDATE  = 0,
-        REFRESH     = 1,
+        INVALIDATE = 0,
+        REFRESH = 1,
     };
 
     MessageQueue();
     ~MessageQueue();
     void init(const sp<SurfaceFlinger>& flinger);
-    void setEventThread(const sp<EventThread>& events);
+    void setEventThread(EventThread* events);
 
     void waitMessage();
-    status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
+    status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0);
 
     // sends INVALIDATE message at next VSYNC
     void invalidate();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d8740d9..1054c32 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -424,7 +424,7 @@
     postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
 }
 
-class DispSyncSource : public VSyncSource, private DispSync::Callback {
+class DispSyncSource final : public VSyncSource, private DispSync::Callback {
 public:
     DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
         const char* name) :
@@ -435,14 +435,13 @@
             mVsyncEventLabel(String8::format("VSYNC-%s", name)),
             mDispSync(dispSync),
             mCallbackMutex(),
-            mCallback(),
             mVsyncMutex(),
             mPhaseOffset(phaseOffset),
             mEnabled(false) {}
 
-    virtual ~DispSyncSource() {}
+    ~DispSyncSource() override = default;
 
-    virtual void setVSyncEnabled(bool enable) {
+    void setVSyncEnabled(bool enable) override {
         Mutex::Autolock lock(mVsyncMutex);
         if (enable) {
             status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
@@ -464,12 +463,12 @@
         mEnabled = enable;
     }
 
-    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+    void setCallback(VSyncSource::Callback* callback) override{
         Mutex::Autolock lock(mCallbackMutex);
         mCallback = callback;
     }
 
-    virtual void setPhaseOffset(nsecs_t phaseOffset) {
+    void setPhaseOffset(nsecs_t phaseOffset) override {
         Mutex::Autolock lock(mVsyncMutex);
 
         // Normalize phaseOffset to [0, period)
@@ -506,7 +505,7 @@
 
 private:
     virtual void onDispSyncEvent(nsecs_t when) {
-        sp<VSyncSource::Callback> callback;
+        VSyncSource::Callback* callback;
         {
             Mutex::Autolock lock(mCallbackMutex);
             callback = mCallback;
@@ -533,37 +532,36 @@
     DispSync* mDispSync;
 
     Mutex mCallbackMutex; // Protects the following
-    sp<VSyncSource::Callback> mCallback;
+    VSyncSource::Callback* mCallback = nullptr;
 
     Mutex mVsyncMutex; // Protects the following
     nsecs_t mPhaseOffset;
     bool mEnabled;
 };
 
-class InjectVSyncSource : public VSyncSource {
+class InjectVSyncSource final : public VSyncSource {
 public:
-    InjectVSyncSource() {}
+    InjectVSyncSource() = default;
+    ~InjectVSyncSource() override = default;
 
-    virtual ~InjectVSyncSource() {}
-
-    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+    void setCallback(VSyncSource::Callback* callback) override {
         std::lock_guard<std::mutex> lock(mCallbackMutex);
         mCallback = callback;
     }
 
-    virtual void onInjectSyncEvent(nsecs_t when) {
+    void onInjectSyncEvent(nsecs_t when) {
         std::lock_guard<std::mutex> lock(mCallbackMutex);
         if (mCallback) {
             mCallback->onVSyncEvent(when);
         }
     }
 
-    virtual void setVSyncEnabled(bool) {}
-    virtual void setPhaseOffset(nsecs_t) {}
+    void setVSyncEnabled(bool) override {}
+    void setPhaseOffset(nsecs_t) override {}
 
 private:
     std::mutex mCallbackMutex; // Protects the following
-    sp<VSyncSource::Callback> mCallback;
+    VSyncSource::Callback* mCallback = nullptr;
 };
 
 // Do not call property_set on main thread which will be blocked by init
@@ -577,23 +575,16 @@
     Mutex::Autolock _l(mStateLock);
 
     // start the EventThread
-    sp<VSyncSource> vsyncSrc =
-            new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
-    mEventThread = new EventThread(vsyncSrc, *this, false);
-    sp<VSyncSource> sfVsyncSrc =
-            new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
-    mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
-    mEventQueue.setEventThread(mSFEventThread);
 
-    // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
-    struct sched_param param = {0};
-    param.sched_priority = 2;
-    if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-        ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
-    }
-    if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-        ALOGE("Couldn't set SCHED_FIFO for EventThread");
-    }
+    mEventThreadSource = std::make_unique<DispSyncSource>(
+            &mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
+    mEventThread = std::make_unique<EventThread>(
+            mEventThreadSource.get(), *this, false, "sfEventThread");
+    mSfEventThreadSource = std::make_unique<DispSyncSource>(
+            &mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+    mSFEventThread = std::make_unique<EventThread>(
+            mSfEventThreadSource.get(), *this, true, "appEventThread");
+    mEventQueue.setEventThread(mSFEventThread.get());
 
     // Get a RenderEngine for the given display / config (can't fail)
     getBE().mRenderEngine = RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
@@ -636,8 +627,9 @@
         }
     }
 
-    mEventControlThread = new EventControlThread(this);
-    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
+    mEventControlThread = std::make_unique<EventControlThread>([this](bool enabled) {
+        setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled);
+    });
 
     // initialize our drawing state
     mDrawingState = mCurrentState;
@@ -1072,13 +1064,14 @@
         if (enable) {
             ALOGV("VSync Injections enabled");
             if (mVSyncInjector.get() == nullptr) {
-                mVSyncInjector = new InjectVSyncSource();
-                mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
+                mVSyncInjector = std::make_unique<InjectVSyncSource>();
+                mInjectorEventThread = std::make_unique<EventThread>(
+                        mVSyncInjector.get(), *this, false, "injEvThread");
             }
-            mEventQueue.setEventThread(mInjectorEventThread);
+            mEventQueue.setEventThread(mInjectorEventThread.get());
         } else {
             ALOGV("VSync Injections disabled");
-            mEventQueue.setEventThread(mSFEventThread);
+            mEventQueue.setEventThread(mSFEventThread.get());
         }
 
         mInjectVSyncs = enable;
@@ -1101,7 +1094,8 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
+        NO_THREAD_SAFETY_ANALYSIS {
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
@@ -3567,7 +3561,8 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto)
+        NO_THREAD_SAFETY_ANALYSIS {
     String8 result;
 
     IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bde1a8e..19dd059 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -719,11 +719,13 @@
     // constant members (no synchronization needed for access)
     nsecs_t mBootTime;
     bool mGpuToCpuSupported;
-    sp<EventThread> mEventThread;
-    sp<EventThread> mSFEventThread;
-    sp<EventThread> mInjectorEventThread;
-    sp<InjectVSyncSource> mVSyncInjector;
-    sp<EventControlThread> mEventControlThread;
+    std::unique_ptr<EventThread> mEventThread;
+    std::unique_ptr<EventThread> mSFEventThread;
+    std::unique_ptr<EventThread> mInjectorEventThread;
+    std::unique_ptr<VSyncSource> mEventThreadSource;
+    std::unique_ptr<VSyncSource> mSfEventThreadSource;
+    std::unique_ptr<InjectVSyncSource> mVSyncInjector;
+    std::unique_ptr<EventControlThread> mEventControlThread;
     sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
 
     // Can only accessed from the main thread, these members
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index e1997d7..1a99cf4 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -27,7 +27,6 @@
 
 staticLibraries := \
 	libperformance \
-	libpdx_default_transport \
 	libbufferhub
 
 sharedLibraries := \
@@ -38,7 +37,8 @@
 	libsync \
 	libutils \
         libgui \
-        libui
+        libui \
+	libpdx_default_transport \
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(sourceFiles)
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 063d83c..caf9049 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -10,9 +10,6 @@
     "libbroadcastring",
     "libhwcomposer-client",
     "libdisplay",
-    "libbufferhubqueue",
-    "libbufferhub",
-    "libpdx_default_transport",
   ],
 
   shared_libs: [
@@ -20,6 +17,7 @@
     "android.hardware.graphics.composer@2.1",
     "android.hardware.graphics.mapper@2.0",
     "libbase",
+    "libbufferhubqueue",
     "libbinder",
     "libcutils",
     "libfmq",
@@ -30,6 +28,7 @@
     "libsync",
     "libui",
     "libutils",
+    "libpdx_default_transport",
   ],
 
   header_libs: [
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
index 1470234..a548ef0 100644
--- a/services/vr/performanced/Android.mk
+++ b/services/vr/performanced/Android.mk
@@ -22,7 +22,6 @@
 
 staticLibraries := \
 	libperformance \
-	libpdx_default_transport \
 	libvr_manager
 
 sharedLibraries := \
@@ -30,7 +29,8 @@
 	libbase \
 	libcutils \
 	liblog \
-	libutils
+	libutils \
+	libpdx_default_transport \
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(sourceFiles)
diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp
index 726e854..7404b94 100644
--- a/vulkan/libvulkan/stubhal.cpp
+++ b/vulkan/libvulkan/stubhal.cpp
@@ -97,6 +97,14 @@
     return VK_SUCCESS;
 }
 
+VKAPI_ATTR VkResult
+EnumeratePhysicalDeviceGroups(VkInstance /*instance*/,
+                              uint32_t* count,
+                              VkPhysicalDeviceGroupProperties* /*properties*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
 VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
                                                   const char* name) {
     if (strcmp(name, "vkCreateInstance") == 0)
@@ -108,6 +116,9 @@
             EnumerateInstanceExtensionProperties);
     if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
+    if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            EnumeratePhysicalDeviceGroups);
     if (strcmp(name, "vkGetInstanceProcAddr") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
     // Per the spec, return NULL if instance is NULL.