camera3_test: manage buffers with smart pointer

Manage buffers with smart pointer for better ownership transition and
leakage prevention. Move test Gralloc out of camera device, and make the
single instance shared between devices and future tests.

BUG=b/32689987
CQ-DEPEND=CL:474884
TEST='emerge-kevin arc-camera3-test'
     'arc_camera3_test'

Change-Id: I31100711dc9aa028c8c7a0f922b979d1b6889d5c
Reviewed-on: https://chromium-review.googlesource.com/456983
Commit-Ready: Hung-yu Wu <hywu@chromium.org>
Tested-by: Hung-yu Wu <hywu@chromium.org>
Reviewed-by: Ricky Liang <jcliang@chromium.org>
Reviewed-by: Hung-yu Wu <hywu@chromium.org>
diff --git a/camera3_test/camera3_device_fixture.h b/camera3_test/camera3_device_fixture.h
index 5db9493..c4d2949 100644
--- a/camera3_test/camera3_device_fixture.h
+++ b/camera3_test/camera3_device_fixture.h
@@ -9,46 +9,16 @@
 #include <unordered_map>
 
 #include <base/synchronization/lock.h>
-#include <gbm.h>
 #include <gtest/gtest.h>
 #include <hardware/camera3.h>
 #include <hardware/hardware.h>
-#include <xf86drm.h>
 
 #include "camera3_module_fixture.h"
