Merge "Move display id into MotionEvent"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 898aa90..57745ef 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -1221,8 +1221,10 @@
     }
 
     bool ok = true;
-    ok &= setUpTrace();
-    ok &= startTrace();
+    if (traceStart) {
+        ok &= setUpTrace();
+        ok &= startTrace();
+    }
 
     if (ok && traceStart) {
         if (!traceStream) {
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 562898d..b04543b 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -76,6 +76,7 @@
         "libdebuggerd_client",
         "libdumpstateaidl",
         "libdumpstateutil",
+        "libdumputils",
         "libhidlbase",
         "libhidltransport",
         "liblog",
@@ -119,4 +120,4 @@
         "tests/dumpstate_smoke_test.cpp",
     ],
     static_libs: ["libgmock"],
-}
\ No newline at end of file
+}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index d8bbdbb..371533c 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1506,6 +1506,12 @@
     RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
 
     printf("========================================================\n");
+    printf("== Checkins\n");
+    printf("========================================================\n");
+
+    RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+
+    printf("========================================================\n");
     printf("== dumpstate: done (id %d)\n", ds.id_);
     printf("========================================================\n");
 }
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index a89925f..022f4fc 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -48,10 +48,10 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
 #include <debuggerd/client.h>
+#include <dumputils/dump_utils.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -76,36 +76,6 @@
     return ds.RunCommand(title, full_command, options);
 }
 
-/* list of native processes to include in the native dumps */
-// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
-static const char* native_processes_to_dump[] = {
-        "/system/bin/audioserver",
-        "/system/bin/cameraserver",
-        "/system/bin/drmserver",
-        "/system/bin/mediadrmserver",
-        "/system/bin/mediaextractor", // media.extractor
-        "/system/bin/mediametrics", // media.metrics
-        "/system/bin/mediaserver",
-        "/system/bin/sdcard",
-	"/system/bin/statsd",
-        "/system/bin/surfaceflinger",
-        "/system/bin/vehicle_network_service",
-        "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
-        NULL,
-};
-
-/* list of hal interface to dump containing process during native dumps */
-static const char* hal_interfaces_to_dump[] {
-        "android.hardware.audio@2.0::IDevicesFactory",
-        "android.hardware.bluetooth@1.0::IBluetoothHci",
-        "android.hardware.camera.provider@2.4::ICameraProvider",
-        "android.hardware.graphics.composer@2.1::IComposer",
-        "android.hardware.media.omx@1.0::IOmx",
-        "android.hardware.sensors@1.0::ISensors",
-        "android.hardware.vr@1.0::IVr",
-        NULL,
-};
-
 // Reasonable value for max stats.
 static const int STATS_MAX_N_RUNS = 1000;
 static const long STATS_MAX_AVERAGE = 100000;
@@ -809,53 +779,6 @@
     _redirect_to_file(redirect, path, O_APPEND);
 }
 
-static bool should_dump_hal_interface(const char* interface) {
-    for (const char** i = hal_interfaces_to_dump; *i; i++) {
-        if (!strcmp(*i, interface)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static bool should_dump_native_traces(const char* path) {
-    for (const char** p = native_processes_to_dump; *p; p++) {
-        if (!strcmp(*p, path)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-std::set<int> get_interesting_hal_pids() {
-    using android::hidl::manager::V1_0::IServiceManager;
-    using android::sp;
-    using android::hardware::Return;
-
-    sp<IServiceManager> manager = IServiceManager::getService();
-    std::set<int> pids;
-
-    Return<void> ret = manager->debugDump([&](auto& hals) {
-        for (const auto &info : hals) {
-            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
-                continue;
-            }
-
-            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
-                continue;
-            }
-
-            pids.insert(info.pid);
-        }
-    });
-
-    if (!ret.isOk()) {
-        MYLOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
-    }
-
-    return pids; // whether it was okay or not
-}
-
 const char* DumpTraces(const std::string& traces_path);
 const char* DumpTracesTombstoned(const std::string& traces_dir);
 
@@ -876,18 +799,6 @@
     return nullptr;
 }
 
-static bool IsZygote(int pid) {
-    static const std::string kZygotePrefix = "zygote";
-
-    std::string cmdline;
-    if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
-                                         &cmdline)) {
-        return true;
-    }
-
-    return (cmdline.find(kZygotePrefix) == 0);
-}
-
 const char* DumpTracesTombstoned(const std::string& traces_dir) {
     const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
 
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 352cf0a..94c3102 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -5,6 +5,10 @@
         "-Wall",
         "-Werror",
         "-Wextra",
+
+        "-Wunreachable-code",
+        "-Wunreachable-code-break",
+        "-Wunreachable-code-return",
     ],
     srcs: [
         "CacheItem.cpp",
@@ -15,6 +19,9 @@
         "utils.cpp",
         ":installd_aidl",
     ],
+    header_libs: [
+        "dex2oat_headers",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 0a45ab0..e53a223 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1971,10 +1971,11 @@
     const char* profile_name = getCStr(profileName);
     const char* dm_path = getCStr(dexMetadataPath);
     const char* compilation_reason = getCStr(compilationReason);
+    std::string error_msg;
     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, dm_path, compilation_reason);
-    return res ? error(res, "Failed to dexopt") : ok();
+            downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg);
+    return res ? error(res, error_msg) : ok();
 }
 
 binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 9f1cd45..e1e73c7 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -28,6 +28,8 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <iomanip>
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
@@ -37,6 +39,7 @@
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
+#include <dex2oat_return_codes.h>
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
@@ -44,6 +47,7 @@
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
+#include "dexopt_return_codes.h"
 #include "globals.h"
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
@@ -68,6 +72,7 @@
 static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
 static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
 
+
 // Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
 struct FreeDelete {
   // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
@@ -219,18 +224,19 @@
     }
 }
 
+[[ noreturn ]]
 static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
         bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
         const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
-        int dex_metadata_fd, const char* compilation_reason) {
+        bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
-        return;
+        LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
+                   << MAX_INSTRUCTION_SET_LEN;
+        exit(DexoptReturnCodes::kInstructionSetLength);
     }
 
     // Get the relative path to the input file.
@@ -302,10 +308,11 @@
 
     // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
     const char* dex2oat_bin = "/system/bin/dex2oat";
-    static const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+    constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
     if (is_debug_runtime() || (background_job_compile && is_debuggable_build())) {
-        DCHECK(access(kDex2oatDebugPath, X_OK) == 0);
-        dex2oat_bin = kDex2oatDebugPath;
+        if (access(kDex2oatDebugPath, X_OK) == 0) {
+            dex2oat_bin = kDex2oatDebugPath;
+        }
     }
 
     bool generate_minidebug_info = kEnableMinidebugInfo &&
@@ -431,9 +438,7 @@
 
     // Disable cdex if update input vdex is true since this combination of options is not
     // supported.
-    // Disable cdex for non-background compiles since we don't want to regress app install until
-    // there are enough benefits to justify the tradeoff.
-    const bool disable_cdex = !background_job_compile || (input_vdex_fd == output_vdex_fd);
+    const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
 
     const char* argv[9  // program name, mandatory arguments and the final NULL
                      + (have_dex2oat_isa_variant ? 1 : 0)
@@ -548,7 +553,8 @@
     argv[i] = NULL;
 
     execv(dex2oat_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", dex2oat_bin, strerror(errno));
+    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
+    exit(DexoptReturnCodes::kDex2oatExec);
 }
 
 /*
@@ -600,12 +606,12 @@
 static void SetDex2OatScheduling(bool set_to_bg) {
     if (set_to_bg) {
         if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-            ALOGE("set_sched_policy failed: %s\n", strerror(errno));
-            exit(70);
+            PLOG(ERROR) << "set_sched_policy failed";
+            exit(DexoptReturnCodes::kSetSchedPolicy);
         }
         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
-            ALOGE("setpriority failed: %s\n", strerror(errno));
-            exit(71);
+            PLOG(ERROR) << "setpriority failed";
+            exit(DexoptReturnCodes::kSetPriority);
         }
     }
 }
@@ -705,12 +711,12 @@
 
 static void drop_capabilities(uid_t uid) {
     if (setgid(uid) != 0) {
-        ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
-        exit(64);
+        PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetGid);
     }
     if (setuid(uid) != 0) {
-        ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
-        exit(65);
+        PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetUid);
     }
     // drop capabilities
     struct __user_cap_header_struct capheader;
@@ -719,8 +725,8 @@
     memset(&capdata, 0, sizeof(capdata));
     capheader.version = _LINUX_CAPABILITY_VERSION_3;
     if (capset(&capheader, &capdata[0]) < 0) {
-        ALOGE("capset failed: %s\n", strerror(errno));
-        exit(66);
+        PLOG(ERROR) << "capset failed";
+        exit(DexoptReturnCodes::kCapSet);
     }
 }
 
@@ -730,6 +736,7 @@
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
+[[ noreturn ]]
 static void run_profman(const std::vector<unique_fd>& profile_fds,
                         const unique_fd& reference_profile_fd,
                         const std::vector<unique_fd>* apk_fds,
@@ -773,18 +780,18 @@
     argv[i] = NULL;
 
     execv(profman_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", profman_bin, strerror(errno));
-    exit(68);   /* only get here on exec failure */
+    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
 
-
+[[ noreturn ]]
 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);
 }
 
-
+[[ noreturn ]]
 static void run_profman_copy_and_update(unique_fd&& profile_fd,
                                         unique_fd&& reference_profile_fd,
                                         unique_fd&& apk_fd) {
@@ -819,7 +826,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
         run_profman_merge(profiles_fd, reference_profile_fd);
-        exit(68);   /* only get here on exec failure */
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -892,6 +898,7 @@
     return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
 
+[[ noreturn ]]
 static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
                              const unique_fd& reference_profile_fd,
                              const std::vector<std::string>& dex_locations,
@@ -923,8 +930,8 @@
     argv[i] = NULL;
 
     execv(PROFMAN_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
-    exit(68);   /* only get here on exec failure */
+    PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
 
 bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
@@ -969,7 +976,6 @@
         drop_capabilities(uid);
         run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
                          apk_fds, output_fd);
-        exit(68);   /* only get here on exec failure */
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -1640,10 +1646,17 @@
 // secondary dex files. This return codes are returned by the child process created for
 // analyzing secondary dex files in process_secondary_dex_dexopt.
 
-// The dexoptanalyzer was not invoked because of validation or IO errors.
-static int constexpr SECONDARY_DEX_DEXOPTANALYZER_SKIPPED = 200;
-// The dexoptanalyzer was not invoked because the dex file does not exist anymore.
-static int constexpr SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE = 201;
+enum DexoptAnalyzerSkipCodes {
+  // The dexoptanalyzer was not invoked because of validation or IO errors.
+  // Specific errors are encoded in the name.
+  kSecondaryDexDexoptAnalyzerSkippedValidatePath = 200,
+  kSecondaryDexDexoptAnalyzerSkippedOpenZip = 201,
+  kSecondaryDexDexoptAnalyzerSkippedPrepareDir = 202,
+  kSecondaryDexDexoptAnalyzerSkippedOpenOutput = 203,
+  kSecondaryDexDexoptAnalyzerSkippedFailExec = 204,
+  // The dexoptanalyzer was not invoked because the dex file does not exist anymore.
+  kSecondaryDexDexoptAnalyzerSkippedNoFile = 205,
+};
 
 // Verifies the result of analyzing secondary dex files from process_secondary_dex_dexopt.
 // If the result is valid returns true and sets dexopt_needed_out to a valid value.
@@ -1651,7 +1664,7 @@
 // The result is expected to be either one of SECONDARY_DEX_* codes or a valid exit code
 // of dexoptanalyzer.
 static bool process_secondary_dexoptanalyzer_result(const std::string& dex_path, int result,
-            int* dexopt_needed_out) {
+            int* dexopt_needed_out, std::string* error_msg) {
     // The result values are defined in dexoptanalyzer.
     switch (result) {
         case 0:  // dexoptanalyzer: no_dexopt_needed
@@ -1667,21 +1680,42 @@
         case 2:  // dexoptanalyzer: dex2oat_for_bootimage_oat
         case 3:  // dexoptanalyzer: dex2oat_for_filter_oat
         case 4:  // dexoptanalyzer: dex2oat_for_relocation_oat
-            LOG(ERROR) << "Dexoptnalyzer return the status of an oat file."
-                    << " Expected odex file status for secondary dex " << dex_path
-                    << " : dexoptanalyzer result=" << result;
+            *error_msg = StringPrintf("Dexoptanalyzer return the status of an oat file."
+                                      " Expected odex file status for secondary dex %s"
+                                      " : dexoptanalyzer result=%d",
+                                      dex_path.c_str(),
+                                      result);
             return false;
-        case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE:
+    }
+
+    // Use a second switch for enum switch-case analysis.
+    switch (static_cast<DexoptAnalyzerSkipCodes>(result)) {
+        case kSecondaryDexDexoptAnalyzerSkippedNoFile:
             // If the file does not exist there's no need for dexopt.
             *dexopt_needed_out = NO_DEXOPT_NEEDED;
             return true;
-        case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED:
+
+        case kSecondaryDexDexoptAnalyzerSkippedValidatePath:
+            *error_msg = "Dexoptanalyzer path validation failed";
             return false;
-        default:
-            LOG(ERROR) << "Unexpected result from analyzing secondary dex " << dex_path
-                    << " result=" << result;
+        case kSecondaryDexDexoptAnalyzerSkippedOpenZip:
+            *error_msg = "Dexoptanalyzer open zip failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedPrepareDir:
+            *error_msg = "Dexoptanalyzer dir preparation failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedOpenOutput:
+            *error_msg = "Dexoptanalyzer open output failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedFailExec:
+            *error_msg = "Dexoptanalyzer failed to execute";
             return false;
     }
+
+    *error_msg = StringPrintf("Unexpected result from analyzing secondary dex %s result=%d",
+                              dex_path.c_str(),
+                              result);
+    return false;
 }
 
 enum SecondaryDexAccess {
@@ -1719,10 +1753,10 @@
 // Create the oat file structure for the secondary dex 'dex_path' and assign
 // the individual path component to the 'out_' parameters.
 static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
-        char* out_oat_dir, char* out_oat_isa_dir, char* out_oat_path) {
+        char* out_oat_dir, char* out_oat_isa_dir, char* out_oat_path, std::string* error_msg) {
     size_t dirIndex = dex_path.rfind('/');
     if (dirIndex == std::string::npos) {
-        LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
+        *error_msg = std::string("Unexpected dir structure for dex file ").append(dex_path);
         return false;
     }
     // TODO(calin): we have similar computations in at lest 3 other places
@@ -1734,7 +1768,7 @@
 
     if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
             /*is_secondary_dex*/true, out_oat_path)) {
-        LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
+        *error_msg = std::string("Could not create oat path for secondary dex ").append(dex_path);
         return false;
     }
     return true;
@@ -1742,17 +1776,19 @@
 
 // Validate that the dexopt_flags contain a valid storage flag and convert that to an installd
 // recognized storage flags (FLAG_STORAGE_CE or FLAG_STORAGE_DE).
-static bool validate_dexopt_storage_flags(int dexopt_flags, int* out_storage_flag) {
+static bool validate_dexopt_storage_flags(int dexopt_flags,
+                                          int* out_storage_flag,
+                                          std::string* error_msg) {
     if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
         *out_storage_flag = FLAG_STORAGE_CE;
         if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
-            LOG(ERROR) << "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
+            *error_msg = "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
             return false;
         }
     } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
         *out_storage_flag = FLAG_STORAGE_DE;
     } else {
-        LOG(ERROR) << "Secondary dex storage flag must be set";
+        *error_msg = "Secondary dex storage flag must be set";
         return false;
     }
     return true;
@@ -1768,10 +1804,12 @@
 static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname,
         int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
         const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
-        std::string* oat_dir_out, bool downgrade, const char* class_loader_context) {
+        std::string* oat_dir_out, bool downgrade, const char* class_loader_context,
+        /* out */ std::string* error_msg) {
     LOG(DEBUG) << "Processing secondary dex path " << dex_path;
     int storage_flag;
-    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag)) {
+    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
+        LOG(ERROR) << *error_msg;
         return false;
     }
     // Compute the oat dir as it's not easy to extract it from the child computation.
@@ -1779,8 +1817,8 @@
     char oat_dir[PKG_PATH_MAX];
     char oat_isa_dir[PKG_PATH_MAX];
     if (!create_secondary_dex_oat_layout(
-            dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path)) {
-        LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
+            dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) {
+        LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg;
         return false;
     }
     oat_dir_out->assign(oat_dir);
@@ -1793,7 +1831,7 @@
         // Validate the path structure.
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
         }
 
         // Open the dex file.
@@ -1801,15 +1839,15 @@
         zip_fd.reset(open(dex_path.c_str(), O_RDONLY));
         if (zip_fd.get() < 0) {
             if (errno == ENOENT) {
-                _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE);
+                _exit(kSecondaryDexDexoptAnalyzerSkippedNoFile);
             } else {
-                _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+                _exit(kSecondaryDexDexoptAnalyzerSkippedOpenZip);
             }
         }
 
         // Prepare the oat directories.
         if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedPrepareDir);
         }
 
         // Open the vdex/oat files if any.
@@ -1821,7 +1859,7 @@
                                           true /* is_secondary_dex */,
                                           &oat_file_fd,
                                           &vdex_file_fd)) {
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedOpenOutput);
         }
 
         // Analyze profiles.
@@ -1838,18 +1876,27 @@
                             downgrade,
                             class_loader_context);
         PLOG(ERROR) << "Failed to exec dexoptanalyzer";
-        _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
     /* parent */
     int result = wait_child(pid);
     if (!WIFEXITED(result)) {
-        LOG(ERROR) << "dexoptanalyzer failed for path " << dex_path << ": " << result;
+        *error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x",
+                                  dex_path.c_str(),
+                                  result);
+        LOG(ERROR) << *error_msg;
         return false;
     }
     result = WEXITSTATUS(result);
     // Check that we successfully executed dexoptanalyzer.
-    bool success = process_secondary_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
+    bool success = process_secondary_dexoptanalyzer_result(dex_path,
+                                                           result,
+                                                           dexopt_needed_out,
+                                                           error_msg);
+    if (!success) {
+        LOG(ERROR) << *error_msg;
+    }
 
     LOG(DEBUG) << "Processed secondary dex file " << dex_path << " result=" << result;
 
@@ -1857,7 +1904,7 @@
     // Note that dexoptanalyzer is executed even if force compilation is enabled (because it
     // makes the code simpler; force compilation is only needed during tests).
     if (success &&
-        (result != SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE) &&
+        (result != kSecondaryDexDexoptAnalyzerSkippedNoFile) &&
         ((dexopt_flags & DEXOPT_FORCE) != 0)) {
         *dexopt_needed_out = DEX2OAT_FROM_SCRATCH;
     }
@@ -1870,23 +1917,37 @@
     return success;
 }
 
+static std::string format_dexopt_error(int status, const char* dex_path) {
+  if (WIFEXITED(status)) {
+    int int_code = WEXITSTATUS(status);
+    const char* code_name = get_return_code_name(static_cast<DexoptReturnCodes>(int_code));
+    if (code_name != nullptr) {
+      return StringPrintf("Dex2oat invocation for %s failed: %s", dex_path, code_name);
+    }
+  }
+  return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status);
+}
+
 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,
-        const char* dex_metadata_path, const char* compilation_reason) {
+        const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
-    if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
-        LOG_FATAL("dexopt flags contains unknown fields\n");
-    }
+    CHECK(error_msg != nullptr);
+    CHECK_EQ(dexopt_flags & ~DEXOPT_MASK, 0)
+        << "dexopt flags contains unknown fields: " << dexopt_flags;
 
     if (!validate_dex_path_size(dex_path)) {
+        *error_msg = StringPrintf("Failed to validate %s", dex_path);
         return -1;
     }
 
     if (class_loader_context != nullptr && strlen(class_loader_context) > PKG_PATH_MAX) {
-        LOG(ERROR) << "Class loader context exceeds the allowed size: " << class_loader_context;
+        *error_msg = StringPrintf("Class loader context exceeds the allowed size: %s",
+                                  class_loader_context);
+        LOG(ERROR) << *error_msg;
         return -1;
     }
 
@@ -1897,18 +1958,22 @@
     bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
     bool background_job_compile = (dexopt_flags & DEXOPT_IDLE_BACKGROUND_JOB) != 0;
     bool enable_hidden_api_checks = (dexopt_flags & DEXOPT_ENABLE_HIDDEN_API_CHECKS) != 0;
+    bool generate_compact_dex = (dexopt_flags & DEXOPT_GENERATE_COMPACT_DEX) != 0;
 
     // Check if we're dealing with a secondary dex file and if we need to compile it.
     std::string oat_dir_str;
     if (is_secondary_dex) {
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                 instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                downgrade, class_loader_context)) {
+                downgrade, class_loader_context, error_msg)) {
             oat_dir = oat_dir_str.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
                 return 0;  // Nothing to do, report success.
             }
         } else {
+            if (error_msg->empty()) {  // TODO: Make this a CHECK.
+                *error_msg = "Failed processing secondary.";
+            }
             return -1;  // We had an error, logged in the process method.
         }
     } else {
@@ -1921,7 +1986,8 @@
     // Open the input file.
     unique_fd input_fd(open(dex_path, O_RDONLY, 0));
     if (input_fd.get() < 0) {
-        ALOGE("installd cannot open '%s' for input during dexopt\n", dex_path);
+        *error_msg = StringPrintf("installd cannot open '%s' for input during dexopt", dex_path);
+        LOG(ERROR) << *error_msg;
         return -1;
     }
 
@@ -1930,6 +1996,7 @@
     Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
             instruction_set, is_secondary_dex, out_oat_path);
     if (out_oat_fd.get() < 0) {
+        *error_msg = "Could not open out oat file.";
         return -1;
     }
 
