Add otapreopt logic for CompactDex version bump am: a3a18bee9d  -s ours
am: 5cb5c84079  -s ours

Change-Id: I4411f221c2f596cd1861599d47674997e9b5134f
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/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/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 3531c4e..5d68696 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -101,6 +101,7 @@
         "Layer.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
+        "LayerStats.cpp",
         "LayerVector.cpp",
         "MessageQueue.cpp",
         "MonitoredProducer.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 3dbc136..d07a52b 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;
     }
@@ -631,8 +620,8 @@
 
     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 +635,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 +650,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 +682,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 +705,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 +870,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/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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cb410a1..29c1ee2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -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();
@@ -3695,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) {
@@ -3902,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
 {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 392acaa..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;
@@ -775,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/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/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/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/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;