+#include "camera3_test_gralloc.h"
+#include "common/camera_buffer_handle.h"
 
 namespace camera3_test {
 
-class Camera3TestGralloc {
- public:
-  int Initialize();
-
-  void Destroy();
-
-  int Allocate(int width,
-               int height,
-               int format,
-               int usage,
-               buffer_handle_t* handle);
-
-  int Free(buffer_handle_t handle);
-
- private:
-  struct gbm_device* CreateGbmDevice();
-
-  // Conversion from HAL to GBM usage flags
-  uint64_t GrallocConvertFlags(int flags);
-
-  // Conversion from HAL to fourcc-based GBM formats
-  uint32_t GrallocConvertFormat(int format);
-
-  gbm_device* gbm_dev_;
-
-  // Real format of flexible YUV 420; it may be GBM_FORMAT_YVU420 or
-  // GBM_FORMAT_NV12
-  uint32_t flexible_yuv_420_format_;
-};
-
 class Camera3Device {
  public:
   explicit Camera3Device(int cam_id)
@@ -56,7 +26,8 @@
         initialized_(false),
         cam_device_(NULL),
         hal_thread_(GetThreadName(cam_id).c_str()),
-        cam_stream_idx_(0) {}
+        cam_stream_idx_(0),
+        gralloc_(Camera3TestGralloc::GetInstance()) {}
 
   ~Camera3Device() {}
 
@@ -148,11 +119,10 @@
   // Index of active streams
   int cam_stream_idx_;
 
-  Camera3TestGralloc gralloc_;
+  Camera3TestGralloc* gralloc_;
 
   // Store allocated buffers while easy to lookup and remove
-  std::unordered_map<camera3_stream_t*,
-                     std::set<std::unique_ptr<buffer_handle_t>>>
+  std::unordered_map<camera3_stream_t*, std::set<BufferHandleUniquePtr>>
       stream_buffers_;
 
   base::Lock stream_lock_;
diff --git a/camera3_test/camera3_device_test.cc b/camera3_test/camera3_device_test.cc
index e79177e..e90aad2 100644
--- a/camera3_test/camera3_device_test.cc
+++ b/camera3_test/camera3_device_test.cc
@@ -6,203 +6,8 @@
 
 #include <algorithm>
 
-#include <base/bind.h>
-
-#include "arc/camera_buffer_mapper.h"
-#include "common/camera_buffer_handle.h"
-
 namespace camera3_test {
 
-int32_t Camera3TestGralloc::Initialize() {
-  gbm_dev_ = CreateGbmDevice();
-  if (!gbm_dev_) {
-    LOG(ERROR) << "Can't create gbm device";
-    return -ENODEV;
-  }
-
-  uint32_t formats[] = {GBM_FORMAT_YVU420, GBM_FORMAT_NV12, GBM_FORMAT_YUV422,
-                        GBM_FORMAT_NV21};
-  size_t i = 0;
-  for (; i < arraysize(formats); i++) {
-    if (gbm_device_is_format_supported(gbm_dev_, formats[i],
-                                       GBM_BO_USE_RENDERING)) {
-      flexible_yuv_420_format_ = formats[i];
-      break;
-    }
-  }
-  if (i == arraysize(formats)) {
-    LOG(ERROR) << "Can't detect flexible YUV 420 format";
-    return -EINVAL;
-  }
-
-  return 0;
-}
-
-void Camera3TestGralloc::Destroy() {
-  if (gbm_dev_) {
-    close(gbm_device_get_fd(gbm_dev_));
-    gbm_device_destroy(gbm_dev_);
-  }
-}
-
-int32_t Camera3TestGralloc::Allocate(int32_t width,
-                                     int32_t height,
-                                     int32_t format,
-                                     int32_t usage,
-                                     buffer_handle_t* handle) {
-  uint64_t gbm_usage;
-  uint32_t gbm_format;
-  struct gbm_bo* bo;
-
-  gbm_format = GrallocConvertFormat(format);
-  gbm_usage = GrallocConvertFlags(usage);
-
-  if (!gbm_device_is_format_supported(gbm_dev_, gbm_format, gbm_usage)) {
-    LOG(ERROR) << "Unsupported format " << gbm_format;
-    return -EINVAL;
-  }
-
-  bo = gbm_bo_create(gbm_dev_, width, height, gbm_format, gbm_usage);
-  if (!bo) {
-    LOG(ERROR) << "Failed to create bo (" << width << "x" << height << ")";
-    return -ENOBUFS;
-  }
-
-  camera_buffer_handle_t* hnd = new camera_buffer_handle_t();
-
-  hnd->base.version = sizeof(hnd->base);
-  hnd->base.numInts = kCameraBufferHandleNumInts;
-  hnd->base.numFds = kCameraBufferHandleNumFds;
-
-  hnd->magic = kCameraBufferMagic;
-  hnd->buffer_id = reinterpret_cast<uint64_t>(bo);
-  hnd->type = arc::GRALLOC;
-  hnd->drm_format = gbm_bo_get_format(bo);
-  hnd->hal_pixel_format = format;
-  hnd->width = gbm_bo_get_width(bo);
-  hnd->height = gbm_bo_get_height(bo);
-  for (size_t i = 0; i < gbm_bo_get_num_planes(bo); ++i) {
-    hnd->fds[i].reset(gbm_bo_get_plane_fd(bo, i));
-    hnd->strides[i] = gbm_bo_get_plane_stride(bo, i);
-    hnd->offsets[i] = gbm_bo_get_plane_offset(bo, i);
-  }
-
-  *handle = reinterpret_cast<buffer_handle_t>(hnd);
-
-  return 0;
-}
-
-int32_t Camera3TestGralloc::Free(buffer_handle_t handle) {
-  auto hnd = camera_buffer_handle_t::FromBufferHandle(handle);
-  if (hnd) {
-    if (hnd->buffer_id == 0) {
-      ADD_FAILURE() << "Buffer handle mapping fails";
-      delete hnd;
-      return -EINVAL;
-    }
-
-    gbm_bo_destroy(reinterpret_cast<struct gbm_bo*>(hnd->buffer_id));
-    delete hnd;
-    return 0;
-  }
-
-  return -EINVAL;
-}
-
-struct gbm_device* Camera3TestGralloc::CreateGbmDevice() {
-  int32_t fd;
-  int32_t num_nodes = 63;
-  int32_t min_node = 128;
-  int32_t max_node = min_node + num_nodes;
-  struct gbm_device* gbm = nullptr;
-
-  // Try to get hardware-backed device first
-  for (int32_t i = min_node; i < max_node; i++) {
-    fd = drmOpenRender(i);
-    if (fd < 0) {
-      continue;
-    }
-
-    drmVersionPtr version = drmGetVersion(fd);
-    if (!strcmp("vgem", version->name)) {
-      drmFreeVersion(version);
-      close(fd);
-      continue;
-    }
-
-    gbm = gbm_create_device(fd);
-    if (!gbm) {
-      drmFreeVersion(version);
-      close(fd);
-      continue;
-    }
-
-    drmFreeVersion(version);
-    return gbm;
-  }
-
-  // Fall back to vgem if not hardware-backed device is found
-  for (int32_t i = min_node; i < max_node; i++) {
-    fd = drmOpenRender(i);
-    if (fd < 0) {
-      continue;
-    }
-
-    drmVersionPtr version = drmGetVersion(fd);
-    if (strcmp("vgem", drmGetVersion(fd)->name)) {
-      drmFreeVersion(version);
-      close(fd);
-      continue;
-    }
-
-    gbm = gbm_create_device(fd);
-    if (!gbm) {
-      close(fd);
-      return nullptr;
-    }
-
-    drmFreeVersion(version);
-    return gbm;
-  }
-
-  return nullptr;
-}
-
-uint64_t Camera3TestGralloc::GrallocConvertFlags(int32_t flags) {
-  uint64_t usage = GBM_BO_USE_RENDERING;
-
-  // TODO: conversion from Gralloc flags to GBM flags
-
-  return usage;
-}
-
-uint32_t Camera3TestGralloc::GrallocConvertFormat(int32_t format) {
-  switch (format) {
-    case HAL_PIXEL_FORMAT_BGRA_8888:
-      return GBM_FORMAT_ARGB8888;
-    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
-      return GBM_FORMAT_ARGB8888;
-    case HAL_PIXEL_FORMAT_RGB_565:
-      return GBM_FORMAT_RGB565;
-    case HAL_PIXEL_FORMAT_RGB_888:
-      return GBM_FORMAT_RGB888;
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-      return GBM_FORMAT_ABGR8888;
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-      return GBM_FORMAT_XBGR8888;
-    case HAL_PIXEL_FORMAT_YCbCr_420_888:
-      return flexible_yuv_420_format_;
-    case HAL_PIXEL_FORMAT_YV12:
-      return GBM_FORMAT_YVU420;
-    case HAL_PIXEL_FORMAT_BLOB:
-      return GBM_FORMAT_ARGB8888;
-    default:
-      LOG(ERROR) << "Unsupported format conversion " << format;
-  }
-
-  return GBM_FORMAT_ARGB8888;
-}
-
 int Camera3Device::Initialize(Camera3Module* cam_module,
                               const camera3_callback_ops_t* callback_ops) {
   if (!cam_module || !hal_thread_.Start()) {
@@ -226,7 +31,7 @@
                                       &result));
   EXPECT_EQ(0, result) << "Camera device initialization fails";
 
-  EXPECT_EQ(0, gralloc_.Initialize()) << "Gralloc initialization fails";
+  EXPECT_NE(nullptr, gralloc_) << "Gralloc initialization fails";
 
   camera_info cam_info;
   EXPECT_EQ(0, cam_module->GetCameraInfo(cam_id_, &cam_info));
@@ -246,9 +51,6 @@
   // Buffers are expected to be freed in ProcessCaptureResult callback in the
   // test.
   EXPECT_TRUE(stream_buffers_.empty()) << "Buffers are not freed correctly";
-  ClearOutputStreamBuffers();
-
-  gralloc_.Destroy();
 
   int result = -EIO;
   hal_thread_.PostTaskSync(base::Bind(&Camera3Device::CloseOnHalThread,
@@ -344,17 +146,11 @@
   const std::vector<camera3_stream_t>* streams_ptr =
       streams.empty() ? &cam_stream_[cam_stream_idx_] : &streams;
   for (const auto& it : *streams_ptr) {
-    std::unique_ptr<buffer_handle_t> buffer(new buffer_handle_t);
-
-    // Buffers of blob format must have a height of 1, and width equal to
-    // their size in bytes.
-    EXPECT_EQ(
-        0, gralloc_.Allocate(
-               (it.format == HAL_PIXEL_FORMAT_BLOB) ? jpeg_max_size : it.width,
-               (it.format == HAL_PIXEL_FORMAT_BLOB) ? 1 : it.height, it.format,
-               GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_CAMERA_WRITE,
-               buffer.get()))
-        << "Gralloc allocation fails";
+    BufferHandleUniquePtr buffer = gralloc_->Allocate(
+        (it.format == HAL_PIXEL_FORMAT_BLOB) ? jpeg_max_size : it.width,
+        (it.format == HAL_PIXEL_FORMAT_BLOB) ? 1 : it.height, it.format,
+        GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_CAMERA_WRITE);
+    EXPECT_NE(nullptr, buffer) << "Gralloc allocation fails";
 
     camera3_stream_buffer_t stream_buffer;
     {
@@ -388,11 +184,6 @@
     bool found = false;
     for (const auto& it : stream_buffers_[output_buffer.stream]) {
       if (*it == *output_buffer.buffer) {
-        int result = gralloc_.Free(*it);
-        if (result != 0) {
-          LOG(ERROR) << "Failed to free output buffer";
-          return result;
-        }
         stream_buffers_[output_buffer.stream].erase(it);
         if (stream_buffers_[output_buffer.stream].empty()) {
           stream_buffers_.erase(output_buffer.stream);
@@ -411,13 +202,7 @@
 
 void Camera3Device::ClearOutputStreamBuffers() {
   base::AutoLock l(stream_buffers_lock_);
-
   // Free frame buffers
-  for (auto const& it : stream_buffers_) {
-    for (auto const& buffer : it.second) {
-      EXPECT_EQ(0, gralloc_.Free(*buffer)) << "Buffer is not freed correctly";
-    }
-  }
   stream_buffers_.clear();
 }
 
diff --git a/camera3_test/camera3_frame_test.cc b/camera3_test/camera3_frame_test.cc
index 124ec94..79dd228 100644
--- a/camera3_test/camera3_frame_test.cc
+++ b/camera3_test/camera3_frame_test.cc
@@ -543,6 +543,10 @@
       ASSERT_EQ(0, GetMinResolution(format, &resolution))
           << "Failed to get min resolution for format " << format;
     }
+    VLOGF(1) << "Device " << cam_id_;
+    VLOGF(1) << "Format 0x" << std::hex << format;
+    VLOGF(1) << "Resolution " << resolution.Width() << "x"
+             << resolution.Height();
 
     cam_device_.AddOutputStream(format, resolution.Width(),
                                 resolution.Height());
diff --git a/camera3_test/camera3_test_gralloc.cc b/camera3_test/camera3_test_gralloc.cc
new file mode 100644
index 0000000..dd1c142
--- /dev/null
+++ b/camera3_test/camera3_test_gralloc.cc
@@ -0,0 +1,175 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "camera3_test_gralloc.h"
+
+#include <algorithm>
+
+#include "arc/camera_buffer_mapper.h"
+#include "common/camera_buffer_mapper_internal.h"
+#include <drm_fourcc.h>
+
+namespace camera3_test {
+
+void BufferHandleDeleter::operator()(buffer_handle_t* handle) {
+  if (handle) {
+    auto hnd = camera_buffer_handle_t::FromBufferHandle(*handle);
+    if (hnd) {
+      if (hnd->buffer_id) {
+        arc::CameraBufferMapper::GetInstance()->Deregister(*handle);
+        gbm_bo_destroy(reinterpret_cast<struct gbm_bo*>(hnd->buffer_id));
+      } else {
+        LOG(ERROR) << "Buffer handle mapping fails";
+      }
+      delete hnd;
+    }
+    delete handle;
+  }
+}
+
+Camera3TestGralloc* Camera3TestGralloc::GetInstance() {
+  static Camera3TestGralloc gralloc;
+
+  if (!gralloc.gbm_dev_) {
+    gralloc.gbm_dev_ = ::arc::internal::CreateGbmDevice();
+    if (!gralloc.gbm_dev_) {
+      LOG(ERROR) << "Can't create gbm device";
+      return nullptr;
+    }
+
+    uint32_t formats[] = {DRM_FORMAT_YVU420, DRM_FORMAT_NV12, DRM_FORMAT_YUV420,
+                          DRM_FORMAT_NV21};
+    size_t i = 0;
+    for (; i < arraysize(formats); i++) {
+      if (gbm_device_is_format_supported(gralloc.gbm_dev_, formats[i],
+                                         GBM_BO_USE_RENDERING)) {
+        gralloc.flexible_yuv_420_format_ = formats[i];
+        break;
+      }
+    }
+    if (i == arraysize(formats)) {
+      LOG(ERROR) << "Can't detect flexible YUV 420 format";
+      close(gbm_device_get_fd(gralloc.gbm_dev_));
+      gbm_device_destroy(gralloc.gbm_dev_);
+      gralloc.gbm_dev_ = nullptr;
+      return nullptr;
+    }
+  }
+  return &gralloc;
+}
+
+Camera3TestGralloc::~Camera3TestGralloc() {
+  if (gbm_dev_) {
+    close(gbm_device_get_fd(gbm_dev_));
+    gbm_device_destroy(gbm_dev_);
+  }
+}
+
+BufferHandleUniquePtr Camera3TestGralloc::Allocate(int32_t width,
+                                                   int32_t height,
+                                                   int32_t format,
+                                                   int32_t usage) {
+  uint64_t gbm_usage;
+  uint32_t gbm_format;
+  struct gbm_bo* bo;
+
+  gbm_format = GrallocConvertFormat(format);
+  gbm_usage = GrallocConvertFlags(format, usage);
+
+  if (gbm_format == 0 ||
+      !gbm_device_is_format_supported(gbm_dev_, gbm_format, gbm_usage)) {
+    LOG(ERROR) << "Unsupported format " << gbm_format;
+    return BufferHandleUniquePtr(nullptr);
+  }
+
+  bo = gbm_bo_create(gbm_dev_, width, height, gbm_format, gbm_usage);
+  if (!bo) {
+    LOG(ERROR) << "Failed to create bo (" << width << "x" << height << ")";
+    return BufferHandleUniquePtr(nullptr);
+  }
+
+  camera_buffer_handle_t* hnd = new camera_buffer_handle_t();
+
+  hnd->base.version = sizeof(hnd->base);
+  hnd->base.numInts = kCameraBufferHandleNumInts;
+  hnd->base.numFds = kCameraBufferHandleNumFds;
+
+  hnd->magic = kCameraBufferMagic;
+  hnd->buffer_id = reinterpret_cast<uint64_t>(bo);
+  hnd->type = arc::GRALLOC;
+  hnd->drm_format = gbm_bo_get_format(bo);
+  hnd->hal_pixel_format = format;
+  hnd->width = gbm_bo_get_width(bo);
+  hnd->height = gbm_bo_get_height(bo);
+  for (size_t i = 0; i < gbm_bo_get_num_planes(bo); ++i) {
+    hnd->fds[i].reset(gbm_bo_get_plane_fd(bo, i));
+    hnd->strides[i] = gbm_bo_get_plane_stride(bo, i);
+    hnd->offsets[i] = gbm_bo_get_plane_offset(bo, i);
+  }
+
+  BufferHandleUniquePtr handle(new buffer_handle_t);
+  *handle = reinterpret_cast<buffer_handle_t>(hnd);
+  buffer_mapper_->Register(*handle);
+  return handle;
+}
+
+int Camera3TestGralloc::Lock(buffer_handle_t buffer,
+                             uint32_t flags,
+                             uint32_t x,
+                             uint32_t y,
+                             uint32_t width,
+                             uint32_t height,
+                             void** out_addr) {
+  return buffer_mapper_->Lock(buffer, flags, x, y, width, height, out_addr);
+}
+
+int Camera3TestGralloc::LockYCbCr(buffer_handle_t buffer,
+                                  uint32_t flags,
+                                  uint32_t x,
+                                  uint32_t y,
+                                  uint32_t width,
+                                  uint32_t height,
+                                  struct android_ycbcr* out_ycbcr) {
+  return buffer_mapper_->LockYCbCr(buffer, flags, x, y, width, height,
+                                   out_ycbcr);
+}
+
+int Camera3TestGralloc::Unlock(buffer_handle_t buffer) {
+  return buffer_mapper_->Unlock(buffer);
+}
+
+int Camera3TestGralloc::GetFormat(buffer_handle_t buffer) {
+  auto hnd = camera_buffer_handle_t::FromBufferHandle(buffer);
+  return (hnd && hnd->buffer_id) ? hnd->hal_pixel_format : -EINVAL;
+}
+
+uint64_t Camera3TestGralloc::GrallocConvertFlags(int32_t format,
+                                                 int32_t flags) {
+  return (format == HAL_PIXEL_FORMAT_BLOB) ? GBM_BO_USE_LINEAR
+                                           : GBM_BO_USE_RENDERING;
+}
+
+uint32_t Camera3TestGralloc::GrallocConvertFormat(int32_t format) {
+  switch (format) {
+    case HAL_PIXEL_FORMAT_BGRA_8888:
+      return DRM_FORMAT_ARGB8888;
+    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+      return DRM_FORMAT_XBGR8888;
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+      return DRM_FORMAT_ABGR8888;
+    case HAL_PIXEL_FORMAT_RGBX_8888:
+      return DRM_FORMAT_XBGR8888;
+    case HAL_PIXEL_FORMAT_YCbCr_420_888:
+      return flexible_yuv_420_format_;
+    case HAL_PIXEL_FORMAT_YV12:
+      return DRM_FORMAT_YVU420;
+    case HAL_PIXEL_FORMAT_BLOB:
+      return DRM_FORMAT_R8;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+}  // namespace camera3_test
diff --git a/camera3_test/camera3_test_gralloc.h b/camera3_test/camera3_test_gralloc.h
new file mode 100644
index 0000000..fc34150
--- /dev/null
+++ b/camera3_test/camera3_test_gralloc.h
@@ -0,0 +1,133 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAMERA3_TEST_CAMERA3_TEST_GRALLOC_H_
+#define CAMERA3_TEST_CAMERA3_TEST_GRALLOC_H_
+
+#include <memory>
+#include <unordered_map>
+
+#include <arc/camera_buffer_mapper.h>
+#include <base/synchronization/lock.h>
+#include <gbm.h>
+#include <xf86drm.h>
+
+#include "common/camera_buffer_handle.h"
+
+namespace camera3_test {
+
+struct BufferHandleDeleter {
+  void operator()(buffer_handle_t* handle);
+};
+
+typedef std::unique_ptr<buffer_handle_t, struct BufferHandleDeleter>
+    BufferHandleUniquePtr;
+
+class Camera3TestGralloc {
+ public:
+  // Get Gralloc single instance
+  static Camera3TestGralloc* GetInstance();
+
+  // Allocate buffer by given parameters
+  BufferHandleUniquePtr Allocate(int width, int height, int format, int usage);
+
+  // This method is analogous to the lock() function in Android gralloc module.
+  // Here the buffer handle is mapped with the given args.
+  //
+  // Args:
+  //    |buffer|: The buffer handle to map.
+  //    |flags|:  Currently omitted and is reserved for future use.
+  //    |x|: The base x coordinate in pixels.
+  //    |y|: The base y coordinate in pixels.
+  //    |width|: The width in pixels of the area to map.
+  //    |height|: The height in pixels of the area to map.
+  //    |out_addr|: The mapped address.
+  //
+  // Returns:
+  //    0 on success with |out_addr| set with the mapped address;
+  //    -EINVAL on invalid buffer handle or invalid buffer format.
+  int Lock(buffer_handle_t buffer,
+           uint32_t flags,
+           uint32_t x,
+           uint32_t y,
+           uint32_t width,
+           uint32_t height,
+           void** out_addr);
+
+  // This method is analogous to the lock_ycbcr() function in Android gralloc
+  // module.  Here all the physical planes of the buffer handle are mapped with
+  // the given args.
+  //
+  // Args:
+  //    |buffer|: The buffer handle to map.
+  //    |flags|:  Currently omitted and is reserved for future use.
+  //    |x|: The base x coordinate in pixels.
+  //    |y|: The base y coordinate in pixels.
+  //    |width|: The width in pixels of the area to map.
+  //    |height|: The height in pixels of the area to map.
+  //    |out_ycbcr|: The mapped addresses, plane strides and chroma offset.
+  //        - |out_ycbcr.y| stores the mapped address of the Y-plane.
+  //        - |out_ycbcr.cb| stores the mapped address of the Cb-plane.
+  //        - |out_ycbcr.cr| stores the mapped address of the Cr-plane.
+  //        - |out_ycbcr.ystride| stores the stride of the Y-plane.
+  //        - |out_ycbcr.cstride| stores the stride of the chroma planes.
+  //        - |out_ycbcr.chroma_step| stores the distance between two adjacent
+  //          pixels on the chroma plane. The value is 1 for normal planar
+  //          formats, and 2 for semi-planar formats.
+  //
+  // Returns:
+  //    0 on success with |out_ycbcr.y| set with the mapped buffer info;
+  //    -EINVAL on invalid buffer handle or invalid buffer format.
+  int LockYCbCr(buffer_handle_t buffer,
+                uint32_t flags,
+                uint32_t x,
+                uint32_t y,
+                uint32_t width,
+                uint32_t height,
+                struct android_ycbcr* out_ycbcr);
+
+  // This method is analogous to the unlock() function in Android gralloc
+  // module.  Here the buffer is simply unmapped.
+  //
+  // Args:
+  //    |buffer|: The buffer handle to unmap.
+  //
+  // Returns:
+  //    0 on success; -EINVAL on invalid buffer handle.
+  int Unlock(buffer_handle_t buffer);
+
+  // Get buffer format
+  // Returns:
+  //    HAL_PIXEL_FORMAT_* on success; -EINVAL on invalid buffer handle.
+  static int GetFormat(buffer_handle_t buffer);
+
+ private:
+  // Free buffer
+  int Free(buffer_handle_t handle);
+
+  Camera3TestGralloc()
+      : gbm_dev_(nullptr),
+        buffer_mapper_(arc::CameraBufferMapper::GetInstance()) {}
+
+  ~Camera3TestGralloc();
+
+  // Conversion from HAL to GBM usage flags
+  uint64_t GrallocConvertFlags(int format, int flags);
+
+  // Conversion from HAL to fourcc-based GBM formats
+  uint32_t GrallocConvertFormat(int format);
+
+  gbm_device* gbm_dev_;
+
+  // Real GBM format of flexible YUV 420. The flexible format here does not
+  // necessarily match the yuv420 format allocated by Android gralloc, but for
+  // testing we are free to choose any yuv420 format that works.
+  uint32_t flexible_yuv_420_format_;
+
+  arc::CameraBufferMapper* buffer_mapper_;
+};
+
+}  // namespace camera3_test
+
+#endif  // CAMERA3_TEST_CAMERA3_TEST_GRALLOC_H_
diff --git a/camera3_test/module.mk b/camera3_test/module.mk
index d00409a..35cd9a2 100644
--- a/camera3_test/module.mk
+++ b/camera3_test/module.mk
@@ -11,7 +11,9 @@
 camera3_test_CPPFLAGS := $(call get_pc_cflags,$(camera3_test_PC_DEPS))
 camera3_test_LDLIBS := $(call get_pc_libs,$(camera3_test_PC_DEPS)) -ldl \
 	$(shell gtest-config --libs)
-camera3_test_CXX_OBJECTS += common/future.o
+camera3_test_CXX_OBJECTS += \
+	$(libcbm_OBJS) \
+	common/future.o
 
 CXX_BINARY(camera3_test/arc_camera3_test): CPPFLAGS += $(camera3_test_CPPFLAGS)
 CXX_BINARY(camera3_test/arc_camera3_test): LDLIBS += $(camera3_test_LDLIBS)