@@ -1938,6 +2005,7 @@
     Dex2oatFileWrapper out_vdex_fd;
     if (!open_vdex_files_for_dex2oat(dex_path, out_oat_path, dexopt_needed, instruction_set,
             is_public, uid, is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
+        *error_msg = "Could not open vdex files.";
         return -1;
     }
 
@@ -1949,7 +2017,8 @@
     if (is_secondary_dex) {
         if (selinux_android_restorecon_pkgdir(oat_dir, se_info, uid,
                 SELINUX_ANDROID_RESTORECON_RECURSE)) {
-            LOG(ERROR) << "Failed to restorecon " << oat_dir;
+            *error_msg = std::string("Failed to restorecon ").append(oat_dir);
+            LOG(ERROR) << *error_msg;
             return -1;
         }
     }
@@ -1973,7 +2042,7 @@
         }
     }
 
-    ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
+    LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
     pid_t pid = fork();
     if (pid == 0) {
@@ -1982,8 +2051,8 @@
 
         SetDex2OatScheduling(boot_complete);
         if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
-            ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno));
-            _exit(67);
+            PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
+            _exit(DexoptReturnCodes::kFlock);
         }
 
         run_dex2oat(input_fd.get(),
@@ -2003,15 +2072,17 @@
                     class_loader_context,
                     target_sdk_version,
                     enable_hidden_api_checks,
+                    generate_compact_dex,
                     dex_metadata_fd.get(),
                     compilation_reason);
-        _exit(68);   /* only get here on exec failure */
     } else {
         int res = wait_child(pid);
         if (res == 0) {
-            ALOGV("DexInv: --- END '%s' (success) ---\n", dex_path);
+            LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
         } else {
-            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", dex_path, res);
+            LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x"
+                         << std::hex << std::setw(4) << res << ", process failed";
+            *error_msg = format_dexopt_error(res, dex_path);
             return res;
         }
     }
@@ -2119,9 +2190,10 @@
         char oat_isa_dir[PKG_PATH_MAX];
         bool result = true;
         for (size_t i = 0; i < isas.size(); i++) {
+            std::string error_msg;
             if (!create_secondary_dex_oat_layout(
-                    dex_path,isas[i], oat_dir, oat_isa_dir, oat_path)) {
-                LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
+                    dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
+                LOG(ERROR) << error_msg;
                 _exit(kReconcileSecondaryDexValidationError);
             }
 
@@ -2222,7 +2294,7 @@
 
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashValidatePath);
         }
 
         unique_fd fd(TEMP_FAILURE_RETRY(open(dex_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
@@ -2232,7 +2304,7 @@
                 _exit(0);
             }
             PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashOpenPath);
         }
 
         SHA256_CTX ctx;
@@ -2245,7 +2317,7 @@
                 break;
             } else if (bytes_read == -1) {
                 PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
-                _exit(1);
+                _exit(DexoptReturnCodes::kHashReadDex);
             }
 
             SHA256_Update(&ctx, buffer.data(), bytes_read);
@@ -2254,7 +2326,7 @@
         std::array<uint8_t, SHA256_DIGEST_LENGTH> hash;
         SHA256_Final(hash.data(), &ctx);
         if (!WriteFully(pipe_write, hash.data(), hash.size())) {
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashWrite);
         }
 
         _exit(0);
@@ -2572,7 +2644,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(app_shared_gid);
         run_profman_merge(profiles_fd, snapshot_fd, &apk_fds);
-        exit(42);   /* only get here on exec failure */
     }
 
     /* parent */
@@ -2650,7 +2721,6 @@
             drop_capabilities(AID_SYSTEM);
 
             run_profman_merge(profiles_fd, snapshot_fd, &apk_fds);
-            exit(42);   /* only get here on exec failure */
         }
 
         /* parent */
@@ -2714,7 +2784,6 @@
         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 */
     }
 
     /* parent */
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 62f9467..bb6fab3 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -106,7 +106,7 @@
         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,
-        const char* dexMetadataPath, const char* compilation_reason);
+        const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg);
 
 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/dexopt_return_codes.h b/cmds/installd/dexopt_return_codes.h
new file mode 100644
index 0000000..bbecfa4
--- /dev/null
+++ b/cmds/installd/dexopt_return_codes.h
@@ -0,0 +1,119 @@
+/*
+ * 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 <dex2oat_return_codes.h>
+
+namespace android {
+namespace installd {
+
+// Constants for exit codes that installd code emits. These are failure situations before calling
+// any tools, e.g., in validation, and must not overlap with the exit codes of tools, so they
+// can be distinguished.
+enum DexoptReturnCodes : int {
+    kSetGid = 64,
+    kSetUid = 65,
+    kCapSet = 66,
+    kFlock = 67,
+    kProfmanExec = 68,
+    kSetSchedPolicy = 70,
+    kSetPriority = 71,
+    kDex2oatExec = 72,
+    kInstructionSetLength = 73,
+    kHashValidatePath = 74,
+    kHashOpenPath = 75,
+    kHashReadDex = 76,
+    kHashWrite = 77,
+};
+
+inline const char* get_installd_return_code_name(DexoptReturnCodes code) {
+    switch (code) {
+        case kSetGid:
+            return "setgid";
+        case kSetUid:
+            return "setuid";
+        case kCapSet:
+            return "capset";
+        case kFlock:
+            return "flock";
+        case kProfmanExec:
+            return "exec(profman)";
+        case kSetSchedPolicy:
+            return "setschedpolicy";
+        case kSetPriority:
+            return "setpriority";
+        case kDex2oatExec:
+            return "exec(dex2oat)";
+        case kInstructionSetLength:
+            return "instruction-set-length";
+        case kHashValidatePath:
+            return "hash(validate-path)";
+        case kHashOpenPath:
+            return "hash(open-path)";
+        case kHashReadDex:
+            return "hash(read-dex)";
+        case kHashWrite:
+            return "hash(write)";
+    }
+    return nullptr;
+}
+
+inline const char* get_dex2oat_return_code_name(art::dex2oat::ReturnCode code) {
+    switch (code) {
+        case art::dex2oat::ReturnCode::kNoFailure:
+            return "dex2oat success";
+        case art::dex2oat::ReturnCode::kOther:
+            return "unspecified dex2oat error";
+        case art::dex2oat::ReturnCode::kCreateRuntime:
+            return "dex2oat failed to create a runtime";
+    }
+    return nullptr;
+}
+
+// Get some slightly descriptive string for the return code. Handles both DexoptReturnCodes (local
+// exit codes) as well as art::dex2oat::ReturnCode.
+inline const char* get_return_code_name(int code) {
+    // Try to enforce non-overlap (see comment on DexoptReturnCodes)
+    // TODO: How could switch-case checks be used to enforce completeness?
+    switch (code) {
+        case kSetGid:
+        case kSetUid:
+        case kCapSet:
+        case kFlock:
+        case kProfmanExec:
+        case kSetSchedPolicy:
+        case kSetPriority:
+        case kDex2oatExec:
+        case kInstructionSetLength:
+        case kHashValidatePath:
+        case kHashOpenPath:
+        case kHashReadDex:
+        case kHashWrite:
+            break;
+        case static_cast<int>(art::dex2oat::ReturnCode::kNoFailure):
+        case static_cast<int>(art::dex2oat::ReturnCode::kOther):
+        case static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime):
+            break;
+    }
+    const char* value = get_installd_return_code_name(static_cast<DexoptReturnCodes>(code));
+    if (value != nullptr) {
+        return value;
+    }
+    value = get_dex2oat_return_code_name(static_cast<art::dex2oat::ReturnCode>(code));
+    return value;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 06c83e4..26aa443 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -53,6 +53,7 @@
 // controls whether extra debugging flags can be used (taking more compile time.)
 constexpr int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
 constexpr int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
+constexpr int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11;
 
 /* all known values for dexopt flags */
 constexpr int DEXOPT_MASK =
@@ -64,7 +65,9 @@
     | DEXOPT_FORCE
     | DEXOPT_STORAGE_CE
     | DEXOPT_STORAGE_DE
-    | DEXOPT_ENABLE_HIDDEN_API_CHECKS;
+    | DEXOPT_IDLE_BACKGROUND_JOB
+    | DEXOPT_ENABLE_HIDDEN_API_CHECKS
+    | DEXOPT_GENERATE_COMPACT_DEX;
 
 // NOTE: keep in sync with StorageManager
 constexpr int FLAG_STORAGE_DE = 1 << 0;
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 899285a..58355f9 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -81,8 +81,10 @@
 static_assert(DEXOPT_STORAGE_DE     == 1 << 8, "DEXOPT_STORAGE_DE unexpected.");
 static_assert(DEXOPT_ENABLE_HIDDEN_API_CHECKS == 1 << 10,
         "DEXOPT_ENABLE_HIDDEN_API_CHECKS unexpected");
+static_assert(DEXOPT_GENERATE_COMPACT_DEX == 1 << 11, "DEXOPT_GENERATE_COMPACT_DEX unexpected");
 
-static_assert(DEXOPT_MASK           == 0x5fe, "DEXOPT_MASK unexpected.");
+static_assert(DEXOPT_MASK           == (0xdfe | DEXOPT_IDLE_BACKGROUND_JOB),
+              "DEXOPT_MASK unexpected.");
 
 
 
@@ -568,6 +570,7 @@
     // Run dexopt with the parameters of parameters_.
     // TODO(calin): embed the profile name in the parameters.
     int Dexopt() {
+        std::string dummy;
         return dexopt(parameters_.apk_path,
                       parameters_.uid,
                       parameters_.pkgName,
@@ -583,7 +586,8 @@
                       parameters_.target_sdk_version,
                       parameters_.profile_name,
                       parameters_.dex_metadata_path,
-                      parameters_.compilation_reason);
+                      parameters_.compilation_reason,
+                      &dummy);
     }
 
     int RunPreopt() {
diff --git a/cmds/installd/otapreopt_parameters.cpp b/cmds/installd/otapreopt_parameters.cpp
index 802d5d7..d56aec9 100644
--- a/cmds/installd/otapreopt_parameters.cpp
+++ b/cmds/installd/otapreopt_parameters.cpp
@@ -133,6 +133,9 @@
 
     // The compilation reason is ab-ota (match the system property pm.dexopt.ab-ota)
     compilation_reason = "ab-ota";
+
+    // Flag is enabled by default for A/B otas.
+    dexopt_flags = DEXOPT_GENERATE_COMPACT_DEX;
 }
 
 bool OTAPreoptParameters::ReadArgumentsV1(const char** argv) {
@@ -146,6 +149,8 @@
         return false;
     }
 
+    SetDefaultsForPostV1Arguments();
+
     size_t param_index = 0;
     for (;; ++param_index) {
         const char* param = argv[3 + param_index];
@@ -193,8 +198,9 @@
                 constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
                 constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
                 constexpr int OLD_DEXOPT_OTA            = 1 << 6;
+                static_assert(DEXOPT_GENERATE_COMPACT_DEX > OLD_DEXOPT_OTA, "must not overlap");
                 int input = atoi(param);
-                dexopt_flags =
+                dexopt_flags |=
                         ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
                         ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
                         ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
@@ -226,8 +232,6 @@
         return false;
     }
 
-    SetDefaultsForPostV1Arguments();
-
     return true;
 }
 
@@ -239,7 +243,9 @@
         case 4: num_args_expected = 13; break;
         case 5: num_args_expected = 14; break;
         case 6: num_args_expected = 15; break;
-        case 7: num_args_expected = 16; break;
+        case 7:
+        // Version 8 adds a new dexopt flag: DEXOPT_GENERATE_COMPACT_DEX
+        case 8: num_args_expected = 16; break;
         default:
             LOG(ERROR) << "Don't know how to read arguments for version " << version;
             return false;
@@ -302,6 +308,10 @@
 
             case 6:
                 dexopt_flags = atoi(param);
+                // Add CompactDex generation flag for versions less than 8 since it wasn't passed
+                // from the package manager. Only conditionally set the flag here so that it can
+                // be fully controlled by the package manager.
+                dexopt_flags |= (version < 8) ? DEXOPT_GENERATE_COMPACT_DEX : 0u;
                 break;
 
             case 7:
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 7438d3d..739f33f 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -1,6 +1,7 @@
 // Build the unit tests for installd
 cc_test {
     name: "installd_utils_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_utils_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -18,6 +19,7 @@
 
 cc_test {
     name: "installd_cache_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_cache_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -39,6 +41,7 @@
 
 cc_test {
     name: "installd_service_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_service_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -60,6 +63,7 @@
 
 cc_test {
     name: "installd_dexopt_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_dexopt_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -81,6 +85,7 @@
 
 cc_test {
     name: "installd_otapreopt_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_otapreopt_test.cpp"],
     cflags: ["-Wall", "-Werror"],
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index d640558..668e604 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -249,7 +249,7 @@
 
     void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
             bool should_binder_call_succeed, bool should_dex_be_compiled = true,
-            int32_t uid = -1) {
+            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1) {
         if (uid == -1) {
             uid = kTestAppUid;
         }
@@ -290,6 +290,9 @@
         ASSERT_EQ(expected_access, access(odex.c_str(), R_OK));
         ASSERT_EQ(expected_access, access(vdex.c_str(), R_OK));
         ASSERT_EQ(-1, access(art.c_str(), R_OK));  // empty profiles do not generate an image.
+        if (binder_result != nullptr) {
+            *binder_result = result;
+        }
     }
 
     void reconcile_secondary_dex(const std::string& path, int32_t storage_flag,
@@ -335,10 +338,18 @@
                              const char* oat_dir,
                              int32_t uid,
                              int32_t dexopt_needed,
+                             binder::Status* binder_result = nullptr,
                              const char* dm_path = nullptr,
                              bool downgrade = false) {
-        return CompilePrimaryDex(
-                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, true);
+        CompilePrimaryDex(compiler_filter,
+                          dex_flags,
+                          oat_dir,
+                          uid,
+                          dexopt_needed,
+                          dm_path,
+                          downgrade,
+                          true,
+                          binder_result);
     }
 
     void CompilePrimaryDexFail(std::string compiler_filter,
@@ -346,10 +357,18 @@
                                const char* oat_dir,
                                int32_t uid,
                                int32_t dexopt_needed,
+                               binder::Status* binder_result = nullptr,
                                const char* dm_path = nullptr,
                                bool downgrade = false) {
-        return CompilePrimaryDex(
-                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, false);
+        CompilePrimaryDex(compiler_filter,
+                          dex_flags,
+                          oat_dir,
+                          uid,
+                          dexopt_needed,
+                          dm_path,
+                          downgrade,
+                          false,
+                          binder_result);
     }
 
     void CompilePrimaryDex(std::string compiler_filter,
@@ -359,7 +378,8 @@
                            int32_t dexopt_needed,
                            const char* dm_path,
                            bool downgrade,
-                           bool should_binder_call_succeed) {
+                           bool should_binder_call_succeed,
+                           /*out */ binder::Status* binder_result) {
         std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
         std::unique_ptr<std::string> out_path(
                 oat_dir == nullptr ? nullptr : new std::string(oat_dir));
@@ -400,6 +420,9 @@
         ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
 
         if (!should_binder_call_succeed) {
+            if (binder_result != nullptr) {
+                *binder_result = result;
+            }
             return;
         }
         // Check the access to the compiler output.
@@ -417,6 +440,9 @@
         if (compiler_filter == "speed-profile") {
             CheckFileAccess(art, kSystemUid, uid, mode);
         }
+        if (binder_result != nullptr) {
+            *binder_result = result;
+        }
     }
 
     std::string GetPrimaryDexArtifact(const char* oat_dir,
@@ -462,26 +488,36 @@
 TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
     LOG(INFO) << "DexoptSecondaryDoesNotExist";
     // If the file validates but does not exist we do not treat it as an error.
+    binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_ + "not.there", DEXOPT_STORAGE_CE,
-        /*binder_ok*/ true,  /*compile_ok*/ false);
+        /*binder_ok*/ true,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(), "No error");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryStorageValidationError) {
     LOG(INFO) << "DexoptSecondaryStorageValidationError";
+    binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
-        /*binder_ok*/ false,  /*compile_ok*/ false);
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
     LOG(INFO) << "DexoptSecondaryAppOwnershipValidationError";
+    binder::Status status;
     CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
-        /*binder_ok*/ false,  /*compile_ok*/ false);
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
     LOG(INFO) << "DexoptSecondaryAcessViaDifferentUidError";
+    binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
-        /*binder_ok*/ false,  /*compile_ok*/ false, kSystemUid);
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status, kSystemUid);
+    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Dexoptanalyzer open zip failed'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryPublic) {
@@ -495,11 +531,16 @@
 
 TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) {
     LOG(INFO) << "DexoptPrimaryFailedInvalidFilter";
+    binder::Status status;
     CompilePrimaryDexFail("awesome-filter",
                           DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC,
                           app_oat_dir_.c_str(),
                           kTestAppGid,
-                          DEX2OAT_FROM_SCRATCH);
+                          DEX2OAT_FROM_SCRATCH,
+                          &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): \'256: Dex2oat invocation for "
+                 "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {
diff --git a/cmds/installd/tests/installd_otapreopt_test.cpp b/cmds/installd/tests/installd_otapreopt_test.cpp
index 82bf932..63426cb 100644
--- a/cmds/installd/tests/installd_otapreopt_test.cpp
+++ b/cmds/installd/tests/installd_otapreopt_test.cpp
@@ -20,6 +20,7 @@
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
 
+#include "installd_constants.h"
 #include "otapreopt_parameters.h"
 
 namespace android {
@@ -61,7 +62,7 @@
         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++]));
+        const int 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++]));
@@ -78,7 +79,7 @@
         if (version > 3) {
             ASSERT_EQ(params.target_sdk_version, atoi(args[i++]));
         } else {
-             ASSERT_EQ(params.target_sdk_version, 0);
+            ASSERT_EQ(params.target_sdk_version, 0);
         }
         if (version > 4) {
             ASSERT_STREQ(params.profile_name, ParseNull(args[i++]));
@@ -95,6 +96,11 @@
         } else {
             ASSERT_STREQ(params.compilation_reason, "ab-ota");
         }
+        if (version > 7) {
+            ASSERT_EQ(params.dexopt_flags, dexopt_flags);
+        } else {
+            ASSERT_EQ(params.dexopt_flags, dexopt_flags | DEXOPT_GENERATE_COMPACT_DEX);
+        }
     }
 
     const char* getVersionCStr(uint32_t version) {
@@ -106,6 +112,7 @@
             case 5: return "5";
             case 6: return "6";
             case 7: return "7";
+            case 8: return "8";
         }
         return nullptr;
     }
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index dd8812d..0952db6 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -59,8 +59,8 @@
 
     auto pair = splitFirst(mInterfaceName, '/');
 
