Merge "libnativewindow: remove software flex pixel formats from VNDK" into pi-dev
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/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/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/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/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 3531c4e..0c0fedc 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",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 3dbc136..b804af8 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -629,6 +629,13 @@
               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,
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/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/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