-    FQName fqName(pair.first);
-    if (!fqName.isValid() || fqName.isIdentifier() || !fqName.isFullyQualified()) {
+    FQName fqName;
+    if (!FQName::parse(pair.first, &fqName) || fqName.isIdentifier() || !fqName.isFullyQualified()) {
         mLshal.err() << "Invalid fully-qualified name '" << pair.first << "'\n\n";
         return USAGE;
     }
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index b9e0139..5545966 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -252,16 +252,16 @@
     // use a double for loop here because lshal doesn't care about efficiency.
     for (TableEntry &packageEntry : mImplementationsTable) {
         std::string packageName = packageEntry.interfaceName;
-        FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
-        if (!fqPackageName.isValid()) {
+        FQName fqPackageName;
+        if (!FQName::parse(packageName.substr(0, packageName.find("::")), &fqPackageName)) {
             continue;
         }
         for (TableEntry &interfaceEntry : mPassthroughRefTable) {
             if (interfaceEntry.arch != ARCH_UNKNOWN) {
                 continue;
             }
-            FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
-            if (!interfaceName.isValid()) {
+            FQName interfaceName;
+            if (!FQName::parse(splitFirst(interfaceEntry.interfaceName, '/').first, &interfaceName)) {
                 continue;
             }
             if (interfaceName.getPackageAndVersion() == fqPackageName) {
@@ -308,10 +308,10 @@
                 // Quick hack to work around *'s
                 replaceAll(&fqInstanceName, '*', 'D');
             }
-            auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
-            FQName fqName(splittedFqInstanceName.first);
-            if (!fqName.isValid()) {
-                err() << "Warning: '" << splittedFqInstanceName.first
+            auto splitFqInstanceName = splitFirst(fqInstanceName, '/');
+            FQName fqName;
+            if (!FQName::parse(splitFqInstanceName.first, &fqName)) {
+                err() << "Warning: '" << splitFqInstanceName.first
                      << "' is not a valid FQName." << std::endl;
                 continue;
             }
@@ -335,7 +335,7 @@
             std::string interfaceName =
                     &table == &mImplementationsTable ? "" : fqName.name();
             std::string instanceName =
-                    &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
+                    &table == &mImplementationsTable ? "" : splitFqInstanceName.second;
 
             vintf::Version version{fqName.getPackageMajorVersion(),
                                    fqName.getPackageMinorVersion()};
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index d7c3730..e2ab71a 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -36,9 +36,6 @@
     <!-- basic system services -->
     <feature name="android.software.home_screen" />
 
-    <!-- device administration -->
-    <feature name="android.software.device_admin" />
-
     <!-- input management and third-party input method editors -->
     <feature name="android.software.input_methods" />
 
diff --git a/headers/media_plugin/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h
index 0a51952..033c8ce 100644
--- a/headers/media_plugin/media/cas/DescramblerAPI.h
+++ b/headers/media_plugin/media/cas/DescramblerAPI.h
@@ -48,6 +48,10 @@
         kScrambling_Reserved    = 1,
         kScrambling_EvenKey     = 2,
         kScrambling_OddKey      = 3,
+        kScrambling_Mask_Key    = 0x3,
+
+        // Hint that the descrambling request is for a PES header only
+        kScrambling_Flag_PesHeader = (1 << 31),
     };
 
     struct SubSample {
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 5a029d0..c2bf97e 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -85,6 +85,7 @@
     OMX_IndexParamMaxFrameDurationForBitrateControl,/**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexParamVideoVp9,                         /**< reference: OMX_VIDEO_PARAM_VP9TYPE */
     OMX_IndexParamVideoAndroidVp9Encoder,           /**< reference: OMX_VIDEO_PARAM_ANDROID_VP9ENCODERTYPE */
+    OMX_IndexParamVideoAndroidImageGrid,            /**< reference: OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE */
     OMX_IndexExtVideoEndUnused,
 
     /* Image & Video common configurations */
diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
index dc5cdab..9fd2fd2 100644
--- a/headers/media_plugin/media/openmax/OMX_Video.h
+++ b/headers/media_plugin/media/openmax/OMX_Video.h
@@ -89,6 +89,7 @@
     OMX_VIDEO_CodingVP9,        /**< Google VP9 */
     OMX_VIDEO_CodingHEVC,       /**< ITU H.265/HEVC */
     OMX_VIDEO_CodingDolbyVision,/**< Dolby Vision */
+    OMX_VIDEO_CodingImageHEIC,  /**< HEIF image encoded with HEVC */
     OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_VIDEO_CodingMax = 0x7FFFFFFF
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index c102564..4b90765 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -213,6 +213,7 @@
     OMX_VIDEO_HEVCProfileUnknown      = 0x0,
     OMX_VIDEO_HEVCProfileMain         = 0x1,
     OMX_VIDEO_HEVCProfileMain10       = 0x2,
+    OMX_VIDEO_HEVCProfileMainStill    = 0x4,
     // Main10 profile with HDR SEI support.
     OMX_VIDEO_HEVCProfileMain10HDR10  = 0x1000,
     OMX_VIDEO_HEVCProfileMax          = 0x7FFFFFFF
@@ -421,6 +422,48 @@
     OMX_U32 nBitrateRatios[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
 } OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE;
 
+/**
+ * Android specific param for specifying image grid layout information for image encoding
+ * use cases, corresponding to index OMX_IndexParamVideoAndroidImageGrid.
+ *
+ * OMX_VIDEO_CodingImageHEIC encoders must handle this param type. When this param is set
+ * on the component with bEnabled set to true, nGrid* indicates the desired grid config
+ * by the client. The component can use this as a heuristic, but is free to choose any
+ * suitable grid configs, and the client shall always get the actual from the component
+ * after the param is set. Encoder will receive each input image in full, and shall encode
+ * it into tiles in row-major, top-row first, left-to-right order, and send each encoded
+ * tile in a separate output buffer. All output buffers for the same input buffer shall
+ * carry the same timestamp as the input buffer. If the input buffer is marked EOS,
+ * the EOS should only appear on the last output buffer for that input buffer.
+ *
+ * OMX_VIDEO_CodingHEVC encoders might also receive this param when it's used for image
+ * encoding, although in this case the param only serves as a hint. The encoder will
+ * receive the input image tiles in row-major, top-row first, left-to-right order.
+ * The grid config can be used for quality control, or optimizations.
+ *
+ * If this param is not set, the component shall assume that grid option is disabled.
+ *
+ *  nSize                      : Size of the structure in bytes
+ *  nVersion                   : OMX specification version information
+ *  nPortIndex                 : Port that this structure applies to (output port for encoders)
+ *  bEnabled                   : Whether grid is enabled. If true, nGrid* specifies the grid
+ *                               config; otherwise nGrid* shall be ignored.
+ *  nGridWidth                 : Width of each tile.
+ *  nGridHeight                : Height of each tile.
+ *  nGridRows                  : Number of rows in the grid.
+ *  nGridCols                  : Number of cols in the grid.
+ */
+typedef struct OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bEnabled;
+    OMX_U32 nGridWidth;
+    OMX_U32 nGridHeight;
+    OMX_U32 nGridRows;
+    OMX_U32 nGridCols;
+} OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index f3b86ae..62c8987 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -100,11 +100,12 @@
             : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
-int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) {
+int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+        bool startIfModeDefault) {
     sp<IAppOpsService> service = getService();
     return service != NULL
-            ? service->startOperation(getToken(service), op, uid, callingPackage)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            ? service->startOperation(getToken(service), op, uid, callingPackage,
+                    startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 638ae5c..9c76350 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -61,13 +61,14 @@
     }
 
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-                const String16& packageName) {
+                const String16& packageName, bool startIfModeDefault) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeStrongBinder(token);
         data.writeInt32(code);
         data.writeInt32(uid);
         data.writeString16(packageName);
+        data.writeInt32(startIfModeDefault ? 1 : 0);
         remote()->transact(START_OPERATION_TRANSACTION, data, &reply);
         // fail on exception
         if (reply.readExceptionCode() != 0) return MODE_ERRORED;
@@ -159,7 +160,8 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            int32_t res = startOperation(token, code, uid, packageName);
+            bool startIfModeDefault = data.readInt32() == 1;
+            int32_t res = startOperation(token, code, uid, packageName, startIfModeDefault);
             reply->writeNoException();
             reply->writeInt32(res);
             return NO_ERROR;
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 4212776..a44d270 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -99,7 +99,8 @@
 
     int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
-    int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage);
+    int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+            bool startIfModeDefault);
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index dc18045..ecba5d6 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -33,7 +33,7 @@
     virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName) = 0;
+            const String16& packageName, bool startIfModeDefault) = 0;
     virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
             const String16& packageName) = 0;
     virtual void startWatchingMode(int32_t op, const String16& packageName,
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
new file mode 100644
index 0000000..3412e14
--- /dev/null
+++ b/libs/dumputils/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "libdumputils",
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+
+    srcs: ["dump_utils.cpp"],
+
+    cflags: ["-Wall", "-Werror"],
+
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
new file mode 100644
index 0000000..0fd2b81
--- /dev/null
+++ b/libs/dumputils/dump_utils.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 <set>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <dumputils/dump_utils.h>
+#include <log/log.h>
+
+/* list of native processes to include in the native dumps */
+// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
+static const char* native_processes_to_dump[] = {
+        "/system/bin/audioserver",
+        "/system/bin/cameraserver",
+        "/system/bin/drmserver",
+        "/system/bin/mediadrmserver",
+        "/system/bin/mediaextractor", // media.extractor
+        "/system/bin/mediametrics", // media.metrics
+        "/system/bin/mediaserver",
+        "/system/bin/sdcard",
+        "/system/bin/statsd",
+        "/system/bin/surfaceflinger",
+        "/system/bin/vehicle_network_service",
+        "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
+        NULL,
+};
+
+/* list of hal interface to dump containing process during native dumps */
+static const char* hal_interfaces_to_dump[] {
+        "android.hardware.audio@2.0::IDevicesFactory",
+        "android.hardware.bluetooth@1.0::IBluetoothHci",
+        "android.hardware.camera.provider@2.4::ICameraProvider",
+        "android.hardware.graphics.composer@2.1::IComposer",
+        "android.hardware.media.omx@1.0::IOmx",
+        "android.hardware.sensors@1.0::ISensors",
+        "android.hardware.vr@1.0::IVr",
+        NULL,
+};
+
+bool should_dump_hal_interface(const char* interface) {
+    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+        if (!strcmp(*i, interface)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool should_dump_native_traces(const char* path) {
+    for (const char** p = native_processes_to_dump; *p; p++) {
+        if (!strcmp(*p, path)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+std::set<int> get_interesting_hal_pids() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    using android::sp;
+    using android::hardware::Return;
+
+    sp<IServiceManager> manager = IServiceManager::getService();
+    std::set<int> pids;
+
+    Return<void> ret = manager->debugDump([&](auto& hals) {
+        for (const auto &info : hals) {
+            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+                continue;
+            }
+
+            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
+                continue;
+            }
+
+            pids.insert(info.pid);
+        }
+    });
+
+    if (!ret.isOk()) {
+        ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
+    }
+
+    return pids; // whether it was okay or not
+}
+
+bool IsZygote(int pid) {
+    static const std::string kZygotePrefix = "zygote";
+
+    std::string cmdline;
+    if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
+                                         &cmdline)) {
+        return true;
+    }
+
+    return (cmdline.find(kZygotePrefix) == 0);
+}
diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h
new file mode 100644
index 0000000..25f7127
--- /dev/null
+++ b/libs/dumputils/include/dumputils/dump_utils.h
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DUMPUTILS_H_
+#define DUMPUTILS_H_
+
+#include <set>
+
+bool should_dump_native_traces(const char* path);
+
+std::set<int> get_interesting_hal_pids();
+
+bool IsZygote(int pid);
+
+#endif  // DUMPUTILS_H_
diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp
index 299bdfa..b715e43 100644
--- a/libs/gui/HdrMetadata.cpp
+++ b/libs/gui/HdrMetadata.cpp
@@ -66,4 +66,32 @@
     return NO_ERROR;
 }
 
+bool HdrMetadata::operator==(const HdrMetadata& rhs) const {
+    if (validTypes != rhs.validTypes) return false;
+
+    if ((validTypes & SMPTE2086) == SMPTE2086) {
+        if (smpte2086.displayPrimaryRed.x != rhs.smpte2086.displayPrimaryRed.x ||
+            smpte2086.displayPrimaryRed.y != rhs.smpte2086.displayPrimaryRed.y ||
+            smpte2086.displayPrimaryGreen.x != rhs.smpte2086.displayPrimaryGreen.x ||
+            smpte2086.displayPrimaryGreen.y != rhs.smpte2086.displayPrimaryGreen.y ||
+            smpte2086.displayPrimaryBlue.x != rhs.smpte2086.displayPrimaryBlue.x ||
+            smpte2086.displayPrimaryBlue.y != rhs.smpte2086.displayPrimaryBlue.y ||
+            smpte2086.whitePoint.x != rhs.smpte2086.whitePoint.x ||
+            smpte2086.whitePoint.y != rhs.smpte2086.whitePoint.y ||
+            smpte2086.maxLuminance != rhs.smpte2086.maxLuminance ||
+            smpte2086.minLuminance != rhs.smpte2086.minLuminance) {
+            return false;
+        }
+    }
+
+    if ((validTypes & CTA861_3) == CTA861_3) {
+        if (cta8613.maxFrameAverageLightLevel != rhs.cta8613.maxFrameAverageLightLevel ||
+            cta8613.maxContentLightLevel != rhs.cta8613.maxContentLightLevel) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 } // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b7773c4..92a24ad 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -105,12 +105,11 @@
 }
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
-    for (auto const& state : other.mComposerStates) {
-        ssize_t index = mComposerStates.indexOf(state);
-        if (index < 0) {
-            mComposerStates.add(state);
+    for (auto const& kv : other.mComposerStates) {
+        if (mComposerStates.count(kv.first) == 0) {
+            mComposerStates[kv.first] = kv.second;
         } else {
-            mComposerStates.editItemAt(static_cast<size_t>(index)).state.merge(state.state);
+            mComposerStates[kv.first].state.merge(kv.second.state);
         }
     }
     other.mComposerStates.clear();
@@ -141,7 +140,10 @@
 
     mForceSynchronous |= synchronous;
 
-    composerStates = mComposerStates;
+    for (auto const& kv : mComposerStates){
+        composerStates.add(kv.second);
+    }
+
     mComposerStates.clear();
 
     displayStates = mDisplayStates;
@@ -182,18 +184,15 @@
 }
 
 layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
-    ComposerState s;
-    s.client = sc->getClient()->mClient;
-    s.state.surface = sc->getHandle();
-
-    ssize_t index = mComposerStates.indexOf(s);
-    if (index < 0) {
+    if (mComposerStates.count(sc) == 0) {
         // we don't have it, add an initialized layer_state to our list
-        index = mComposerStates.add(s);
+        ComposerState s;
+        s.client = sc->getClient()->mClient;
+        s.state.surface = sc->getHandle();
+        mComposerStates[sc] = s;
     }
 
-    ComposerState* const out = mComposerStates.editArray();
-    return &(out[index].state);
+    return &(mComposerStates[sc].state);
 }
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
index cd01952..9800602 100644
--- a/libs/gui/include/gui/HdrMetadata.h
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -38,6 +38,8 @@
     size_t getFlattenedSize() const;
     status_t flatten(void* buffer, size_t size) const;
     status_t unflatten(void const* buffer, size_t size);
+
+    bool operator==(const HdrMetadata& rhs) const;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e5156c6..3fe6635 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <unordered_map>
 
 #include <binder/IBinder.h>
 
@@ -127,8 +128,14 @@
 
     static status_t injectVSync(nsecs_t when);
 
+    struct SCHash {
+        std::size_t operator()(const sp<SurfaceControl>& sc) const {
+            return std::hash<SurfaceControl *>{}(sc.get());
+        }
+    };
+
     class Transaction {
-        SortedVector<ComposerState> mComposerStates;
+        std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
         SortedVector<DisplayState > mDisplayStates;
         uint32_t                    mForceSynchronous = 0;
         uint32_t                    mTransactionNestCount = 0;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index e0d2113..c07a812 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -1090,7 +1090,7 @@
 static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) {
     // The input should be in reversed time order (most recent sample at index i=0)
     // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function
-    static constexpr float NANOS_PER_SECOND = 1E-9;
+    static constexpr float SECONDS_PER_NANO = 1E-9;
 
     if (count < 2) {
         return 0; // if 0 or 1 points, velocity is zero
@@ -1103,7 +1103,7 @@
             ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]);
             return 0;
         }
-        return (x[1] - x[0]) / (NANOS_PER_SECOND * (t[1] - t[0]));
+        return (x[1] - x[0]) / (SECONDS_PER_NANO * (t[1] - t[0]));
     }
     // Guaranteed to have at least 3 points here
     float work = 0;
@@ -1113,7 +1113,7 @@
             continue;
         }
         float vprev = kineticEnergyToVelocity(work); // v[i-1]
-        float vcurr = (x[i] - x[i-1]) / (NANOS_PER_SECOND * (t[i] - t[i-1])); // v[i]
+        float vcurr = (x[i] - x[i-1]) / (SECONDS_PER_NANO * (t[i] - t[i-1])); // v[i]
         work += (vcurr - vprev) * fabsf(vcurr);
         if (i == count - 1) {
             work *= 0.5; // initial condition, case 2) above
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
index 6a38a1f..d4393d6 100644
--- a/libs/sensor/OWNERS
+++ b/libs/sensor/OWNERS
@@ -1,2 +1,2 @@
-ashutoshj@google.com
-pengxu@google.com
+arthuri@google.com
+bduddie@google.com
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 2d72944..17ebf80 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -74,7 +74,7 @@
                 case HAL_DATASPACE_SRGB:
                     return std::string("(deprecated) sRGB");
 
-                case HAL_DATASPACE_V0_BT709:
+                case HAL_DATASPACE_BT709:
                     return std::string("(deprecated) BT709");
 
                 case HAL_DATASPACE_ARBITRARY:
@@ -84,7 +84,7 @@
                 // Fallthrough
                 default:
                     return android::base::StringPrintf("Unknown deprecated dataspace code %d",
-                                                       dataspaceSelect);
+                                                       dataspace);
             }
     }
 
@@ -98,7 +98,7 @@
             case HAL_DATASPACE_JFIF:
             case HAL_DATASPACE_BT601_625:
             case HAL_DATASPACE_BT601_525:
-            case HAL_DATASPACE_V0_BT709:
+            case HAL_DATASPACE_BT709:
                 return std::string("SMPTE_170M");
 
             case HAL_DATASPACE_SRGB_LINEAR:
@@ -159,8 +159,8 @@
 
             case HAL_DATASPACE_BT601_625:
             case HAL_DATASPACE_BT601_525:
-            case HAL_DATASPACE_V0_BT709:
-                return std::string("Limited range)");
+            case HAL_DATASPACE_BT709:
+                return std::string("Limited range");
 
             case HAL_DATASPACE_ARBITRARY:
             case HAL_DATASPACE_UNKNOWN:
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 8fe9dfb..6db09a9 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -395,25 +395,16 @@
 }
 
 BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                               uint32_t usage, size_t user_metadata_size)
-    : BufferProducer(width, height, format, usage, usage, user_metadata_size) {}
-
-BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                               uint64_t producer_usage, uint64_t consumer_usage,
-                               size_t user_metadata_size)
+                               uint64_t usage, size_t user_metadata_size)
     : BASE(BufferHubRPC::kClientPath) {
   ATRACE_NAME("BufferProducer::BufferProducer");
   ALOGD_IF(TRACE,
            "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u "
-           "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64
-           " user_metadata_size=%zu",
-           event_fd(), width, height, format, producer_usage, consumer_usage,
-           user_metadata_size);
+           "usage=%" PRIx64 " user_metadata_size=%zu",
+           event_fd(), width, height, format, usage, user_metadata_size);
 
-  // (b/37881101) Deprecate producer/consumer usage
   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
-      width, height, format, (producer_usage | consumer_usage),
-      user_metadata_size);
+      width, height, format, usage, user_metadata_size);
   if (!status) {
     ALOGE(
         "BufferProducer::BufferProducer: Failed to create producer buffer: %s",
@@ -431,26 +422,18 @@
   }
 }
 
-BufferProducer::BufferProducer(uint32_t usage, size_t size)
-    : BufferProducer(usage, usage, size) {}
-
-BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage,
-                               size_t size)
+BufferProducer::BufferProducer(uint64_t usage, size_t size)
     : BASE(BufferHubRPC::kClientPath) {
   ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE,
-           "BufferProducer::BufferProducer: producer_usage=%" PRIx64
-           " consumer_usage=%" PRIx64 " size=%zu",
-           producer_usage, consumer_usage, size);
+  ALOGD_IF(TRACE, "BufferProducer::BufferProducer: usage=%" PRIx64 " size=%zu",
+           usage, size);
   const int width = static_cast<int>(size);
   const int height = 1;
   const int format = HAL_PIXEL_FORMAT_BLOB;
   const size_t user_metadata_size = 0;
 
-  // (b/37881101) Deprecate producer/consumer usage
   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
-      width, height, format, (producer_usage | consumer_usage),
-      user_metadata_size);
+      width, height, format, usage, user_metadata_size);
   if (!status) {
     ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s",
           status.GetErrorMessage().c_str());
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index 8a4440f..c791250 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -111,10 +111,6 @@
   uint32_t usage() const { return buffer_.usage(); }
   uint32_t layer_count() const { return buffer_.layer_count(); }
 
-  // TODO(b/37881101) Clean up producer/consumer usage.
-  uint64_t producer_usage() const { return buffer_.usage(); }
-  uint64_t consumer_usage() const { return buffer_.usage(); }
-
   uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
   void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
 
@@ -230,14 +226,10 @@
 
   // Constructs a buffer with the given geometry and parameters.
   BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                 uint32_t usage, size_t metadata_size = 0);
-  BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                 uint64_t producer_usage, uint64_t consumer_usage,
-                 size_t metadata_size);
+                 uint64_t usage, size_t metadata_size = 0);
 
   // Constructs a blob (flat) buffer with the given usage flags.
-  BufferProducer(uint32_t usage, size_t size);
-  BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, size_t size);
+  BufferProducer(uint64_t usage, size_t size);
 
   // Imports the given file handle to a producer channel, taking ownership.
   explicit BufferProducer(LocalChannelHandle channel);
diff --git a/libs/vr/libdvr/tests/dvr_api_test.h b/libs/vr/libdvr/tests/dvr_api_test.h
index 648af75..d8359e7 100644
--- a/libs/vr/libdvr/tests/dvr_api_test.h
+++ b/libs/vr/libdvr/tests/dvr_api_test.h
@@ -3,8 +3,6 @@
 
 #include <gtest/gtest.h>
 
-#define ASSERT_NOT_NULL(x) ASSERT_TRUE((x) != nullptr)
-
 /** DvrTestBase loads the libdvr.so at runtime and get the Dvr API version 1. */
 class DvrApiTest : public ::testing::Test {
  protected:
@@ -17,11 +15,11 @@
     // https://github.com/android-ndk/ndk/issues/360
     flags |= RTLD_NODELETE;
     platform_handle_ = dlopen("libdvr.so", flags);
-    ASSERT_NOT_NULL(platform_handle_) << "Dvr shared library missing.";
+    ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing.";
 
     auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>(
         dlsym(platform_handle_, "dvrGetApi"));
-    ASSERT_NOT_NULL(dvr_get_api) << "Platform library missing dvrGetApi.";
+    ASSERT_NE(nullptr, dvr_get_api) << "Platform library missing dvrGetApi.";
 
     ASSERT_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0)
         << "Unable to find compatible Dvr API.";
diff --git a/libs/vr/libdvr/tests/dvr_display-test.cpp b/libs/vr/libdvr/tests/dvr_display-test.cpp
index 1165573..c72f940 100644
--- a/libs/vr/libdvr/tests/dvr_display-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display-test.cpp
@@ -16,20 +16,58 @@
 
 class DvrDisplayTest : public DvrApiTest {
  protected:
+  void SetUp() override {
+    DvrApiTest::SetUp();
+    int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_),
+                                           &display_metrics_);
+    ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
+    ALOGD(
+        "display_width: %d, display_height: %d, display_x_dpi: %d, "
+        "display_y_dpi: %d, vsync_period_ns: %d.",
+        display_metrics_.display_width, display_metrics_.display_height,
+        display_metrics_.display_x_dpi, display_metrics_.display_y_dpi,
+        display_metrics_.vsync_period_ns);
+  }
+
   void TearDown() override {
     if (write_queue_ != nullptr) {
       api_.WriteBufferQueueDestroy(write_queue_);
       write_queue_ = nullptr;
     }
+    if (direct_surface_ != nullptr) {
+      api_.SurfaceDestroy(direct_surface_);
+      direct_surface_ = nullptr;
+    }
     DvrApiTest::TearDown();
   }
 
+  /* Convert a write buffer to an android hardware buffer and fill in
+   * color_textures evenly to the buffer.
+   * AssertionError if the width of the buffer is not equal to the input width,
+   * AssertionError if the height of the buffer is not equal to the input
+   * height.
+   */
+  void FillWriteBuffer(DvrWriteBuffer* write_buffer,
+                       const std::vector<uint32_t>& color_textures,
+                       uint32_t width, uint32_t height);
+
+  // Write buffer queue properties.
+  static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+                                     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+                                     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+  uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+  static constexpr size_t kMetadataSize = 0;
+  static constexpr int kTimeoutMs = 1000;  // Time for getting buffer.
+  uint32_t kLayerCount = 1;
   DvrWriteBufferQueue* write_queue_ = nullptr;
+  DvrSurface* direct_surface_ = nullptr;
+
+  // Device display properties.
+  DvrNativeDisplayMetrics display_metrics_;
 };
 
-TEST_F(DvrDisplayTest, DisplaySingleColor) {
-  // Create direct surface.
-  DvrSurface* direct_surface = nullptr;
+TEST_F(DvrDisplayTest, DisplayWithOneBuffer) {
+  // Create a direct surface.
   std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
       {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
@@ -43,73 +81,32 @@
   };
   int ret =
       api_.SurfaceCreate(direct_surface_attributes.data(),
-                         direct_surface_attributes.size(), &direct_surface);
+                         direct_surface_attributes.size(), &direct_surface_);
   ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
 
-  // Get screen dimension.
-  DvrNativeDisplayMetrics display_metrics;
-  ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics), &display_metrics);
-  ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
-  ALOGD(
-      "display_width: %d, display_height: %d, display_x_dpi: %d, "
-      "display_y_dpi: %d, vsync_period_ns: %d.",
-      display_metrics.display_width, display_metrics.display_height,
-      display_metrics.display_x_dpi, display_metrics.display_y_dpi,
-      display_metrics.vsync_period_ns);
-
   // Create a buffer queue with the direct surface.
-  constexpr uint32_t kLayerCount = 1;
-  constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
-                              AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
-                              AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
-  constexpr uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
   constexpr size_t kCapacity = 1;
-  constexpr size_t kMetadataSize = 0;
-  uint32_t width = display_metrics.display_width;
-  uint32_t height = display_metrics.display_height;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
   ret = api_.SurfaceCreateWriteBufferQueue(
-      direct_surface, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
       kMetadataSize, &write_queue_);
   EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
-  ASSERT_NOT_NULL(write_queue_) << "Write buffer queue should not be null.";
+  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
 
   // Get buffer from WriteBufferQueue.
   DvrWriteBuffer* write_buffer = nullptr;
-  constexpr int kTimeoutMs = 1000;
   DvrNativeBufferMetadata out_meta;
   int out_fence_fd = -1;
   ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer,
                                         &out_meta, &out_fence_fd);
   EXPECT_EQ(0, ret) << "Failed to get the buffer.";
-  ASSERT_NOT_NULL(write_buffer) << "Gained buffer should not be null.";
+  ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null.";
 
-  // Convert to an android hardware buffer.
-  AHardwareBuffer* ah_buffer{nullptr};
-  ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
-  EXPECT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
-  ASSERT_NOT_NULL(ah_buffer) << "AHardware buffer should not be null.";
-
-  // Change the content of the android hardware buffer.
-  void* buffer_data{nullptr};
-  int32_t fence = -1;
-  ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-                             fence, nullptr, &buffer_data);
-  EXPECT_EQ(0, ret) << "Failed to lock the hardware buffer.";
-  ASSERT_NOT_NULL(buffer_data) << "Buffer data should not be null.";
-
-  uint32_t color_texture = 0xff0000ff;  // Red color in RGBA.
-  for (uint32_t i = 0; i < width * height; ++i) {
-    memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
-                                   i * sizeof(color_texture)),
-           &color_texture, sizeof(color_texture));
-  }
-
-  fence = -1;
-  ret = AHardwareBuffer_unlock(ah_buffer, &fence);
-  EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
-
-  // Release the android hardware buffer.
-  AHardwareBuffer_release(ah_buffer);
+  // Color the write buffer.
+  FillWriteBuffer(write_buffer,
+                  {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
+                  width, height);
 
   // Post buffer.
   int ready_fence_fd = -1;
@@ -118,4 +115,237 @@
   EXPECT_EQ(0, ret) << "Failed to post the buffer.";
 
   sleep(5);  // For visual check on the device under test.
+  // Should observe three primary colors on the screen center.
+}
+
+TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) {
+  // Create a direct surface.
+  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_attributes.data(),
+                         direct_surface_attributes.size(), &direct_surface_);
+  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue with the direct surface.
+  constexpr size_t kCapacity = 2;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
+
+  int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9);
+  ALOGD("The number of display cycles: %d", num_display_cycles_in_5s);
+  int bufferhub_id_prev_write_buffer = -1;
+  for (int i = 0; i < num_display_cycles_in_5s; ++i) {
+    // Get a buffer from the WriteBufferQueue.
+    DvrWriteBuffer* write_buffer = nullptr;
+    DvrNativeBufferMetadata out_meta;
+    int out_fence_fd = -1;
+    ret = api_.WriteBufferQueueGainBuffer(
+        write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd);
+    EXPECT_EQ(0, ret) << "Failed to get the a write buffer.";
+    ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null.";
+
+    int bufferhub_id = api_.WriteBufferGetId(write_buffer);
+    ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i,
+          bufferhub_id);
+    EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id)
+        << "Double buffering should be using the two buffers in turns, not "
+           "reusing the same write buffer.";
+    bufferhub_id_prev_write_buffer = bufferhub_id;
+
+    // Color the write buffer.
+    if (i % 2) {
+      FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
+                      height);
+    } else {
+      FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width,
+                      height);
+    }
+
+    // Post the write buffer.
+    int ready_fence_fd = -1;
+    ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
+                                          ready_fence_fd);
+    EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+  }
+  // Should observe blinking screen in secondary colors
+  // although it is actually displaying primary colors.
+}
+
+TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) {
+  // Create the direct_surface_0 of z order 10 and direct_surface_1 of z
+  // order 11.
+  DvrSurface* direct_surface_0 = nullptr;
+  std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_0_attributes.data(),
+                         direct_surface_0_attributes.size(), &direct_surface_0);
+  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  DvrSurface* direct_surface_1 = nullptr;
+  std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 11},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  ret =
+      api_.SurfaceCreate(direct_surface_1_attributes.data(),
+                         direct_surface_1_attributes.size(), &direct_surface_1);
+  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue for each of the direct surfaces.
+  constexpr size_t kCapacity = 1;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+
+  DvrWriteBufferQueue* write_queue_0 = nullptr;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_0);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null.";
+
+  DvrWriteBufferQueue* write_queue_1 = nullptr;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_1);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null.";
+
+  // Get a buffer from each of the write buffer queues.
+  DvrWriteBuffer* write_buffer_0 = nullptr;
+  DvrNativeBufferMetadata out_meta_0;
+  int out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(
+      write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null.";
+
+  DvrWriteBuffer* write_buffer_1 = nullptr;
+  DvrNativeBufferMetadata out_meta_1;
+  out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(
+      write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null.";
+
+  // Color the write buffers.
+  FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
+                  height);
+  FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width,
+                  height);
+
+  // Post buffers.
+  int ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0,
+                                        &out_meta_0, ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1,
+                                        &out_meta_1, ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  sleep(5);  // For visual check on the device under test.
+  // Should observe three secondary colors.
+
+  // Test finished. Clean up buffers and surfaces.
+  if (write_queue_0 != nullptr) {
+    api_.WriteBufferQueueDestroy(write_queue_0);
+    write_queue_0 = nullptr;
+  }
+  if (write_queue_1 != nullptr) {
+    api_.WriteBufferQueueDestroy(write_queue_1);
+    write_queue_1 = nullptr;
+  }
+  if (direct_surface_0 != nullptr) {
+    api_.SurfaceDestroy(direct_surface_0);
+  }
+  if (direct_surface_1 != nullptr) {
+    api_.SurfaceDestroy(direct_surface_1);
+  }
+}
+
+void DvrDisplayTest::FillWriteBuffer(
+    DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures,
+    uint32_t width, uint32_t height) {
+  uint32_t num_colors = color_textures.size();
+  // Convert the first write buffer to an android hardware buffer.
+  AHardwareBuffer* ah_buffer = nullptr;
+  int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
+  ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
+  ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null.";
+  AHardwareBuffer_Desc ah_buffer_describe;
+  AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe);
+  ASSERT_EQ(ah_buffer_describe.format, kFormat)
+      << "The format of the android hardware buffer is wrong.";
+  ASSERT_EQ(ah_buffer_describe.layers, kLayerCount)
+      << "The obtained android hardware buffer should have 2 layers.";
+  ASSERT_EQ(ah_buffer_describe.width, width)
+      << "The obtained android hardware buffer width is wrong.";
+  ASSERT_EQ(ah_buffer_describe.height, height)
+      << "The obtained android hardware buffer height is wrong.";
+  // Change the content of the android hardware buffer.
+  void* buffer_data = nullptr;
+  int32_t fence = -1;
+  ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+                             fence, nullptr, &buffer_data);
+  ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer.";
+  ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null.";
+
+  uint32_t num_pixels = width * height / num_colors;
+  for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) {
+    uint32_t color_texture = color_textures[color_index];
+    for (uint32_t i = 0; i < num_pixels; ++i) {
+      memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
+                                     (i + num_pixels * color_index) *
+                                         sizeof(color_texture)),
+             &color_texture, sizeof(color_texture));
+    }
+  }
+  uint32_t color_texture = color_textures[num_colors - 1];
+  uint32_t num_colored_pixels = num_pixels * (num_colors - 1);
+  num_pixels = width * height - num_colored_pixels;
+  for (uint32_t i = 0; i < num_pixels; ++i) {
+    memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
+                                   (i + num_colored_pixels) *
+                                       sizeof(color_texture)),
+           &color_texture, sizeof(color_texture));
+  }
+  fence = -1;
+  ret = AHardwareBuffer_unlock(ah_buffer, &fence);
+  EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
+
+  // Release the android hardware buffer.
+  AHardwareBuffer_release(ah_buffer);
 }
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 23a9853..3e4a42c 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -39,6 +39,7 @@
     "android.frameworks.vr.composer@1.0",
     "android.hardware.graphics.allocator@2.0",
     "android.hardware.graphics.composer@2.1",
+    "android.hardware.graphics.composer@2.2",
     "libbinder",
     "libbase",
     "libbufferhubqueue",
@@ -62,6 +63,7 @@
 
 headerLibraries = [
     "android.hardware.graphics.composer@2.1-command-buffer",
+    "android.hardware.graphics.composer@2.2-command-buffer",
     "libdvr_headers",
     "libsurfaceflinger_headers",
 ]
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 46e7a97..b453d19 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -87,6 +87,8 @@
         "EGL_ANDROID_get_native_client_buffer "
         "EGL_ANDROID_front_buffer_auto_refresh "
         "EGL_ANDROID_get_frame_timestamps "
+        "EGL_EXT_surface_SMPTE2086_metadata "
+        "EGL_EXT_surface_CTA861_3_metadata "
         ;
 
 char const * const gExtensionString  =
@@ -240,8 +242,6 @@
          !strcmp((procname), "eglHibernateProcessIMG")      ||    \
          !strcmp((procname), "eglAwakenProcessIMG"))
 
-
-
 // accesses protected by sExtensionMapMutex
 static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
 
@@ -476,26 +476,61 @@
     return dataSpace;
 }
 
-// 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
+// stripAttributes is used by eglCreateWindowSurface, eglCreatePbufferSurface
+// and eglCreatePixmapSurface to clean up color space related Window parameters
+// that a driver does not advertise support for.
+// Return true if stripped_attrib_list has stripped contents.
+
 static EGLBoolean stripAttributes(egl_display_ptr dp, const EGLint* attrib_list,
                                   EGLint format,
                                   std::vector<EGLint>& stripped_attrib_list) {
     std::vector<EGLint> allowedColorSpaces;
+    bool haveColorSpaceSupport = dp->haveExtension("EGL_KHR_gl_colorspace");
     switch (format) {
         case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGB_565:
-            // driver okay with linear & sRGB for 8888, but can't handle
-            // Display-P3 or other spaces.
-            allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
-            allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
+            if (haveColorSpaceSupport) {
+                // Spec says:
+                //     [fn1] Only OpenGL and OpenGL ES contexts which support sRGB
+                //     rendering must respect requests for EGL_GL_COLORSPACE_SRGB_KHR, and
+                //     only to sRGB formats supported by the context (normally just SRGB8)
+                //     Older versions not supporting sRGB rendering will ignore this
+                //     surface attribute.
+                //
+                // We support sRGB and pixel format is SRGB8, so allow
+                // the EGL_GL_COLORSPACE_SRGB_KHR and
+                // EGL_GL_COLORSPACE_LINEAR_KHR
+                // colorspaces to be specified.
+
+                allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+                allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
+            }
+            if (findExtension(dp->disp.queryString.extensions,
+                                  "EGL_EXT_gl_colorspace_display_p3_linear")) {
+                allowedColorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
+            }
+            if (findExtension(dp->disp.queryString.extensions,
+                                  "EGL_EXT_gl_colorspace_display_p3")) {
+                allowedColorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
+            }
+            if (findExtension(dp->disp.queryString.extensions,
+                                  "EGL_EXT_gl_colorspace_bt2020_linear")) {
+                allowedColorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
+            }
+            if (findExtension(dp->disp.queryString.extensions,
+                                  "EGL_EXT_gl_colorspace_bt2020_pq")) {
+                allowedColorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
+            }
+            if (findExtension(dp->disp.queryString.extensions,
+                                  "EGL_EXT_gl_colorspace_scrgb_linear")) {
+                allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
+            }
             break;
 
         case HAL_PIXEL_FORMAT_RGBA_FP16:
         case HAL_PIXEL_FORMAT_RGBA_1010102:
-        default:
-            // driver does not want to see colorspace attributes for 1010102 or fp16.
+        case HAL_PIXEL_FORMAT_RGB_565:
             // Future: if driver supports XXXX extension, we can pass down that colorspace
+        default:
             break;
     }
 
@@ -513,40 +548,23 @@
                             found = true;
                         }
                     }
-                    if (found || !dp->haveExtension("EGL_KHR_gl_colorspace")) {
+                    if (found) {
+                        // Found supported attribute
+                        stripped_attrib_list.push_back(attr[0]);
+                        stripped_attrib_list.push_back(attr[1]);
+                    } else if (!haveColorSpaceSupport) {
+                        // Device does not support colorspace extension
+                        // pass on the attribute and let downstream
+                        // components validate like normal
                         stripped_attrib_list.push_back(attr[0]);
                         stripped_attrib_list.push_back(attr[1]);
                     } else {
+                        // Found supported attribute that driver does not
+                        // support, strip it.
                         stripped = true;
                     }
                 }
                 break;
-            case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
-            case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
-            case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
-            case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
-            case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
-            case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
-            case EGL_SMPTE2086_WHITE_POINT_X_EXT:
-            case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
-            case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
-            case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
-                if (dp->haveExtension("EGL_EXT_surface_SMPTE2086_metadata")) {
-                    stripped = true;
-                } else {
-                    stripped_attrib_list.push_back(attr[0]);
-                    stripped_attrib_list.push_back(attr[1]);
-                }
-                break;
-            case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
-            case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
-                if (dp->haveExtension("EGL_EXT_surface_CTA861_3_metadata")) {
-                    stripped = true;
-                } else {
-                    stripped_attrib_list.push_back(attr[0]);
-                    stripped_attrib_list.push_back(attr[1]);
-                }
-                break;
             default:
                 stripped_attrib_list.push_back(attr[0]);
                 stripped_attrib_list.push_back(attr[1]);
@@ -700,34 +718,26 @@
     }
 }
 
-EGLBoolean setSurfaceMetadata(egl_surface_t* s, NativeWindowType window,
-                              const EGLint *attrib_list) {
-    // set any HDR metadata
-    bool smpte2086 = false;
-    bool cta8613 = false;
-    if (attrib_list == nullptr) return EGL_TRUE;
-
-    for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
-        smpte2086 |= s->setSmpte2086Attribute(attr[0], attr[1]);
-        cta8613 |= s->setCta8613Attribute(attr[0], attr[1]);
-    }
-    if (smpte2086) {
-        android_smpte2086_metadata metadata = s->getSmpte2086Metadata();
-        int err = native_window_set_buffers_smpte2086_metadata(window, &metadata);
+EGLBoolean sendSurfaceMetadata(egl_surface_t* s) {
+    android_smpte2086_metadata smpteMetadata;
+    if (s->getSmpte2086Metadata(smpteMetadata)) {
+        int err =
+                native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata);
+        s->resetSmpte2086Metadata();
         if (err != 0) {
             ALOGE("error setting native window smpte2086 metadata: %s (%d)",
                   strerror(-err), err);
-            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
             return EGL_FALSE;
         }
     }
-    if (cta8613) {
-        android_cta861_3_metadata metadata = s->getCta8613Metadata();
-        int err = native_window_set_buffers_cta861_3_metadata(window, &metadata);
+    android_cta861_3_metadata cta8613Metadata;
+    if (s->getCta8613Metadata(cta8613Metadata)) {
+        int err =
+                native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata);
+        s->resetCta8613Metadata();
         if (err != 0) {
             ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
                   strerror(-err), err);
-            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
             return EGL_FALSE;
         }
     }
@@ -812,11 +822,7 @@
         if (surface != EGL_NO_SURFACE) {
             egl_surface_t* s =
                     new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx);
-
-            if (setSurfaceMetadata(s, window, origAttribList)) {
-                return s;
-            }
-            eglDestroySurface(dpy, s);
+            return s;
         }
 
         // EGLSurface creation failed
@@ -1424,7 +1430,7 @@
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
-    egl_surface_t const * const s = get_surface(draw);
+    egl_surface_t* const s = get_surface(draw);
 
     if (CC_UNLIKELY(dp->traceGpuCompletion)) {
         EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
@@ -1443,6 +1449,11 @@
         }
     }
 
+    if (!sendSurfaceMetadata(s)) {
+        native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
+        return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
+    }
+
     if (n_rects == 0) {
         return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
     }
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 0f36614..74ddd1c 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -51,8 +51,11 @@
 
 // ----------------------------------------------------------------------------
 
-static bool findExtension(const char* exts, const char* name, size_t nameLen) {
+bool findExtension(const char* exts, const char* name, size_t nameLen) {
     if (exts) {
+        if (!nameLen) {
+            nameLen = strlen(name);
+        }
         for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) {
             if (match[nameLen] == '\0' || match[nameLen] == ' ') {
                 return true;
@@ -226,11 +229,6 @@
                     "EGL_EXT_gl_colorspace_bt2020_linear EGL_EXT_gl_colorspace_bt2020_pq ");
         }
 
-        // Always advertise HDR metadata extensions since it's okay for an application
-        // to specify such information even though it may not be used by the system.
-        mExtensionString.append(
-                "EGL_EXT_surface_SMPTE2086_metadata EGL_EXT_surface_CTA861_3_metadata ");
-
         char const* start = gExtensionString;
         do {
             // length of the extension name
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 661f47e..ccd333d 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -42,6 +42,8 @@
 class egl_context_t;
 struct egl_connection_t;
 
+bool findExtension(const char* exts, const char* name, size_t nameLen = 0);
+
 // ----------------------------------------------------------------------------
 
 class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index b68fd61..f879254 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -64,8 +64,17 @@
         cnx(cnx),
         connected(true),
         colorSpace(colorSpace),
-        egl_smpte2086_metadata({}),
-        egl_cta861_3_metadata({}) {
+        egl_smpte2086_dirty(false),
+        egl_cta861_3_dirty(false) {
+    egl_smpte2086_metadata.displayPrimaryRed = { EGL_DONT_CARE, EGL_DONT_CARE };
+    egl_smpte2086_metadata.displayPrimaryGreen = { EGL_DONT_CARE, EGL_DONT_CARE };
+    egl_smpte2086_metadata.displayPrimaryBlue = { EGL_DONT_CARE, EGL_DONT_CARE };
+    egl_smpte2086_metadata.whitePoint = { EGL_DONT_CARE, EGL_DONT_CARE };
+    egl_smpte2086_metadata.maxLuminance = EGL_DONT_CARE;
+    egl_smpte2086_metadata.minLuminance = EGL_DONT_CARE;
+    egl_cta861_3_metadata.maxFrameAverageLightLevel = EGL_DONT_CARE;
+    egl_cta861_3_metadata.maxContentLightLevel = EGL_DONT_CARE;
+
     if (win) {
         win->incStrong(this);
     }
@@ -92,33 +101,43 @@
     switch (attribute) {
         case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
             egl_smpte2086_metadata.displayPrimaryRed.x = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
             egl_smpte2086_metadata.displayPrimaryRed.y = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
             egl_smpte2086_metadata.displayPrimaryGreen.x = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
             egl_smpte2086_metadata.displayPrimaryGreen.y = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
             egl_smpte2086_metadata.displayPrimaryBlue.x = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
             egl_smpte2086_metadata.displayPrimaryBlue.y = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_WHITE_POINT_X_EXT:
             egl_smpte2086_metadata.whitePoint.x = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
             egl_smpte2086_metadata.whitePoint.y = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
             egl_smpte2086_metadata.maxLuminance = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
         case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
             egl_smpte2086_metadata.minLuminance = value;
+            egl_smpte2086_dirty = true;
             return EGL_TRUE;
     }
     return EGL_FALSE;
@@ -128,16 +147,32 @@
     switch (attribute) {
         case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
             egl_cta861_3_metadata.maxContentLightLevel = value;
+            egl_cta861_3_dirty = true;
             return EGL_TRUE;
         case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
             egl_cta861_3_metadata.maxFrameAverageLightLevel = value;
+            egl_cta861_3_dirty = true;
             return EGL_TRUE;
     }
     return EGL_FALSE;
 }
 
-const android_smpte2086_metadata egl_surface_t::getSmpte2086Metadata() {
-    android_smpte2086_metadata metadata;
+EGLBoolean egl_surface_t::getSmpte2086Metadata(android_smpte2086_metadata& metadata) const {
+    if (!egl_smpte2086_dirty) return EGL_FALSE;
+    if (egl_smpte2086_metadata.displayPrimaryRed.x == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryRed.y == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryGreen.x == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryGreen.y == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryBlue.x == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryBlue.y == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.whitePoint.x == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.whitePoint.y == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.maxLuminance == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.minLuminance == EGL_DONT_CARE) {
+        ALOGW("egl_surface_t: incomplete SMPTE 2086 metadata!");
+        return EGL_FALSE;
+    }
+
     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;
@@ -149,14 +184,22 @@
     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;
+    return EGL_TRUE;
 }
 
-const android_cta861_3_metadata egl_surface_t::getCta8613Metadata() {
-    android_cta861_3_metadata metadata;
+EGLBoolean egl_surface_t::getCta8613Metadata(android_cta861_3_metadata& metadata) const {
+    if (!egl_cta861_3_dirty) return EGL_FALSE;
+
+    if (egl_cta861_3_metadata.maxContentLightLevel == EGL_DONT_CARE ||
+        egl_cta861_3_metadata.maxFrameAverageLightLevel == EGL_DONT_CARE) {
+        ALOGW("egl_surface_t: incomplete CTA861.3 metadata!");
+        return EGL_FALSE;
+    }
+
     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;
+
+    return EGL_TRUE;
 }
 
 
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index bda91bb..4e1de5c 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -142,8 +142,10 @@
     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 android_cta861_3_metadata getCta8613Metadata();
+    EGLBoolean getSmpte2086Metadata(android_smpte2086_metadata& smpte2086) const;
+    EGLBoolean getCta8613Metadata(android_cta861_3_metadata& cta861_3) const;
+    void resetSmpte2086Metadata() { egl_smpte2086_dirty = false; }
+    void resetCta8613Metadata() { egl_cta861_3_dirty = false; }
 
     // 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.
@@ -176,6 +178,10 @@
         EGLint maxContentLightLevel;
         EGLint maxFrameAverageLightLevel;
     };
+
+    bool egl_smpte2086_dirty;
+    bool egl_cta861_3_dirty;
+
     egl_smpte2086_metadata egl_smpte2086_metadata;
     egl_cta861_3_metadata egl_cta861_3_metadata;
 };
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 9ffe036..5927dc1 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -61,8 +61,8 @@
 class EGLTest : public ::testing::Test {
 public:
     void get8BitConfig(EGLConfig& config);
-    void addOptionalWindowMetadata(std::vector<EGLint>& attrs);
-    void checkOptionalWindowMetadata(EGLSurface eglSurface);
+    void setSurfaceSmpteMetadata(EGLSurface surface);
+    void checkSurfaceSmpteMetadata(EGLSurface eglSurface);
 
 protected:
     EGLDisplay mEglDisplay;
@@ -421,39 +421,39 @@
     EXPECT_EQ(components[3], 8);
 }
 
-void EGLTest::addOptionalWindowMetadata(std::vector<EGLint>& attrs) {
+void EGLTest::setSurfaceSmpteMetadata(EGLSurface surface) {
     if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
-        attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT);
-        attrs.push_back(METADATA_SCALE(0.640));
-        attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT);
-        attrs.push_back(METADATA_SCALE(0.330));
-        attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT);
-        attrs.push_back(METADATA_SCALE(0.290));
-        attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT);
-        attrs.push_back(METADATA_SCALE(0.600));
-        attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT);
-        attrs.push_back(METADATA_SCALE(0.150));
-        attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT);
-        attrs.push_back(METADATA_SCALE(0.060));
-        attrs.push_back(EGL_SMPTE2086_WHITE_POINT_X_EXT);
-        attrs.push_back(METADATA_SCALE(0.3127));
-        attrs.push_back(EGL_SMPTE2086_WHITE_POINT_Y_EXT);
-        attrs.push_back(METADATA_SCALE(0.3290));
-        attrs.push_back(EGL_SMPTE2086_MAX_LUMINANCE_EXT);
-        attrs.push_back(METADATA_SCALE(300));
-        attrs.push_back(EGL_SMPTE2086_MIN_LUMINANCE_EXT);
-        attrs.push_back(METADATA_SCALE(0.7));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT,
+                         METADATA_SCALE(0.640));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT,
+                         METADATA_SCALE(0.330));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT,
+                         METADATA_SCALE(0.290));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT,
+                         METADATA_SCALE(0.600));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT,
+                         METADATA_SCALE(0.150));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT,
+                         METADATA_SCALE(0.060));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_WHITE_POINT_X_EXT,
+                         METADATA_SCALE(0.3127));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_WHITE_POINT_Y_EXT,
+                         METADATA_SCALE(0.3290));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT,
+                         METADATA_SCALE(300));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_MIN_LUMINANCE_EXT,
+                         METADATA_SCALE(0.7));
     }
 
     if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
-        attrs.push_back(EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT);
-        attrs.push_back(METADATA_SCALE(300));
-        attrs.push_back(EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT);
-        attrs.push_back(METADATA_SCALE(75));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                         METADATA_SCALE(300));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT,
+                         METADATA_SCALE(75));
     }
 }
 
-void EGLTest::checkOptionalWindowMetadata(EGLSurface eglSurface) {
+void EGLTest::checkSurfaceSmpteMetadata(EGLSurface eglSurface) {
     EGLBoolean success;
     EGLint value;
 
@@ -534,8 +534,6 @@
     winAttrs.push_back(EGL_GL_COLORSPACE_KHR);
     winAttrs.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
 
-    ASSERT_NO_FATAL_FAILURE(addOptionalWindowMetadata(winAttrs));
-
     winAttrs.push_back(EGL_NONE);
 
     EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs.data());
@@ -547,7 +545,9 @@
     ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
     ASSERT_EQ(EGL_GL_COLORSPACE_BT2020_PQ_EXT, value);
 
-    ASSERT_NO_FATAL_FAILURE(checkOptionalWindowMetadata(eglSurface));
+    ASSERT_NO_FATAL_FAILURE(setSurfaceSmpteMetadata(eglSurface));
+
+    ASSERT_NO_FATAL_FAILURE(checkSurfaceSmpteMetadata(eglSurface));
 
     EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
 }
@@ -584,9 +584,6 @@
     std::vector<EGLint> winAttrs;
     winAttrs.push_back(EGL_GL_COLORSPACE_KHR);
     winAttrs.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
-
-    ASSERT_NO_FATAL_FAILURE(addOptionalWindowMetadata(winAttrs));
-
     winAttrs.push_back(EGL_NONE);
 
     EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs.data());
@@ -598,7 +595,9 @@
     ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
     ASSERT_EQ(EGL_GL_COLORSPACE_BT2020_PQ_EXT, value);
 
-    ASSERT_NO_FATAL_FAILURE(checkOptionalWindowMetadata(eglSurface));
+    ASSERT_NO_FATAL_FAILURE(setSurfaceSmpteMetadata(eglSurface));
+
+    ASSERT_NO_FATAL_FAILURE(checkSurfaceSmpteMetadata(eglSurface));
 
     EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
 }
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index 13f6fba..0bb77f3 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -32,6 +32,8 @@
 using namespace android;
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
+#define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
+
 static void printGLString(const char *name, GLenum s) {
     // fprintf(stderr, "printGLString %s, %d\n", name, s);
     const char *v = (const char *) glGetString(s);
@@ -265,6 +267,39 @@
     return true;
 }
 
+void setSurfaceMetadata(EGLDisplay dpy, EGLSurface surface) {
+    static EGLBoolean toggle = GL_FALSE;
+    if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_SMPTE2086_metadata")) {
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, METADATA_SCALE(0.640));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, METADATA_SCALE(0.330));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, METADATA_SCALE(0.290));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, METADATA_SCALE(0.600));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, METADATA_SCALE(0.150));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, METADATA_SCALE(0.060));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_X_EXT, METADATA_SCALE(0.3127));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, METADATA_SCALE(0.3290));
+        if (toggle) {
+            eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(350));
+        } else {
+            eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(300));
+        }
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, METADATA_SCALE(0.7));
+    }
+
+    if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_CTA861_3_metadata")) {
+        if (toggle) {
+            eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                             METADATA_SCALE(300));
+        } else {
+            eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                             METADATA_SCALE(325));
+        }
+        eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT,
+                         METADATA_SCALE(75));
+    }
+    toggle = !toggle;
+}
+
 int main(int /*argc*/, char** /*argv*/) {
     EGLBoolean returnValue;
     EGLConfig myConfig = {0};
@@ -318,10 +353,11 @@
     printf("Chose this configuration:\n");
     printEGLConfiguration(dpy, myConfig);
 
-    surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+    EGLint winAttribs[] = {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE};
+    surface = eglCreateWindowSurface(dpy, myConfig, window, winAttribs);
     checkEglError("eglCreateWindowSurface");
     if (surface == EGL_NO_SURFACE) {
-        printf("gelCreateWindowSurface failed.\n");
+        printf("eglCreateWindowSurface failed.\n");
         return 0;
     }
 
@@ -356,6 +392,7 @@
 
     for (;;) {
         renderFrame();
+        setSurfaceMetadata(dpy, surface);
         eglSwapBuffers(dpy, surface);
         checkEglError("eglSwapBuffers");
     }
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
index af65b5f..b0081c2 100644
--- a/opengl/tests/gl2_jni/Android.mk
+++ b/opengl/tests/gl2_jni/Android.mk
@@ -37,13 +37,13 @@
   gl_code.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libutils \
 	liblog \
 	libEGL \
 	libGLESv2
 
 LOCAL_MODULE := libgl2jni
 
+LOCAL_SDK_VERSION := current
 
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gl2_jni/jni/gl_code.cpp b/opengl/tests/gl2_jni/jni/gl_code.cpp
index 5af4f6b..9b22c6c 100644
--- a/opengl/tests/gl2_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl2_jni/jni/gl_code.cpp
@@ -2,7 +2,12 @@
 
 #include <jni.h>
 #define LOG_TAG "GL2JNI gl_code.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
+
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp
index a675c7c..63d94be 100644
--- a/opengl/tests/gl_basic/gl_basic.cpp
+++ b/opengl/tests/gl_basic/gl_basic.cpp
@@ -15,6 +15,8 @@
 
 using namespace android;
 
+#define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
+
 EGLDisplay eglDisplay;
 EGLSurface eglSurface;
 EGLContext eglContext;
@@ -330,6 +332,39 @@
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 }
 
+void setSurfaceMetadata(EGLDisplay dpy, EGLSurface surface) {
+    static EGLBoolean toggle = GL_FALSE;
+    if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_SMPTE2086_metadata")) {
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, METADATA_SCALE(0.640));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, METADATA_SCALE(0.330));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, METADATA_SCALE(0.290));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, METADATA_SCALE(0.600));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, METADATA_SCALE(0.150));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, METADATA_SCALE(0.060));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_X_EXT, METADATA_SCALE(0.3127));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, METADATA_SCALE(0.3290));
+        if (toggle) {
+            eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(350));
+        } else {
+            eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(300));
+        }
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, METADATA_SCALE(0.7));
+    }
+
+    if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_CTA861_3_metadata")) {
+        if (toggle) {
+            eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                             METADATA_SCALE(300));
+        } else {
+            eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                             METADATA_SCALE(325));
+        }
+        eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT,
+                         METADATA_SCALE(75));
+    }
+    toggle = !toggle;
+}
+
 void render()
 {
     const GLfloat vertices[] = {
@@ -354,5 +389,6 @@
     int nelem = sizeof(indices)/sizeof(indices[0]);
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, indices);
+    setSurfaceMetadata(eglDisplay, eglSurface);
     eglSwapBuffers(eglDisplay, eglSurface);
 }
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
index 570ae2b..d64dfcf 100644
--- a/opengl/tests/gl_jni/Android.mk
+++ b/opengl/tests/gl_jni/Android.mk
@@ -37,13 +37,14 @@
   gl_code.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libutils \
 	liblog \
 	libEGL \
 	libGLESv1_CM
 
 LOCAL_MODULE := libgljni
 
+LOCAL_SDK_VERSION := current
+
 LOCAL_ARM_MODE := arm
 
 
diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp
index 3aa8adb..88f3228 100644
--- a/opengl/tests/gl_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl_jni/jni/gl_code.cpp
@@ -2,7 +2,12 @@
 
 #include <jni.h>
 #define LOG_TAG "GLJNI gl_code.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
+
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
 #include <GLES/gl.h>
 
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
index 854b54f..3f411ea 100644
--- a/opengl/tests/gl_perfapp/Android.mk
+++ b/opengl/tests/gl_perfapp/Android.mk
@@ -39,11 +39,12 @@
   gl_code.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libutils \
 	liblog \
 	libEGL \
 	libGLESv2
 
+LOCAL_SDK_VERSION := current
+
 LOCAL_MODULE := libglperf
 
 
diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp
index 0cb594a..bd1fd83 100644
--- a/opengl/tests/gl_perfapp/jni/gl_code.cpp
+++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp
@@ -2,16 +2,21 @@
 
 #include <jni.h>
 #define LOG_TAG "GLPerf gl_code.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
+
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
-#include <utils/Timers.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
+#include <time.h>
 
 #include "../../gl_perf/fill_common.cpp"
 
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
index dc265b6..5bdc0a8 100644
--- a/opengl/tests/gldual/Android.mk
+++ b/opengl/tests/gldual/Android.mk
@@ -37,13 +37,13 @@
   gl_code.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libutils \
 	liblog \
 	libEGL \
 	libGLESv2
 
 LOCAL_MODULE := libgldualjni
 
+LOCAL_SDK_VERSION := current
 
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gldual/jni/gl_code.cpp b/opengl/tests/gldual/jni/gl_code.cpp
index 90d150b..4e44976 100644
--- a/opengl/tests/gldual/jni/gl_code.cpp
+++ b/opengl/tests/gldual/jni/gl_code.cpp
@@ -2,7 +2,12 @@
 
 #include <jni.h>
 #define LOG_TAG "GL2JNI gl_code.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
+
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index c6cf111..4d32ea6 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -52,6 +52,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <utils/Trace.h>
@@ -69,28 +70,32 @@
 
 // Default input dispatching timeout if there is no focused application or paused window
 // from which to determine an appropriate dispatching timeout.
-const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
+constexpr nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
 
 // Amount of time to allow for all pending events to be processed when an app switch
 // key is on the way.  This is used to preempt input dispatch and drop input events
 // when an application takes too long to respond and the user has pressed an app switch key.
-const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
+constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
 
 // Amount of time to allow for an event to be dispatched (measured since its eventTime)
 // before considering it stale and dropping it.
-const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
+constexpr nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
 
 // Amount of time to allow touch events to be streamed out to a connection before requiring
 // that the first event be finished.  This value extends the ANR timeout by the specified
 // amount.  For example, if streaming is allowed to get ahead by one second relative to the
 // queue of waiting unfinished events, then ANRs will similarly be delayed by one second.
-const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec
+constexpr nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec
 
 // Log a warning when an event takes longer than this to process, even if an ANR does not occur.
-const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
+constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
+
+// Log a warning when an interception call takes longer than this to process.
+constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms;
 
 // Number of recent events to keep for debugging purposes.
-const size_t RECENT_QUEUE_MAX_SIZE = 10;
+constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;
+
 
 static inline nsecs_t now() {
     return systemTime(SYSTEM_TIME_MONOTONIC);
@@ -2449,7 +2454,12 @@
             flags, keyCode, args->scanCode, metaState, 0,
             args->downTime, args->eventTime);
 
+    android::base::Timer t;
     mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
+    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+        ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
+                std::to_string(t.duration().count()).c_str());
+    }
 
     bool needWake;
     { // acquire lock
@@ -2519,7 +2529,13 @@
 
     uint32_t policyFlags = args->policyFlags;
     policyFlags |= POLICY_FLAG_TRUSTED;
+
+    android::base::Timer t;
     mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
+    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+        ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
+                std::to_string(t.duration().count()).c_str());
+    }
 
     bool needWake;
     { // acquire lock
@@ -2630,7 +2646,12 @@
         }
 
         if (!(policyFlags & POLICY_FLAG_FILTERED)) {
+            android::base::Timer t;
             mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
+            if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+                ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
+                        std::to_string(t.duration().count()).c_str());
+            }
         }
 
         mLock.lock();
@@ -2655,7 +2676,12 @@
 
         if (!(policyFlags & POLICY_FLAG_FILTERED)) {
             nsecs_t eventTime = motionEvent->getEventTime();
+            android::base::Timer t;
             mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags);
+            if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+                ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
+                        std::to_string(t.duration().count()).c_str());
+            }
         }
 
         mLock.lock();
@@ -3543,8 +3569,13 @@
 
     mLock.unlock();
 
+    android::base::Timer t;
     nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
             &event, entry->policyFlags);
+    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+        ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
+                std::to_string(t.duration().count()).c_str());
+    }
 
     mLock.lock();
 
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 8a35509..b1d5e61 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -12,7 +12,7 @@
         "-Werror",
         "-Wno-unused-parameter",
     ],
-    shared_libs = [
+    shared_libs: [
         "libcutils",
         "liblog",
         "libutils",
diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS
index 6a38a1f..d4393d6 100644
--- a/services/sensorservice/OWNERS
+++ b/services/sensorservice/OWNERS
@@ -1,2 +1,2 @@
-ashutoshj@google.com
-pengxu@google.com
+arthuri@google.com
+bduddie@google.com
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c32ffb9..2bd0a19 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -24,6 +24,7 @@
 #include <cutils/properties.h>
 #include <hardware/sensors.h>
 #include <hardware_legacy/power.h>
+#include <log/log.h>
 #include <openssl/digest.h>
 #include <openssl/hmac.h>
 #include <openssl/rand.h>
@@ -1093,10 +1094,15 @@
     // check specific to memory type
     switch(type) {
         case SENSOR_DIRECT_MEM_TYPE_ASHMEM: { // channel backed by ashmem
+            if (resource->numFds < 1) {
+                ALOGE("Ashmem direct channel requires a memory region to be supplied");
+                android_errorWriteLog(0x534e4554, "70986337");  // SafetyNet
+                return nullptr;
+            }
             int fd = resource->data[0];
             int size2 = ashmem_get_size_region(fd);
             // check size consistency
-            if (size2 < static_cast<int>(size)) {
+            if (size2 < static_cast<int64_t>(size)) {
                 ALOGE("Ashmem direct channel size %" PRIu32 " greater than shared memory size %d",
                       size, size2);
                 return nullptr;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ae34d34..eeeba2e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -24,6 +24,7 @@
         "android.hardware.configstore@1.0",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
         "android.hardware.power@1.0",
         "libbase",
         "libbinder",
@@ -57,6 +58,7 @@
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
     ],
     export_static_lib_headers: [
         "libserviceutils",
@@ -64,6 +66,7 @@
     export_shared_lib_headers: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
         "libhidlbase",
         "libhidltransport",
         "libhwbinder",
@@ -73,8 +76,8 @@
 cc_library_headers {
     name: "libsurfaceflinger_headers",
     export_include_dirs: ["."],
-    static_libs = ["libserviceutils"],
-    export_static_lib_headers = ["libserviceutils"],
+    static_libs: ["libserviceutils"],
+    export_static_lib_headers: ["libserviceutils"],
 }
 
 filegroup {
@@ -101,6 +104,7 @@
         "Layer.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
+        "LayerStats.cpp",
         "LayerVector.cpp",
         "MessageQueue.cpp",
         "MonitoredProducer.cpp",
@@ -139,7 +143,7 @@
         "frameworks/native/vulkan/include",
     ],
     cppflags: [
-        "-fwhole-program-vtables",  // requires ThinLTO
+        "-fwhole-program-vtables", // requires ThinLTO
     ],
     lto: {
         thin: true,
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 3dbc136..ec47551 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -98,15 +98,13 @@
 }
 
 bool BufferLayer::isProtected() const {
-    const sp<GraphicBuffer>& buffer(getBE().compositionInfo.mBuffer);
-    return (buffer != 0) &&
-            (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    const sp<GraphicBuffer>& buffer(mActiveBuffer);
+    return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
 }
 
 bool BufferLayer::isVisible() const {
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
-            (getBE().compositionInfo.mBuffer != nullptr ||
-             getBE().compositionInfo.hwc.sidebandStream != nullptr);
+            (mActiveBuffer != nullptr || getBE().compositionInfo.hwc.sidebandStream != nullptr);
 }
 
 bool BufferLayer::isFixedSize() const {
@@ -162,7 +160,7 @@
                          bool useIdentityTransform) const {
     ATRACE_CALL();
 
-    if (CC_UNLIKELY(getBE().compositionInfo.mBuffer == 0)) {
+    if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -240,8 +238,7 @@
         }
 
         // Set things up for texturing.
-        mTexture.setDimensions(getBE().compositionInfo.mBuffer->getWidth(),
-                               getBE().compositionInfo.mBuffer->getHeight());
+        mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
         mTexture.setFiltering(useFiltering);
         mTexture.setMatrix(textureMatrix);
 
@@ -291,12 +288,10 @@
 bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
     if (mBufferLatched) {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPreComposition(mCurrentFrameNumber,
-                                             refreshStartTime);
+        mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
     }
     mRefreshPending = false;
-    return mQueuedFrames > 0 || mSidebandStreamChanged ||
-            mAutoRefresh;
+    return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
 }
 bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
                                     const std::shared_ptr<FenceTime>& presentFence,
@@ -308,8 +303,8 @@
     // Update mFrameEventHistory.
     {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence,
-                                              presentFence, compositorTiming);
+        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
+                                              compositorTiming);
     }
 
     // Update mFrameTracker.
@@ -358,8 +353,7 @@
         return;
     }
 
-    auto releaseFenceTime =
-            std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
+    auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
     mReleaseTimeline.updateSignalTimes();
     mReleaseTimeline.push(releaseFenceTime);
 
@@ -412,7 +406,7 @@
     // Capture the old state of the layer for comparisons later
     const State& s(getDrawingState());
     const bool oldOpacity = isOpaque(s);
-    sp<GraphicBuffer> oldBuffer = getBE().compositionInfo.mBuffer;
+    sp<GraphicBuffer> oldBuffer = mActiveBuffer;
 
     if (!allTransactionsSignaled()) {
         mFlinger->signalLayerUpdate();
@@ -425,12 +419,10 @@
     // buffer mode.
     bool queuedBuffer = false;
     LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
-                    getProducerStickyTransform() != 0, mName.string(),
-                    mOverrideScalingMode, mFreezeGeometryUpdates);
-    status_t updateResult =
-            mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
-                                                    &mAutoRefresh, &queuedBuffer,
-                                                    mLastFrameNumberReceived);
+                    getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+                    mFreezeGeometryUpdates);
+    status_t updateResult = mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, &mAutoRefresh,
+                                                      &queuedBuffer, mLastFrameNumberReceived);
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
@@ -483,17 +475,16 @@
 
     // Decrement the queued-frames count.  Signal another event if we
     // have more frames pending.
-    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) ||
-        mAutoRefresh) {
+    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) {
         mFlinger->signalLayerUpdate();
     }
 
     // update the active buffer
-    getBE().compositionInfo.mBuffer =
-            mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
-    // replicated in LayerBE until FE/BE is ready to be synchronized
-    mActiveBuffer = getBE().compositionInfo.mBuffer;
-    if (getBE().compositionInfo.mBuffer == nullptr) {
+    mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
+    getBE().compositionInfo.mBuffer = mActiveBuffer;
+    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
+
+    if (mActiveBuffer == nullptr) {
         // this can only happen if the very first buffer was rejected.
         return outDirtyRegion;
     }
@@ -520,8 +511,7 @@
     Rect crop(mConsumer->getCurrentCrop());
     const uint32_t transform(mConsumer->getCurrentTransform());
     const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
-    if ((crop != mCurrentCrop) ||
-        (transform != mCurrentTransform) ||
+    if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
         (scalingMode != mCurrentScalingMode)) {
         mCurrentCrop = crop;
         mCurrentTransform = transform;
@@ -530,15 +520,14 @@
     }
 
     if (oldBuffer != nullptr) {
-        uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth();
-        uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight();
-        if (bufWidth != uint32_t(oldBuffer->width) ||
-            bufHeight != uint32_t(oldBuffer->height)) {
+        uint32_t bufWidth = mActiveBuffer->getWidth();
+        uint32_t bufHeight = mActiveBuffer->getHeight();
+        if (bufWidth != uint32_t(oldBuffer->width) || bufHeight != uint32_t(oldBuffer->height)) {
             recomputeVisibleRegions = true;
         }
     }
 
-    mCurrentOpacity = getOpacityForFormat(getBE().compositionInfo.mBuffer->format);
+    mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
     if (oldOpacity != isOpaque(s)) {
         recomputeVisibleRegions = true;
     }
@@ -629,10 +618,17 @@
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
+    const HdrMetadata& metadata = mConsumer->getCurrentHdrMetadata();
+    error = hwcLayer->setHdrMetadata(metadata);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    }
+
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
-                                     getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);
+    getBE().mHwcLayers[hwcId].bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot,
+                                                       &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
@@ -646,7 +642,7 @@
 bool BufferLayer::isOpaque(const Layer::State& s) const {
     // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
     // layer's opaque flag.
-    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (getBE().compositionInfo.mBuffer == nullptr)) {
+    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
         return false;
     }
 
@@ -661,8 +657,7 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer, true);
     mProducer = new MonitoredProducer(producer, mFlinger, this);
-    mConsumer = new BufferLayerConsumer(consumer,
-            mFlinger->getRenderEngine(), mTextureName, this);
+    mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
     mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mConsumer->setContentsChangedListener(this);
     mConsumer->setName(mName);
@@ -694,8 +689,7 @@
 
         // Ensure that callbacks are handled in order
         while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                                                               ms2ns(500));
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
             if (result != NO_ERROR) {
                 ALOGE("[%s] Timed out waiting on callback", mName.string());
             }
@@ -718,8 +712,7 @@
 
         // Ensure that callbacks are handled in order
         while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                                                               ms2ns(500));
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
             if (result != NO_ERROR) {
                 ALOGE("[%s] Timed out waiting on callback", mName.string());
             }
@@ -884,8 +877,7 @@
         // able to be latched. To avoid this, grab this buffer anyway.
         return true;
     }
-    return mQueueItems[0].mFenceTime->getSignalTime() !=
-            Fence::SIGNAL_TIME_PENDING;
+    return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
 }
 
 uint32_t BufferLayer::getEffectiveScalingMode() const {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 03b714f..bb720f7 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -19,15 +19,23 @@
 
 #include <inttypes.h>
 #include <log/log.h>
-#include <gui/BufferQueue.h>
 
 #include "ComposerHal.h"
 
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <gui/BufferQueue.h>
+#include <hidl/HidlTransportUtils.h>
+
 namespace android {
 
 using hardware::Return;
 using hardware::hidl_vec;
 using hardware::hidl_handle;
+using namespace hardware::graphics::composer;
+using PerFrameMetadata = hardware::graphics::composer::V2_2::IComposerClient::PerFrameMetadata;
+using PerFrameMetadataKey =
+        hardware::graphics::composer::V2_2::IComposerClient::PerFrameMetadataKey;
 
 namespace Hwc2 {
 
@@ -117,10 +125,9 @@
 void Composer::CommandWriter::setLayerInfo(uint32_t type, uint32_t appId)
 {
     constexpr uint16_t kSetLayerInfoLength = 2;
-    beginCommand(
-        static_cast<IComposerClient::Command>(
-            IVrComposerClient::VrCommand::SET_LAYER_INFO),
-        kSetLayerInfoLength);
+    beginCommand(static_cast<hardware::graphics::composer::V2_1::IComposerClient::Command>(
+                         IVrComposerClient::VrCommand::SET_LAYER_INFO),
+                 kSetLayerInfoLength);
     write(type);
     write(appId);
     endCommand();
@@ -130,10 +137,9 @@
         const IVrComposerClient::BufferMetadata& metadata)
 {
     constexpr uint16_t kSetClientTargetMetadataLength = 7;
-    beginCommand(
-        static_cast<IComposerClient::Command>(
-            IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA),
-        kSetClientTargetMetadataLength);
+    beginCommand(static_cast<hardware::graphics::composer::V2_1::IComposerClient::Command>(
+                         IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA),
+                 kSetClientTargetMetadataLength);
     writeBufferMetadata(metadata);
     endCommand();
 }
@@ -142,10 +148,9 @@
         const IVrComposerClient::BufferMetadata& metadata)
 {
     constexpr uint16_t kSetLayerBufferMetadataLength = 7;
-    beginCommand(
-        static_cast<IComposerClient::Command>(
-            IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA),
-        kSetLayerBufferMetadataLength);
+    beginCommand(static_cast<hardware::graphics::composer::V2_1::IComposerClient::Command>(
+                         IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA),
+                 kSetLayerBufferMetadataLength);
     writeBufferMetadata(metadata);
     endCommand();
 }
@@ -182,6 +187,13 @@
         LOG_ALWAYS_FATAL("failed to create composer client");
     }
 
+    // 2.2 support is optional
+    sp<V2_2::IComposer> composer_2_2 = V2_2::IComposer::castFrom(mComposer);
+    if (composer_2_2 != nullptr) {
+        mClient_2_2 = IComposerClient::castFrom(mClient);
+        LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2");
+    }
+
     if (mIsUsingVrComposer) {
         sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
         if (vrClient == nullptr) {
@@ -451,6 +463,25 @@
     return error;
 }
 
+Error Composer::getPerFrameMetadataKeys(
+        Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
+    if (!mClient_2_2) {
+        return Error::UNSUPPORTED;
+    }
+
+    Error error = kDefaultError;
+    mClient_2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
+        error = tmpError;
+        if (error != Error::NONE) {
+            return;
+        }
+
+        *outKeys = tmpKeys;
+    });
+
+    return error;
+}
+
 Error Composer::getReleaseFences(Display display,
         std::vector<Layer>* outLayers, std::vector<int>* outReleaseFences)
 {
@@ -530,7 +561,15 @@
 
 Error Composer::setPowerMode(Display display, IComposerClient::PowerMode mode)
 {
-    auto ret = mClient->setPowerMode(display, mode);
+    hardware::Return<Error> ret(Error::UNSUPPORTED);
+    if (mClient_2_2) {
+        ret = mClient_2_2->setPowerMode_2_2(display, mode);
+    } else if (mode != IComposerClient::PowerMode::ON_SUSPEND) {
+        ret = mClient->setPowerMode(display,
+                                    static_cast<hardware::graphics::composer::V2_1::
+                                                        IComposerClient::PowerMode>(mode));
+    }
+
     return unwrapRet(ret);
 }
 
@@ -666,6 +705,44 @@
     return Error::NONE;
 }
 
+Error Composer::setLayerHdrMetadata(Display display, Layer layer, const HdrMetadata& metadata) {
+
+    mWriter.selectDisplay(display);
+    mWriter.selectLayer(layer);
+
+    std::vector<PerFrameMetadata> composerMetadata;
+    if (metadata.validTypes & HdrMetadata::SMPTE2086) {
+        composerMetadata
+                .insert(composerMetadata.end(),
+                        {{PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
+                          metadata.smpte2086.displayPrimaryRed.x},
+                         {PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
+                          metadata.smpte2086.displayPrimaryRed.y},
+                         {PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
+                          metadata.smpte2086.displayPrimaryGreen.x},
+                         {PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y,
+                          metadata.smpte2086.displayPrimaryGreen.y},
+                         {PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X,
+                          metadata.smpte2086.displayPrimaryBlue.x},
+                         {PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y,
+                          metadata.smpte2086.displayPrimaryBlue.y},
+                         {PerFrameMetadataKey::WHITE_POINT_X, metadata.smpte2086.whitePoint.x},
+                         {PerFrameMetadataKey::WHITE_POINT_Y, metadata.smpte2086.whitePoint.y},
+                         {PerFrameMetadataKey::MAX_LUMINANCE, metadata.smpte2086.maxLuminance},
+                         {PerFrameMetadataKey::MIN_LUMINANCE, metadata.smpte2086.minLuminance}});
+    }
+    if (metadata.validTypes & HdrMetadata::CTA861_3) {
+        composerMetadata.insert(composerMetadata.end(),
+                                {{PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
+                                  metadata.cta8613.maxContentLightLevel},
+                                 {PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
+                                  metadata.cta8613.maxFrameAverageLightLevel}});
+    }
+
+    mWriter.setPerFrameMetadata(composerMetadata);
+    return Error::NONE;
+}
+
 Error Composer::setLayerDisplayFrame(Display display, Layer layer,
         const IComposerClient::Rect& frame)
 {
@@ -810,7 +887,8 @@
             mReader.takeErrors();
 
         for (const auto& cmdErr : commandErrors) {
-            auto command = mWriter.getCommand(cmdErr.location);
+            auto command =
+                    static_cast<IComposerClient::Command>(mWriter.getCommand(cmdErr.location));
 
             if (command == IComposerClient::Command::VALIDATE_DISPLAY ||
                 command == IComposerClient::Command::PRESENT_DISPLAY ||
@@ -841,7 +919,10 @@
     uint16_t length = 0;
 
     while (!isEmpty()) {
-        if (!beginCommand(&command, &length)) {
+        auto command_2_1 =
+                reinterpret_cast<hardware::graphics::composer::V2_1::IComposerClient::Command*>(
+                        &command);
+        if (!beginCommand(command_2_1, &length)) {
             break;
         }
 
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 77675fb..c0373aa 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -24,8 +24,10 @@
 #include <vector>
 
 #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
-#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <gui/HdrMetadata.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
 
@@ -42,16 +44,16 @@
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::hardware::graphics::common::V1_0::Transform;
 
+using android::hardware::graphics::composer::V2_1::Config;
+using android::hardware::graphics::composer::V2_1::Display;
+using android::hardware::graphics::composer::V2_1::Error;
 using android::hardware::graphics::composer::V2_1::IComposer;
 using android::hardware::graphics::composer::V2_1::IComposerCallback;
-using android::hardware::graphics::composer::V2_1::IComposerClient;
-using android::hardware::graphics::composer::V2_1::Error;
-using android::hardware::graphics::composer::V2_1::Display;
 using android::hardware::graphics::composer::V2_1::Layer;
-using android::hardware::graphics::composer::V2_1::Config;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
 
-using android::hardware::graphics::composer::V2_1::CommandWriterBase;
-using android::hardware::graphics::composer::V2_1::CommandReaderBase;
+using android::hardware::graphics::composer::V2_2::CommandReaderBase;
+using android::hardware::graphics::composer::V2_2::CommandWriterBase;
 
 using android::hardware::kSynchronizedReadWrite;
 using android::hardware::MessageQueue;
@@ -111,6 +113,9 @@
                                      float* outMaxLuminance, float* outMaxAverageLuminance,
                                      float* outMinLuminance) = 0;
 
+    virtual Error getPerFrameMetadataKeys(
+            Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0;
+
     virtual Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
                                    std::vector<int>* outReleaseFences) = 0;
 
@@ -155,6 +160,8 @@
     virtual Error setLayerCompositionType(Display display, Layer layer,
                                           IComposerClient::Composition type) = 0;
     virtual Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) = 0;
+    virtual Error setLayerHdrMetadata(Display display, Layer layer,
+                                      const HdrMetadata& metadata) = 0;
     virtual Error setLayerDisplayFrame(Display display, Layer layer,
                                        const IComposerClient::Rect& frame) = 0;
     virtual Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) = 0;
@@ -298,6 +305,9 @@
     Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
                              float* outMaxAverageLuminance, float* outMinLuminance) override;
 
+    Error getPerFrameMetadataKeys(
+            Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override;
+
     Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
                            std::vector<int>* outReleaseFences) override;
 
@@ -339,6 +349,7 @@
     Error setLayerCompositionType(Display display, Layer layer,
                                   IComposerClient::Composition type) override;
     Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) override;
+    Error setLayerHdrMetadata(Display display, Layer layer, const HdrMetadata& metadata) override;
     Error setLayerDisplayFrame(Display display, Layer layer,
                                const IComposerClient::Rect& frame) override;
     Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
@@ -375,7 +386,8 @@
     Error execute();
 
     sp<IComposer> mComposer;
-    sp<IComposerClient> mClient;
+    sp<hardware::graphics::composer::V2_1::IComposerClient> mClient;
+    sp<IComposerClient> mClient_2_2;
 
     // 64KiB minus a small space for metadata such as read/write pointers
     static constexpr size_t kWriterInitialSize =
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 814b55e..f14c2fe 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -37,6 +37,7 @@
 using android::FloatRect;
 using android::GraphicBuffer;
 using android::HdrCapabilities;
+using android::HdrMetadata;
 using android::Rect;
 using android::Region;
 using android::sp;
@@ -687,8 +688,7 @@
 
 // Layer methods
 
-Layer::Layer(android::Hwc2::Composer& composer,
-             const std::unordered_set<Capability>& capabilities,
+Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
              hwc2_display_t displayId, hwc2_layer_t layerId)
   : mComposer(composer),
     mCapabilities(capabilities),
@@ -788,6 +788,16 @@
     return static_cast<Error>(intError);
 }
 
+Error Layer::setHdrMetadata(const android::HdrMetadata& metadata) {
+    if (metadata == mHdrMetadata) {
+        return Error::None;
+    }
+
+    mHdrMetadata = metadata;
+    auto intError = mComposer.setLayerHdrMetadata(mDisplayId, mId, metadata);
+    return static_cast<Error>(intError);
+}
+
 Error Layer::setDisplayFrame(const Rect& frame)
 {
     Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top,
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index aade4e0..e74f00d 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,8 +23,9 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
-#include <ui/HdrCapabilities.h>
+#include <gui/HdrMetadata.h>
 #include <math/mat4.h>
+#include <ui/HdrCapabilities.h>
 
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
@@ -306,6 +307,7 @@
     [[clang::warn_unused_result]] Error setCompositionType(Composition type);
     [[clang::warn_unused_result]] Error setDataspace(
             android_dataspace_t dataspace);
+    [[clang::warn_unused_result]] Error setHdrMetadata(const android::HdrMetadata& metadata);
     [[clang::warn_unused_result]] Error setDisplayFrame(
             const android::Rect& frame);
     [[clang::warn_unused_result]] Error setPlaneAlpha(float alpha);
@@ -329,6 +331,7 @@
     hwc2_display_t mDisplayId;
     hwc2_layer_t mId;
     android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+    android::HdrMetadata mHdrMetadata;
     std::function<void(Layer*)> mLayerDestroyedListener;
 };
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
deleted file mode 100644
index fe7944f..0000000
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SF_HWCOMPOSER_HWC1_H
-#define ANDROID_SF_HWCOMPOSER_HWC1_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <hardware/hwcomposer_defs.h>
-
-#include <system/graphics.h>
-
-#include <ui/Fence.h>
-
-#include <utils/BitSet.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <utils/StrongPointer.h>
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
-                           const struct timespec *request,
-                           struct timespec *remain);
-
-struct hwc_composer_device_1;
-struct hwc_display_contents_1;
-struct hwc_layer_1;
-struct hwc_procs;
-struct framebuffer_device_t;
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Fence;
-class FloatRect;
-class GraphicBuffer;
-class NativeHandle;
-class Region;
-class String8;
-class SurfaceFlinger;
-
-class HWComposer
-{
-public:
-    class EventHandler {
-        friend class HWComposer;
-        virtual void onVSyncReceived(
-            HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
-        virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected) = 0;
-        virtual void onInvalidateReceived(HWComposer* composer) = 0;
-    protected:
-        virtual ~EventHandler() {}
-    };
-
-    enum {
-        NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
-        MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES,
-        VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL,
-    };
-
-    HWComposer(
-            const sp<SurfaceFlinger>& flinger,
-            EventHandler& handler);
-
-    ~HWComposer();
-
-    status_t initCheck() const;
-
-    // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to
-    // be used with createWorkList (and all other methods requiring an ID
-    // below).
-    // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are
-    // always valid.
-    // Returns -1 if an ID cannot be allocated
-    int32_t allocateDisplayId();
-
-    // Recycles the given virtual display ID and frees the associated worklist.
-    // IDs below NUM_BUILTIN_DISPLAYS are not recycled.
-    status_t freeDisplayId(int32_t id);
-
-
-    // Asks the HAL what it can do
-    status_t prepare();
-
-    // commits the list
-    status_t commit();
-
-    // set power mode
-    status_t setPowerMode(int disp, int mode);
-
-    // set active config
-    status_t setActiveConfig(int disp, int mode);
-
-    // reset state when an external, non-virtual display is disconnected
-    void disconnectDisplay(int disp);
-
-    // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
-    status_t createWorkList(int32_t id, size_t numLayers);
-
-    bool supportsFramebufferTarget() const;
-
-    // does this display have layers handled by HWC
-    bool hasHwcComposition(int32_t id) const;
-
-    // does this display have layers handled by GLES
-    bool hasGlesComposition(int32_t id) const;
-
-    // get the releaseFence file descriptor for a display's framebuffer layer.
-    // the release fence is only valid after commit()
-    sp<Fence> getAndResetReleaseFence(int32_t id);
-
-    // needed forward declarations
-    class LayerListIterator;
-
-    // return the visual id to be used to find a suitable EGLConfig for
-    // *ALL* displays.
-    int getVisualID() const;
-
-    // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
-    int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
-    int fbCompositionComplete();
-    void fbDump(String8& result);
-
-    // Set the output buffer and acquire fence for a virtual display.
-    // Returns INVALID_OPERATION if id is not a virtual display.
-    status_t setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
-            const sp<GraphicBuffer>& buf);
-
-    // Get the retire fence for the last committed frame. This fence will
-    // signal when the h/w composer is completely finished with the frame.
-    // For physical displays, it is no longer being displayed. For virtual
-    // displays, writes to the output buffer are complete.
-    sp<Fence> getLastRetireFence(int32_t id) const;
-
-    status_t setCursorPositionAsync(int32_t id, const Rect &pos);
-
-    /*
-     * Interface to hardware composer's layers functionality.
-     * This abstracts the HAL interface to layers which can evolve in
-     * incompatible ways from one release to another.
-     * The idea is that we could extend this interface as we add
-     * features to h/w composer.
-     */
-    class HWCLayerInterface {
-    protected:
-        virtual ~HWCLayerInterface() { }
-    public:
-        virtual int32_t getCompositionType() const = 0;
-        virtual uint32_t getHints() const = 0;
-        virtual sp<Fence> getAndResetReleaseFence() = 0;
-        virtual void setDefaultState() = 0;
-        virtual void setSkip(bool skip) = 0;
-        virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
-        virtual void setBlending(uint32_t blending) = 0;
-        virtual void setTransform(uint32_t transform) = 0;
-        virtual void setFrame(const Rect& frame) = 0;
-        virtual void setCrop(const FloatRect& crop) = 0;
-        virtual void setVisibleRegionScreen(const Region& reg) = 0;
-        virtual void setSurfaceDamage(const Region& reg) = 0;
-        virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
-        virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
-        virtual void setAcquireFenceFd(int fenceFd) = 0;
-        virtual void setPlaneAlpha(uint8_t alpha) = 0;
-        virtual void onDisplayed() = 0;
-    };
-
-    /*
-     * Interface used to implement an iterator to a list
-     * of HWCLayer.
-     */
-    class HWCLayer : public HWCLayerInterface {
-        friend class LayerListIterator;
-        // select the layer at the given index
-        virtual status_t setLayer(size_t index) = 0;
-        virtual HWCLayer* dup() = 0;
-        static HWCLayer* copy(HWCLayer *rhs) {
-            return rhs ? rhs->dup() : nullptr;
-        }
-    protected:
-        virtual ~HWCLayer() { }
-    };
-
-    /*
-     * Iterator through a HWCLayer list.
-     * This behaves more or less like a forward iterator.
-     */
-    class LayerListIterator {
-        friend class HWComposer;
-        HWCLayer* const mLayerList;
-        size_t mIndex;
-
-        LayerListIterator() : mLayerList(nullptr), mIndex(0) { }
-
-        LayerListIterator(HWCLayer* layer, size_t index)
-            : mLayerList(layer), mIndex(index) { }
-
-        // we don't allow assignment, because we don't need it for now
-        LayerListIterator& operator = (const LayerListIterator& rhs);
-
-    public:
-        // copy operators
-        LayerListIterator(const LayerListIterator& rhs)
-            : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
-        }
-
-        ~LayerListIterator() { delete mLayerList; }
-
-        // pre-increment
-        LayerListIterator& operator++() {
-            mLayerList->setLayer(++mIndex);
-            return *this;
-        }
-
-        // dereference
-        HWCLayerInterface& operator * () { return *mLayerList; }
-        HWCLayerInterface* operator -> () { return mLayerList; }
-
-        // comparison
-        bool operator == (const LayerListIterator& rhs) const {
-            return mIndex == rhs.mIndex;
-        }
-        bool operator != (const LayerListIterator& rhs) const {
-            return !operator==(rhs);
-        }
-    };
-
-    // Returns an iterator to the beginning of the layer list
-    LayerListIterator begin(int32_t id);
-
-    // Returns an iterator to the end of the layer list
-    LayerListIterator end(int32_t id);
-
-
-    // Events handling ---------------------------------------------------------
-
-    enum {
-        EVENT_VSYNC = HWC_EVENT_VSYNC
-    };
-
-    void eventControl(int disp, int event, int enabled);
-
-    struct DisplayConfig {
-        uint32_t width;
-        uint32_t height;
-        float xdpi;
-        float ydpi;
-        nsecs_t refresh;
-        android_color_mode_t colorMode;
-        bool operator==(const DisplayConfig& rhs) const {
-            return width == rhs.width &&
-                    height == rhs.height &&
-                    xdpi == rhs.xdpi &&
-                    ydpi == rhs.ydpi &&
-                    refresh == rhs.refresh &&
-                    colorMode == rhs.colorMode;
-        }
-    };
-
-    // Query display parameters.  Pass in a display index (e.g.
-    // HWC_DISPLAY_PRIMARY).
-    nsecs_t getRefreshTimestamp(int disp) const;
-    sp<Fence> getDisplayFence(int disp) const;
-    uint32_t getFormat(int disp) const;
-    bool isConnected(int disp) const;
-
-    // These return the values for the current config of a given display index.
-    // To get the values for all configs, use getConfigs below.
-    uint32_t getWidth(int disp) const;
-    uint32_t getHeight(int disp) const;
-    float getDpiX(int disp) const;
-    float getDpiY(int disp) const;
-    nsecs_t getRefreshPeriod(int disp) const;
-    android_color_mode_t getColorMode(int disp) const;
-
-    const Vector<DisplayConfig>& getConfigs(int disp) const;
-    size_t getCurrentConfig(int disp) const;
-
-    status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h,
-            uint32_t format);
-
-    // this class is only used to fake the VSync event on systems that don't
-    // have it.
-    class VSyncThread : public Thread {
-        HWComposer& mHwc;
-        mutable Mutex mLock;
-        Condition mCondition;
-        bool mEnabled;
-        mutable nsecs_t mNextFakeVSync;
-        nsecs_t mRefreshPeriod;
-        virtual void onFirstRef();
-        virtual bool threadLoop();
-    public:
-        VSyncThread(HWComposer& hwc);
-        void setEnabled(bool enabled);
-    };
-
-    friend class VSyncThread;
-
-    // for debugging ----------------------------------------------------------
-    void dump(String8& out) const;
-
-private:
-    void loadHwcModule();
-    int loadFbHalModule();
-
-    LayerListIterator getLayerIterator(int32_t id, size_t index);
-
-    struct cb_context;
-
-    static void hook_invalidate(const struct hwc_procs* procs);
-    static void hook_vsync(const struct hwc_procs* procs, int disp,
-            int64_t timestamp);
-    static void hook_hotplug(const struct hwc_procs* procs, int disp,
-            int connected);
-
-    inline void invalidate();
-    inline void vsync(int disp, int64_t timestamp);
-    inline void hotplug(int disp, int connected);
-
-    status_t queryDisplayProperties(int disp);
-
-    status_t setFramebufferTarget(int32_t id,
-            const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
-
-    struct DisplayData {
-        DisplayData();
-        ~DisplayData();
-        Vector<DisplayConfig> configs;
-        size_t currentConfig;
-        uint32_t format;    // pixel format from FB hal, for pre-hwc-1.1
-        bool connected;
-        bool hasFbComp;
-        bool hasOvComp;
-        size_t capacity;
-        hwc_display_contents_1* list;
-        hwc_layer_1* framebufferTarget;
-        buffer_handle_t fbTargetHandle;
-        sp<Fence> lastRetireFence;  // signals when the last set op retires
-        sp<Fence> lastDisplayFence; // signals when the last set op takes
-                                    // effect on screen
-        buffer_handle_t outbufHandle;
-        sp<Fence> outbufAcquireFence;
-
-        // protected by mEventControlLock
-        int32_t events;
-
-        // We need to hold "copies" of these for memory management purposes. The
-        // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
-        // internally doesn't copy the memory unless one of the copies is
-        // modified.
-        Vector<Region> visibleRegions;
-        Vector<Region> surfaceDamageRegions;
-    };
-
-    sp<SurfaceFlinger>              mFlinger;
-    framebuffer_device_t*           mFbDev;
-    struct hwc_composer_device_1*   mHwc;
-    // invariant: mLists[0] != nullptr iff mHwc != nullptr
-    // mLists[i>0] can be nullptr. that display is to be ignored
-    struct hwc_display_contents_1*  mLists[MAX_HWC_DISPLAYS];
-    DisplayData                     mDisplayData[MAX_HWC_DISPLAYS];
-    // protect mDisplayData from races between prepare and dump
-    mutable Mutex mDisplayLock;
-    size_t                          mNumDisplays;
-
-    cb_context*                     mCBContext;
-    EventHandler&                   mEventHandler;
-    size_t                          mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
-    sp<VSyncThread>                 mVSyncThread;
-    bool                            mDebugForceFakeVSync;
-    BitSet32                        mAllocatedDisplayIDs;
-
-    // protected by mLock
-    mutable Mutex mLock;
-    mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
-
-    // thread-safe
-    mutable Mutex mEventControlLock;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 78dd40b..6104230 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -639,6 +639,7 @@
         hwcInfo.forceClientComposition = true;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
+        hwcInfo.transform = transform;
         auto error = hwcLayer->setTransform(transform);
         ALOGE_IF(error != HWC2::Error::None,
                  "[%s] Failed to set transform %s: "
@@ -1440,7 +1441,7 @@
     info.mMatrix[1][0] = ds.active.transform[1][0];
     info.mMatrix[1][1] = ds.active.transform[1][1];
     {
-        sp<const GraphicBuffer> buffer = getBE().compositionInfo.mBuffer;
+        sp<const GraphicBuffer> buffer = mActiveBuffer;
         if (buffer != 0) {
             info.mActiveBufferWidth = buffer->getWidth();
             info.mActiveBufferHeight = buffer->getHeight();
@@ -1915,6 +1916,21 @@
     layerInfo->set_refresh_pending(isBufferLatched());
 }
 
+void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
+    writeToProto(layerInfo, LayerVector::StateSet::Drawing);
+
+    const auto& hwcInfo = getBE().mHwcLayers.at(hwcId);
+
+    const Rect& frame = hwcInfo.displayFrame;
+    LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+
+    const FloatRect& crop = hwcInfo.sourceCrop;
+    LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+
+    const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
+    layerInfo->set_hwc_transform(transform);
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3671a2b..9c4f1ce 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -42,6 +42,7 @@
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 #include "Transform.h"
+#include "LayerBE.h"
 
 #include <layerproto/LayerProtoHeader.h>
 #include "DisplayHardware/HWComposer.h"
@@ -68,68 +69,6 @@
 
 // ---------------------------------------------------------------------------
 
-struct CompositionInfo {
-    HWC2::Composition compositionType;
-    sp<GraphicBuffer> mBuffer = nullptr;
-    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
-    struct {
-        HWComposer* hwc;
-        sp<Fence> fence;
-        HWC2::BlendMode blendMode;
-        Rect displayFrame;
-        float alpha;
-        FloatRect sourceCrop;
-        HWC2::Transform transform;
-        int z;
-        int type;
-        int appId;
-        Region visibleRegion;
-        Region surfaceDamage;
-        sp<NativeHandle> sidebandStream;
-        android_dataspace dataspace;
-        hwc_color_t color;
-    } hwc;
-    struct {
-        RE::RenderEngine* renderEngine;
-        Mesh* mesh;
-    } renderEngine;
-};
-
-class LayerBE {
-public:
-    LayerBE();
-
-    // The mesh used to draw the layer in GLES composition mode
-    Mesh mMesh;
-
-    // HWC items, accessed from the main thread
-    struct HWCInfo {
-        HWCInfo()
-              : hwc(nullptr),
-                layer(nullptr),
-                forceClientComposition(false),
-                compositionType(HWC2::Composition::Invalid),
-                clearClientTarget(false) {}
-
-        HWComposer* hwc;
-        HWC2::Layer* layer;
-        bool forceClientComposition;
-        HWC2::Composition compositionType;
-        bool clearClientTarget;
-        Rect displayFrame;
-        FloatRect sourceCrop;
-        HWComposerBufferCache bufferCache;
-    };
-
-    // A layer can be attached to multiple displays when operating in mirror mode
-    // (a.k.a: when several displays are attached with equal layerStack). In this
-    // case we need to keep track. In non-mirror mode, a layer will have only one
-    // HWCInfo. This map key is a display layerStack.
-    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
-
-    CompositionInfo compositionInfo;
-};
-
 class Layer : public virtual RefBase {
     static int32_t sSequence;
 
@@ -351,6 +290,8 @@
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
 
+    void writeToProto(LayerProto* layerInfo, int32_t hwcId);
+
 protected:
     /*
      * onDraw - draws the surface.
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
new file mode 100644
index 0000000..d0cc8e7
--- /dev/null
+++ b/services/surfaceflinger/LayerBE.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/Region.h>
+
+#include "SurfaceFlinger.h"
+
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
+#include "RenderEngine/Mesh.h"
+
+namespace android {
+
+struct CompositionInfo {
+    HWC2::Composition compositionType;
+    sp<GraphicBuffer> mBuffer = nullptr;
+    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+    struct {
+        HWC2::Layer* hwcLayer;
+        int32_t hwid = -1;
+        sp<Fence> fence;
+        HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
+        Rect displayFrame;
+        float alpha;
+        FloatRect sourceCrop;
+        HWC2::Transform transform = HWC2::Transform::None;
+        int z;
+        int type;
+        int appId;
+        Region visibleRegion;
+        Region surfaceDamage;
+        sp<NativeHandle> sidebandStream;
+        android_dataspace dataspace;
+        hwc_color_t color;
+    } hwc;
+    struct {
+        Mesh* mesh;
+    } renderEngine;
+};
+
+class LayerBE {
+public:
+    LayerBE();
+
+    // The mesh used to draw the layer in GLES composition mode
+    Mesh mMesh;
+
+    // HWC items, accessed from the main thread
+    struct HWCInfo {
+        HWCInfo()
+              : hwc(nullptr),
+                layer(nullptr),
+                forceClientComposition(false),
+                compositionType(HWC2::Composition::Invalid),
+                clearClientTarget(false),
+                transform(HWC2::Transform::None) {}
+
+        HWComposer* hwc;
+        HWC2::Layer* layer;
+        bool forceClientComposition;
+        HWC2::Composition compositionType;
+        bool clearClientTarget;
+        Rect displayFrame;
+        FloatRect sourceCrop;
+        HWComposerBufferCache bufferCache;
+        HWC2::Transform transform;
+    };
+
+
+    // A layer can be attached to multiple displays when operating in mirror mode
+    // (a.k.a: when several displays are attached with equal layerStack). In this
+    // case we need to keep track. In non-mirror mode, a layer will have only one
+    // HWCInfo. This map key is a display layerStack.
+    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+
+    CompositionInfo compositionInfo;
+};
+
+}; // namespace android
+
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 6a33148..cc39550 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -37,6 +37,13 @@
     rectProto->set_right(rect.right);
 }
 
+void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
+    rectProto->set_left(rect.left);
+    rectProto->set_top(rect.top);
+    rectProto->set_bottom(rect.bottom);
+    rectProto->set_right(rect.right);
+}
+
 void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
     colorProto->set_r(color.r);
     colorProto->set_g(color.g);
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 45a0b5d..860da63 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -29,6 +29,7 @@
 class LayerProtoHelper {
 public:
     static void writeToProto(const Rect& rect, RectProto* rectProto);
+    static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
     static void writeToProto(const Region& region, RegionProto* regionProto);
     static void writeToProto(const half4 color, ColorProto* colorProto);
     static void writeToProto(const Transform& transform, TransformProto* transformProto);
@@ -36,4 +37,4 @@
 };
 
 } // namespace surfaceflinger
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
new file mode 100644
index 0000000..ea2542c
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+#undef LOG_TAG
+#define LOG_TAG "LayerStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LayerStats.h"
+#include "DisplayHardware/HWComposer.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+void LayerStats::enable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mEnabled) return;
+    mLayerStatsMap.clear();
+    mEnabled = true;
+    ALOGD("Logging enabled");
+}
+
+void LayerStats::disable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!mEnabled) return;
+    mEnabled = false;
+    ALOGD("Logging disabled");
+}
+
+void LayerStats::clear() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    mLayerStatsMap.clear();
+    ALOGD("Cleared current layer stats");
+}
+
+bool LayerStats::isEnabled() {
+    return mEnabled;
+}
+
+void LayerStats::traverseLayerTreeStatsLocked(
+        const std::vector<const LayerProtoParser::Layer*>& layerTree,
+        const LayerProtoParser::LayerGlobal* layerGlobal) {
+    for (auto layer : layerTree) {
+        if (!layer) continue;
+        traverseLayerTreeStatsLocked(layer->children, layerGlobal);
+        std::string key =
+                base::StringPrintf("%s,%s,%s,%s,%s,%s,%s,%s,%s",
+                                   destinationLocation(layer->hwcFrame.left,
+                                                       layerGlobal->resolution[0], true),
+                                   destinationLocation(layer->hwcFrame.top,
+                                                       layerGlobal->resolution[1], false),
+                                   destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
+                                                   layerGlobal->resolution[0], true),
+                                   destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                                                   layerGlobal->resolution[1], false),
+                                   layer->type.c_str(), scaleRatioWH(layer).c_str(),
+                                   layerTransform(layer->hwcTransform), layer->pixelFormat.c_str(),
+                                   layer->dataspace.c_str());
+        mLayerStatsMap[key]++;
+    }
+}
+
+void LayerStats::logLayerStats(const LayersProto& layersProto) {
+    ATRACE_CALL();
+    auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
+    auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+    std::lock_guard<std::mutex> lock(mMutex);
+    traverseLayerTreeStatsLocked(layerTree, &layerGlobal);
+    LayerProtoParser::destroyLayerTree(layerTree);
+}
+
+void LayerStats::dump(String8& result) {
+    ATRACE_CALL();
+    ALOGD("Dumping");
+    result.append("Count,DstPosX,DstPosY,DstWidth,DstHeight,LayerType,WScale,HScale,");
+    result.append("Transform,PixelFormat,Dataspace\n");
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (auto& u : mLayerStatsMap) {
+        result.appendFormat("%u,%s\n", u.second, u.first.c_str());
+    }
+}
+
+const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
+    static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
+    int32_t ratio = location * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isHorizontal) {
+        // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
+        if (ratio > 6) return "3/4";
+        // use index 0, 2, 4, 6
+        return locationArray[ratio & ~1];
+    }
+    if (ratio > 7) return "7/8";
+    return locationArray[ratio];
+}
+
+const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
+    static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
+    int32_t ratio = size * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isWidth) {
+        // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
+        if (ratio > 6) return "1";
+        // use index 1, 3, 5, 7
+        return sizeArray[ratio | 1];
+    }
+    if (ratio > 7) return "1";
+    return sizeArray[ratio];
+}
+
+const char* LayerStats::layerTransform(int32_t transform) {
+    return getTransformName(static_cast<hwc_transform_t>(transform));
+}
+
+std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
+    if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
+    std::string ret = "";
+    if (isRotated(layer->hwcTransform)) {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+    } else {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+    }
+    return ret;
+}
+
+const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
+    // Make scale buckets from <1/64 to >= 16, to avoid floating point
+    // calculation, x64 on destinationScale first
+    int32_t scale = destinationScale * 64 / sourceScale;
+    if (!scale) return "<1/64";
+    if (scale < 2) return "1/64";
+    if (scale < 4) return "1/32";
+    if (scale < 8) return "1/16";
+    if (scale < 16) return "1/8";
+    if (scale < 32) return "1/4";
+    if (scale < 64) return "1/2";
+    if (scale < 128) return "1";
+    if (scale < 256) return "2";
+    if (scale < 512) return "4";
+    if (scale < 1024) return "8";
+    return ">=16";
+}
+
+bool LayerStats::isRotated(int32_t transform) {
+    return transform & HWC_TRANSFORM_ROT_90;
+}
+
+bool LayerStats::isVFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_V;
+}
+
+bool LayerStats::isHFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_H;
+}
+
+}  // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
new file mode 100644
index 0000000..1924110
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <layerproto/LayerProtoHeader.h>
+#include <layerproto/LayerProtoParser.h>
+#include <mutex>
+#include <unordered_map>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+class String8;
+
+class LayerStats {
+public:
+    void enable();
+    void disable();
+    void clear();
+    bool isEnabled();
+    void logLayerStats(const LayersProto& layersProto);
+    void dump(String8& result);
+
+private:
+    // Traverse layer tree to get all visible layers' stats
+    void traverseLayerTreeStatsLocked(const std::vector<const LayerProtoParser::Layer*>& layerTree,
+                                      const LayerProtoParser::LayerGlobal* layerGlobal);
+    // Convert layer's top-left position into 8x8 percentage of the display
+    static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
+    // Convert layer's size into 8x8 percentage of the display
+    static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
+    // Return the name of the transform
+    static const char* layerTransform(int32_t transform);
+    // Calculate scale ratios of layer's width/height with rotation information
+    static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
+    // Calculate scale ratio from source to destination and convert to string
+    static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
+    // Return whether the original buffer is rotated in final composition
+    static bool isRotated(int32_t transform);
+    // Return whether the original buffer is V-flipped in final composition
+    static bool isVFlipped(int32_t transform);
+    // Return whether the original buffer is H-flipped in final composition
+    static bool isHFlipped(int32_t transform);
+
+    bool mEnabled = false;
+    // Protect mLayersStatsMap
+    std::mutex mMutex;
+    // Hashmap for tracking the layer stats
+    // KEY is a concatenation of a particular set of layer properties
+    // VALUE is the number of times this particular get scanned out
+    std::unordered_map<std::string, uint32_t> mLayerStatsMap;
+};
+
+}  // namespace android
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 1a5a85e..389fbd2 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -33,26 +33,13 @@
     // because we don't know where this destructor is called from. It could be
     // called with the mStateLock held, leading to a dead-lock (it actually
     // happens).
-    class MessageCleanUpList : public MessageBase {
-    public:
-        MessageCleanUpList(const sp<SurfaceFlinger>& flinger,
-                const wp<IBinder>& producer)
-            : mFlinger(flinger), mProducer(producer) {}
+    sp<LambdaMessage> cleanUpListMessage =
+            new LambdaMessage([flinger = mFlinger, asBinder = wp<IBinder>(onAsBinder())]() {
+                Mutex::Autolock lock(flinger->mStateLock);
+                flinger->mGraphicBufferProducerList.erase(asBinder);
+            });
 
-        virtual ~MessageCleanUpList() {}
-
-        virtual bool handler() {
-            Mutex::Autolock _l(mFlinger->mStateLock);
-            mFlinger->mGraphicBufferProducerList.remove(mProducer);
-            return true;
-        }
-
-    private:
-        sp<SurfaceFlinger> mFlinger;
-        wp<IBinder> mProducer;
-    };
-
-    mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder(mProducer)));
+    mFlinger->postMessageAsync(cleanUpListMessage);
 }
 
 status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 9ecf8ce..ea7dc2f 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -210,42 +210,16 @@
     }
 }
 
-void GLES20RenderEngine::setColorMode(android_color_mode mode) {
-    ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode);
-
-    if (mColorMode == mode) return;
-
-    if (!mPlatformHasWideColor || !mDisplayHasWideColor || mode == HAL_COLOR_MODE_SRGB ||
-        mode == HAL_COLOR_MODE_NATIVE) {
-        // We are returning back to our default color_mode
-        mUseWideColor = false;
-        mWideColorFrameCount = 0;
-    } else {
-        mUseWideColor = true;
-    }
-
-    mColorMode = mode;
-}
-
-void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
-    if (source == HAL_DATASPACE_UNKNOWN) {
-        // Treat UNKNOWN as SRGB
-        source = HAL_DATASPACE_V0_SRGB;
-    }
-    mDataSpace = source;
-}
-
 void GLES20RenderEngine::setSourceY410BT2020(bool enable) {
     mState.setY410BT2020(enable);
 }
 
-void GLES20RenderEngine::setWideColor(bool hasWideColor) {
-    ALOGV("setWideColor: %s", hasWideColor ? "true" : "false");
-    mDisplayHasWideColor = hasWideColor;
+void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
+    mDataSpace = source;
 }
 
-bool GLES20RenderEngine::usesWideColor() {
-    return mUseWideColor;
+void GLES20RenderEngine::setOutputDataSpace(android_dataspace dataspace) {
+    mOutputDataSpace = dataspace;
 }
 
 void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
@@ -326,17 +300,13 @@
     glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
                           mesh.getByteStride(), mesh.getPositions());
 
-    if (usesWideColor()) {
+    // DISPLAY_P3 is the only supported wide color output
+    if (mPlatformHasWideColor && mOutputDataSpace == HAL_DATASPACE_DISPLAY_P3) {
         Description wideColorState = mState;
         switch (int(mDataSpace)) {
             case HAL_DATASPACE_DISPLAY_P3:
                 // input matches output
                 break;
-            case HAL_DATASPACE_V0_SCRGB_LINEAR:
-                wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
-                wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
-                wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
-                break;
             case HAL_DATASPACE_BT2020_PQ:
             case HAL_DATASPACE_BT2020_ITU_PQ:
                 wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
@@ -345,8 +315,13 @@
                 wideColorState.enableToneMapping(true);
                 break;
             default:
+                // treat all other dataspaces as sRGB
                 wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
-                wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+                if ((mDataSpace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_LINEAR) {
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
+                } else {
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+                }
                 wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
                 ALOGV("drawMesh: gamut transform applied");
                 break;
@@ -356,8 +331,9 @@
         glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
 
         if (outputDebugPPMs) {
+            static uint64_t wideColorFrameCount = 0;
             std::ostringstream out;
-            out << "/data/texture_out" << mWideColorFrameCount++;
+            out << "/data/texture_out" << wideColorFrameCount++;
             writePPM(out.str().c_str(), mVpWidth, mVpHeight);
         }
     } else {
@@ -373,11 +349,9 @@
 
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
-    if (usesWideColor()) {
-        result.append("Wide-color: On\n");
-    } else {
-        result.append("Wide-color: Off\n");
-    }
+    result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
+                        dataspaceDetails(mDataSpace).c_str(),
+                        dataspaceDetails(mOutputDataSpace).c_str());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 6e86ea2..db3f792 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,27 +72,20 @@
                                     const half4& color) override;
 
     // Color management related functions and state
-    void setColorMode(android_color_mode mode);
-    void setSourceDataSpace(android_dataspace source);
-    void setSourceY410BT2020(bool enable);
-    void setWideColor(bool hasWideColor);
-    bool usesWideColor();
-
-    // Current color mode of display using the render engine
-    android_color_mode mColorMode = HAL_COLOR_MODE_NATIVE;
+    void setSourceY410BT2020(bool enable) override;
+    void setSourceDataSpace(android_dataspace source) override;
+    void setOutputDataSpace(android_dataspace dataspace) override;
 
     // Current dataspace of layer being rendered
-    android_dataspace mDataSpace = HAL_DATASPACE_V0_SRGB;
+    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
 
-    // Indicate if wide-color mode is needed or not
-    bool mDisplayHasWideColor = false;
-    bool mUseWideColor = false;
-    uint64_t mWideColorFrameCount = 0;
+    // Current output dataspace of the render engine
+    android_dataspace mOutputDataSpace = HAL_DATASPACE_UNKNOWN;
 
     // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
+    const bool mPlatformHasWideColor = false;
     mat4 mSrgbToDisplayP3;
     mat4 mBt2020ToDisplayP3;
-    bool mPlatformHasWideColor = false;
 
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index eacef38..d140574 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -108,11 +108,6 @@
                                           bool yswap, Transform::orientation_flags rotation) = 0;
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
                                     const half4& color) = 0;
-    virtual void setColorMode(android_color_mode mode) = 0;
-    virtual void setSourceDataSpace(android_dataspace source) = 0;
-    virtual void setSourceY410BT2020(bool enable) = 0;
-    virtual void setWideColor(bool hasWideColor) = 0;
-    virtual bool usesWideColor() = 0;
     virtual void setupLayerTexturing(const Texture& texture) = 0;
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
@@ -122,6 +117,11 @@
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
+    // wide color support
+    virtual void setSourceY410BT2020(bool enable) = 0;
+    virtual void setSourceDataSpace(android_dataspace source) = 0;
+    virtual void setOutputDataSpace(android_dataspace dataspace) = 0;
+
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e7c8bb2..29c1ee2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -701,7 +701,7 @@
 bool SurfaceFlinger::authenticateSurfaceTextureLocked(
         const sp<IGraphicBufferProducer>& bufferProducer) const {
     sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
-    return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
+    return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0;
 }
 
 status_t SurfaceFlinger::getSupportedFrameTimestamps(
@@ -1449,6 +1449,7 @@
     setUpHWComposer();
     doDebugFlashRegions();
     doTracing("handleRefresh");
+    logLayerStats();
     doComposition();
     postComposition(refreshStartTime);
 
@@ -1518,6 +1519,25 @@
     }
 }
 
+void SurfaceFlinger::logLayerStats() {
+    ATRACE_CALL();
+    if (CC_UNLIKELY(mLayerStats.isEnabled())) {
+        int32_t hwcId = -1;
+        for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) {
+            const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]);
+            if (displayDevice->isPrimary()) {
+                hwcId = displayDevice->getHwcDisplayId();
+                break;
+            }
+        }
+        if (hwcId < 0) {
+            ALOGE("LayerStats: Hmmm, no primary display?");
+            return;
+        }
+        mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
+    }
+}
+
 void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
 {
     ATRACE_CALL();
@@ -2266,9 +2286,8 @@
                 const wp<IBinder>& display(curr.keyAt(i));
 
                 if (dispSurface != nullptr) {
-                    bool useWideColorMode = hasWideColorDisplay;
-                    if (!mForceNativeColorMode) {
-                        bool hasWideColorModes = false;
+                    bool hasWideColorSupport = false;
+                    if (hasWideColorDisplay) {
                         std::vector<android_color_mode_t> modes =
                                 getHwComposer().getColorModes(state.type);
                         for (android_color_mode_t colorMode : modes) {
@@ -2276,13 +2295,12 @@
                                 case HAL_COLOR_MODE_DISPLAY_P3:
                                 case HAL_COLOR_MODE_ADOBE_RGB:
                                 case HAL_COLOR_MODE_DCI_P3:
-                                    hasWideColorModes = true;
+                                    hasWideColorSupport = true;
                                     break;
                                 default:
                                     break;
                             }
                         }
-                        useWideColorMode = hasWideColorModes && hasWideColorDisplay;
                     }
 
                     bool hasHdrSupport = false;
@@ -2296,11 +2314,11 @@
 
                     sp<DisplayDevice> hw =
                             new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
-                                              dispSurface, producer, useWideColorMode,
+                                              dispSurface, producer, hasWideColorSupport,
                                               hasHdrSupport);
 
                     android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
-                    if (useWideColorMode) {
+                    if (hasWideColorSupport) {
                         defaultColorMode = HAL_COLOR_MODE_SRGB;
                     }
                     setActiveColorModeInternal(hw, defaultColorMode);
@@ -2740,10 +2758,13 @@
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-        getBE().mRenderEngine->setWideColor(
-                displayDevice->getWideColorSupport() && !mForceNativeColorMode);
-        getBE().mRenderEngine->setColorMode(mForceNativeColorMode ?
-                HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
+        android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN;
+        if (displayDevice->getWideColorSupport() &&
+                displayDevice->getActiveColorMode() == HAL_COLOR_MODE_DISPLAY_P3) {
+            outputDataspace = HAL_DATASPACE_DISPLAY_P3;
+        }
+        getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
+
         if (!displayDevice->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
                   displayDevice->getDisplayName().string());
@@ -2893,7 +2914,9 @@
             parent->addChild(lbc);
         }
 
-        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+        mGraphicBufferProducerList.insert(IInterface::asBinder(gbc).get());
+        LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > MAX_LAYERS,
+                            "Suspected IGBP leak");
         mLayersAdded = true;
         mNumLayers++;
     }
@@ -3692,6 +3715,34 @@
                 dumpWideColorInfo(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--enable-layer-stats"))) {
+                index++;
+                mLayerStats.enable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--disable-layer-stats"))) {
+                index++;
+                mLayerStats.disable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--clear-layer-stats"))) {
+                index++;
+                mLayerStats.clear();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--dump-layer-stats"))) {
+                index++;
+                mLayerStats.dump(result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
@@ -3899,6 +3950,25 @@
     return layersProto;
 }
 
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+    LayersProto layersProto;
+
+    const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
+    SizeProto* resolution = layersProto.mutable_resolution();
+    resolution->set_w(displayDevice->getWidth());
+    resolution->set_h(displayDevice->getHeight());
+
+    mDrawingState.traverseInZOrder([&](Layer* layer) {
+        if (!layer->visibleRegion.isEmpty() &&
+            layer->getBE().mHwcLayers.count(hwcId)) {
+            LayerProto* layerProto = layersProto.add_layers();
+            layer->writeToProto(layerProto, hwcId);
+        }
+    });
+
+    return layersProto;
+}
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
@@ -4598,9 +4668,12 @@
         ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
     }
 
-    engine.setWideColor(renderArea.getWideColorSupport() && !mForceNativeColorMode);
-    engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE
-                                              : renderArea.getActiveColorMode());
+    android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN;
+    if (renderArea.getWideColorSupport() &&
+            renderArea.getActiveColorMode() == HAL_COLOR_MODE_DISPLAY_P3) {
+        outputDataspace = HAL_DATASPACE_DISPLAY_P3;
+    }
+    getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
 
     // make sure to clear all GL error flags
     engine.checkErrors();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index aae8d2c..d6aa142 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -44,6 +44,7 @@
 #include <gui/LayerState.h>
 
 #include <gui/OccupancyTracker.h>
+#include <gui/BufferQueue.h>
 
 #include <hardware/hwcomposer_defs.h>
 
@@ -55,11 +56,13 @@
 #include "DisplayDevice.h"
 #include "DispSync.h"
 #include "FrameTracker.h"
+#include "LayerStats.h"
 #include "LayerVector.h"
 #include "MessageQueue.h"
 #include "SurfaceInterceptor.h"
 #include "SurfaceTracing.h"
 #include "StartPropertySetThread.h"
+#include "LayerBE.h"
 
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/HWComposer.h"
@@ -629,6 +632,7 @@
     void doComposition();
     void doDebugFlashRegions();
     void doTracing(const char* where);
+    void logLayerStats();
     void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
 
     // compose surfaces for display hw. this fails if using GL and the surface
@@ -691,6 +695,7 @@
     void dumpBufferingStats(String8& result) const;
     void dumpWideColorInfo(String8& result) const;
     LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
+    LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
@@ -717,7 +722,9 @@
     bool mTransactionPending;
     bool mAnimTransactionPending;
     SortedVector< sp<Layer> > mLayersPendingRemoval;
-    SortedVector< wp<IBinder> > mGraphicBufferProducerList;
+
+    // Can't be unordered_set because wp<> isn't hashable
+    std::set<wp<IBinder>> mGraphicBufferProducerList;
 
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved;
@@ -773,6 +780,7 @@
     bool mPropagateBackpressure = true;
     SurfaceInterceptor mInterceptor;
     SurfaceTracing mTracing;
+    LayerStats mLayerStats;
     bool mUseHwcVirtualDisplays = false;
 
     // Restrict layers to use two buffers in their bufferqueues.
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index 8eb218c..485090c 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -33,4 +33,22 @@
         "-Wno-undef",
     ],
 
-}
\ No newline at end of file
+}
+
+java_library_static {
+    name: "layersprotosnano",
+    host_supported: true,
+    proto: {
+        type: "nano",
+    },
+    srcs: ["*.proto"],
+    no_framework_libs: true,
+    target: {
+        android: {
+            jarjar_rules: "jarjar-rules.txt",
+        },
+        host: {
+            static_libs: ["libprotobuf-java-nano"],
+        },
+    },
+}
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index bf37e1e..7483abd 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -38,6 +38,19 @@
     return lhs->id < rhs->id;
 }
 
+const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
+        const LayersProto& layersProto) {
+    return {{layersProto.resolution().w(), layersProto.resolution().h()}};
+}
+
+void LayerProtoParser::destroyLayerTree(
+        const std::vector<const LayerProtoParser::Layer*>& layerTree) {
+    for (auto layer : layerTree) {
+        destroyLayerTree(layer->children);
+        delete layer;
+    }
+}
+
 std::vector<const LayerProtoParser::Layer*> LayerProtoParser::generateLayerTree(
         const LayersProto& layersProto) {
     auto layerMap = generateMap(layersProto);
@@ -102,6 +115,9 @@
     layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
     layer->queuedFrames = layerProto.queued_frames();
     layer->refreshPending = layerProto.refresh_pending();
+    layer->hwcFrame = generateRect(layerProto.hwc_frame());
+    layer->hwcCrop = generateFloatRect(layerProto.hwc_crop());
+    layer->hwcTransform = layerProto.hwc_transform();
 
     return layer;
 }
@@ -127,6 +143,16 @@
     return rect;
 }
 
+LayerProtoParser::FloatRect LayerProtoParser::generateFloatRect(const FloatRectProto& rectProto) {
+    LayerProtoParser::FloatRect rect;
+    rect.left = rectProto.left();
+    rect.top = rectProto.top();
+    rect.right = rectProto.right();
+    rect.bottom = rectProto.bottom();
+
+    return rect;
+}
+
 LayerProtoParser::Transform LayerProtoParser::generateTransform(
         const TransformProto& transformProto) {
     LayerProtoParser::Transform transform;
@@ -242,6 +268,10 @@
     return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom);
 }
 
+std::string LayerProtoParser::FloatRect::to_string() const {
+    return StringPrintf("[%.2f, %.2f, %.2f, %.2f]", left, top, right, bottom);
+}
+
 std::string LayerProtoParser::Region::to_string(const char* what) const {
     std::string result =
             StringPrintf("  Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id),
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 78c6cd1..4747275 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <layerproto/LayerProtoHeader.h>
 
@@ -56,6 +57,16 @@
         std::string to_string() const;
     };
 
+    class FloatRect {
+    public:
+        float left;
+        float top;
+        float right;
+        float bottom;
+
+        std::string to_string() const;
+    };
+
     class Region {
     public:
         uint64_t id;
@@ -95,11 +106,21 @@
         LayerProtoParser::ActiveBuffer activeBuffer;
         int32_t queuedFrames;
         bool refreshPending;
+        LayerProtoParser::Rect hwcFrame;
+        LayerProtoParser::FloatRect hwcCrop;
+        int32_t hwcTransform;
 
         std::string to_string() const;
     };
 
+    class LayerGlobal {
+    public:
+        int2 resolution;
+    };
+
+    static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
     static std::vector<const Layer*> generateLayerTree(const LayersProto& layersProto);
+    static void destroyLayerTree(const std::vector<const LayerProtoParser::Layer*>& layerTree);
     static std::string layersToString(const std::vector<const LayerProtoParser::Layer*> layers);
 
 private:
@@ -107,6 +128,7 @@
     static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto);
     static LayerProtoParser::Region generateRegion(const RegionProto& regionProto);
     static LayerProtoParser::Rect generateRect(const RectProto& rectProto);
+    static LayerProtoParser::FloatRect generateFloatRect(const FloatRectProto& rectProto);
     static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto);
     static LayerProtoParser::ActiveBuffer generateActiveBuffer(
             const ActiveBufferProto& activeBufferProto);
diff --git a/services/surfaceflinger/layerproto/jarjar-rules.txt b/services/surfaceflinger/layerproto/jarjar-rules.txt
new file mode 100644
index 0000000..40043a8
--- /dev/null
+++ b/services/surfaceflinger/layerproto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index d27dc9b..e232f05 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -7,6 +7,7 @@
 // Contains a list of all layers.
 message LayersProto {
   repeated LayerProto layers = 1;
+  optional SizeProto resolution = 2;
 }
 
 // Information about each layer.
@@ -64,6 +65,12 @@
   // The number of frames available.
   optional int32 queued_frames = 28;
   optional bool refresh_pending = 29;
+  // The layer's composer backend destination frame
+  optional RectProto hwc_frame = 30;
+  // The layer's composer backend source crop
+  optional FloatRectProto hwc_crop = 31;
+  // The layer's composer backend transform
+  optional int32 hwc_transform = 32;
 }
 
 message PositionProto {
@@ -95,6 +102,13 @@
   optional int32 bottom = 4;
 }
 
+message FloatRectProto {
+  optional float left = 1;
+  optional float top = 2;
+  optional float right = 3;
+  optional float bottom = 4;
+}
+
 message ActiveBufferProto {
   optional uint32 width = 1;
   optional uint32 height = 2;
@@ -107,4 +121,4 @@
   optional float g = 2;
   optional float b = 3;
   optional float a = 4;
-}
\ No newline at end of file
+}
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index be4127c..36424b9 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*"
+            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*"
         }
 }
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ac8a2ad..92c26af 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2460,4 +2460,49 @@
     ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
 }
 
+
+class DereferenceSurfaceControlTest : public LayerTransactionTest {
+protected:
+    void SetUp() override {
+        LayerTransactionTest::SetUp();
+        bgLayer = createLayer("BG layer", 20, 20);
+        fillLayerColor(bgLayer, Color::RED);
+        fgLayer = createLayer("FG layer", 20, 20);
+        fillLayerColor(fgLayer, Color::BLUE);
+        Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
+        {
+            SCOPED_TRACE("before anything");
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+        }
+    }
+    void TearDown() override {
+        LayerTransactionTest::TearDown();
+        bgLayer = 0;
+        fgLayer = 0;
+    }
+
+    sp<SurfaceControl> bgLayer;
+    sp<SurfaceControl> fgLayer;
+};
+
+TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
+    fgLayer = nullptr;
+    {
+        SCOPED_TRACE("after setting null");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
+    }
+}
+
+TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
+    auto transaction = Transaction().show(fgLayer);
+    fgLayer = nullptr;
+    {
+        SCOPED_TRACE("after setting null");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+    }
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index fafc54e..21590df 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -165,9 +165,7 @@
 
     EXPECT_CALL(*mComposer, getActiveConfig(DisplayDevice::DISPLAY_PRIMARY, _))
             .WillOnce(DoAll(SetArgPointee<1>(0), Return(Error::NONE)));
-    EXPECT_CALL(*mComposer, getColorModes(DisplayDevice::DISPLAY_PRIMARY, _))
-            .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::NATIVE})),
-                            Return(Error::NONE)));
+    EXPECT_CALL(*mComposer, getColorModes(DisplayDevice::DISPLAY_PRIMARY, _)).Times(0);
     EXPECT_CALL(*mComposer, getHdrCapabilities(DisplayDevice::DISPLAY_PRIMARY, _, _, _, _))
             .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));
 
diff --git a/services/surfaceflinger/tests/unittests/MockComposer.h b/services/surfaceflinger/tests/unittests/MockComposer.h
index 248afcf..acd9b30 100644
--- a/services/surfaceflinger/tests/unittests/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/MockComposer.h
@@ -39,8 +39,8 @@
 using android::hardware::graphics::composer::V2_1::Error;
 using android::hardware::graphics::composer::V2_1::IComposer;
 using android::hardware::graphics::composer::V2_1::IComposerCallback;
-using android::hardware::graphics::composer::V2_1::IComposerClient;
 using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
 
 class Composer : public Hwc2::Composer {
 public:
@@ -73,6 +73,8 @@
     MOCK_METHOD2(getDisplayType, Error(Display, IComposerClient::DisplayType*));
     MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
     MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
+    MOCK_METHOD2(getPerFrameMetadataKeys,
+                 Error(Display, std::vector<IComposerClient::PerFrameMetadataKey>*));
     MOCK_METHOD3(getReleaseFences, Error(Display, std::vector<Layer>*, std::vector<int>*));
     MOCK_METHOD2(presentDisplay, Error(Display, int*));
     MOCK_METHOD2(setActiveConfig, Error(Display, Config));
@@ -95,6 +97,7 @@
     MOCK_METHOD3(setLayerColor, Error(Display, Layer, const IComposerClient::Color&));
     MOCK_METHOD3(setLayerCompositionType, Error(Display, Layer, IComposerClient::Composition));
     MOCK_METHOD3(setLayerDataspace, Error(Display, Layer, Dataspace));
+    MOCK_METHOD3(setLayerHdrMetadata, Error(Display, Layer, const HdrMetadata&));
     MOCK_METHOD3(setLayerDisplayFrame, Error(Display, Layer, const IComposerClient::Rect&));
     MOCK_METHOD3(setLayerPlaneAlpha, Error(Display, Layer, float));
     MOCK_METHOD3(setLayerSidebandStream, Error(Display, Layer, const native_handle_t*));
diff --git a/services/surfaceflinger/tests/unittests/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/MockRenderEngine.h
index aefbfcf..6d3e17f 100644
--- a/services/surfaceflinger/tests/unittests/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/MockRenderEngine.h
@@ -57,17 +57,15 @@
     MOCK_METHOD6(setViewportAndProjection,
                  void(size_t, size_t, Rect, size_t, bool, Transform::orientation_flags));
     MOCK_METHOD4(setupLayerBlending, void(bool, bool, bool, const half4&));
-    MOCK_METHOD1(setColorMode, void(android_color_mode));
-    MOCK_METHOD1(setSourceDataSpace, void(android_dataspace));
-    MOCK_METHOD1(setSourceY410BT2020, void(bool));
-    MOCK_METHOD1(setWideColor, void(bool));
-    MOCK_METHOD0(usesWideColor, bool());
     MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
     MOCK_METHOD0(setupLayerBlackedOut, void());
     MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
     MOCK_METHOD1(setupColorTransform, mat4(const mat4&));
     MOCK_METHOD0(disableTexturing, void());
     MOCK_METHOD0(disableBlending, void());
+    MOCK_METHOD1(setSourceY410BT2020, void(bool));
+    MOCK_METHOD1(setSourceDataSpace, void(android_dataspace));
+    MOCK_METHOD1(setOutputDataSpace, void(android_dataspace));
     MOCK_METHOD2(bindNativeBufferAsFrameBuffer,
                  void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*));
     MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*));
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
index 15829fa..f21254c 100644
--- a/services/utils/tests/Android.bp
+++ b/services/utils/tests/Android.bp
@@ -17,13 +17,13 @@
 cc_test {
     name: "prioritydumper_test",
     test_suites: ["device-tests"],
-    srcs: [ "PriorityDumper_test.cpp"],
+    srcs: ["PriorityDumper_test.cpp"],
     shared_libs: [
         "libutils",
     ],
-    static_libs = [
+    static_libs: [
         "libgmock",
-        "libserviceutils"
+        "libserviceutils",
     ],
     clang: true,
-}
\ No newline at end of file
+}
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
index 6f930a8..645ab80 100644
--- a/services/vr/hardware_composer/vr_hwc.rc
+++ b/services/vr/hardware_composer/vr_hwc.rc
@@ -3,3 +3,4 @@
   user system
   group system graphics
   onrestart restart surfaceflinger
+  writepid /dev/cpuset/system-background/tasks
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 7196b2b..513fcc1 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -14,7 +14,7 @@
 ]
 
 header_libraries = [
-    "libdvr_headers"
+    "libdvr_headers",
 ]
 
 cc_library {
@@ -48,19 +48,19 @@
     srcs: test_src_files,
     static_libs: test_static_libs,
     header_libs: header_libraries,
-    cflags = [
+    cflags: [
         "-Wall",
         "-Werror",
     ],
-    cppflags = [
+    cppflags: [
         "-std=c++11",
     ],
-    host_ldlibs = [
+    host_ldlibs: [
         "-llog",
     ],
     name: "VirtualTouchpad_test",
     stl: "libc++_static",
-    tags: [ "optional" ],
+    tags: ["optional"],
 }
 
 // Service.
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a9d473d..dec39e0 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -407,6 +407,12 @@
     for (uint32_t i = 0; i < ext_count; i++)
         FilterExtension(ext_names[i]);
 
+    // Enable device extensions that contain physical-device commands, so that
+    // vkGetInstanceProcAddr will return those physical-device commands.
+    if (is_instance_) {
+        hook_extensions_.set(ProcHook::KHR_swapchain);
+    }
+
     ext_names = extension_filter_.names;
     ext_count = extension_filter_.name_count;