DO NOT MERGE - Added missing theme packages on preinstalled XML. am: ed05e95960

Change-Id: Iba74c201a4bc8f54ae089ba31bd84429961ebb71
diff --git a/common/libs/utils/environment.cpp b/common/libs/utils/environment.cpp
index 11a0b8c..e6cacd0 100644
--- a/common/libs/utils/environment.cpp
+++ b/common/libs/utils/environment.cpp
@@ -17,6 +17,8 @@
 #include "common/libs/utils/environment.h"
 
 #include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
 
 namespace cvd {
 
@@ -29,4 +31,55 @@
   return valstr;
 }
 
+/**
+ * at runtime, return the arch of the host: e.g. aarch64, x86_64, etc
+ *
+ * uses "`which uname` -m"
+ *
+ * @return arch string on success, "" on failure
+ */
+std::string HostArch() {
+  static std::string arch;
+  static bool cached = false;
+
+  if (cached) {
+    return arch;
+  }
+  cached = true;
+
+  // good to check if uname exists and is executable
+  // or, guarantee uname is availabe by dependency list
+  FILE* pip = popen("uname -m", "r");
+  if (!pip) {
+    return std::string{};
+  }
+
+  auto read_from_file =
+      [](FILE* fp, size_t len) {
+        /*
+         * to see if input is longer than len,
+         * we read up to len+1. If the length is len+1,
+         * then the input is too long
+         */
+        decltype(len) upper = len + 1;
+        std::string format("%");
+        format.append(std::to_string(upper)).append("s");
+        std::shared_ptr<char> buf(new char[upper],
+                                  std::default_delete<char[]>());
+        if (fscanf(fp, format.c_str(), buf.get()) == EOF) {
+          return std::string{};
+        }
+        std::string result(buf.get());
+        return (result.length() < upper) ? result : std::string{};
+      };
+  arch = read_from_file(pip, 20);
+  pclose(pip);
+
+  // l and r trim on arch
+  static const char* whitespace = "\t\n\r\f\v ";
+  arch.erase(arch.find_last_not_of(whitespace) + 1); // r trim
+  arch.erase(0, arch.find_first_not_of(whitespace)); // l trim
+  return arch;
+}
+
 }  // namespace cvd
diff --git a/common/libs/utils/environment.h b/common/libs/utils/environment.h
index 1aab8de..5a83b49 100644
--- a/common/libs/utils/environment.h
+++ b/common/libs/utils/environment.h
@@ -22,4 +22,6 @@
 std::string StringFromEnv(const std::string& varname,
                           const std::string& defval);
 
+std::string HostArch();
+
 }  // namespace cvd
diff --git a/common/libs/utils/network.cpp b/common/libs/utils/network.cpp
index cece2b6..5b67c8e 100644
--- a/common/libs/utils/network.cpp
+++ b/common/libs/utils/network.cpp
@@ -23,10 +23,19 @@
 #include <android-base/strings.h>
 #include "common/libs/glog/logging.h"
 
+#include "common/libs/utils/environment.h"
 #include "common/libs/utils/subprocess.h"
 
 namespace cvd {
 namespace {
+
+static std::string DefaultHostArtifactsPath(const std::string& file_name) {
+  return (cvd::StringFromEnv("ANDROID_HOST_OUT",
+                             cvd::StringFromEnv("HOME", ".")) +
+          "/") +
+         file_name;
+}
+
 // This should be the size of virtio_net_hdr_v1, from linux/virtio_net.h, but
 // the version of that header that ships with android in Pie does not include
 // that struct (it was added in Q).
@@ -52,28 +61,41 @@
     return tap_fd;
   }
 
-  struct ifreq ifr;
-  memset(&ifr, 0, sizeof(ifr));
-  ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
-  strncpy(ifr.ifr_name, interface_name.c_str(), IFNAMSIZ);
+  if (cvd::HostArch() == "aarch64") {
+    auto tapsetiff_path = DefaultHostArtifactsPath("bin/tapsetiff");
+    cvd::Command cmd(tapsetiff_path);
+    cmd.AddParameter(tap_fd);
+    cmd.AddParameter(interface_name.c_str());
+    int ret = cmd.Start().Wait();
+    if (ret != 0) {
+      LOG(ERROR) << "Unable to run tapsetiff.py. Exited with status " << ret;
+      tap_fd->Close();
+      return cvd::SharedFD();
+    }
+  } else {
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
+    strncpy(ifr.ifr_name, interface_name.c_str(), IFNAMSIZ);
 
-  int err = tap_fd->Ioctl(TUNSETIFF, &ifr);
-  if (err < 0) {
-    LOG(ERROR) << "Unable to connect to " << interface_name
-               << " tap interface: " << tap_fd->StrError();
-    tap_fd->Close();
-    return cvd::SharedFD();
-  }
+    int err = tap_fd->Ioctl(TUNSETIFF, &ifr);
+    if (err < 0) {
+      LOG(ERROR) << "Unable to connect to " << interface_name
+                 << " tap interface: " << tap_fd->StrError();
+      tap_fd->Close();
+      return cvd::SharedFD();
+    }
 
-  // The interface's configuration may have been modified or just not set
-  // correctly on creation. While qemu checks this and enforces the right
-  // configuration, crosvm does not, so it needs to be set before it's passed to
-  // it.
-  tap_fd->Ioctl(TUNSETOFFLOAD,
-                reinterpret_cast<void*>(TUN_F_CSUM | TUN_F_UFO | TUN_F_TSO4 |
+    // The interface's configuration may have been modified or just not set
+    // correctly on creation. While qemu checks this and enforces the right
+    // configuration, crosvm does not, so it needs to be set before it's passed to
+    // it.
+    tap_fd->Ioctl(TUNSETOFFLOAD,
+                  reinterpret_cast<void*>(TUN_F_CSUM | TUN_F_UFO | TUN_F_TSO4 |
                                         TUN_F_TSO6));
-  int len = SIZE_OF_VIRTIO_NET_HDR_V1;
-  tap_fd->Ioctl(TUNSETVNETHDRSZ, &len);
+    int len = SIZE_OF_VIRTIO_NET_HDR_V1;
+    tap_fd->Ioctl(TUNSETVNETHDRSZ, &len);
+  }
 
   return tap_fd;
 }
diff --git a/guest/hals/hwcomposer/common/Android.bp b/guest/hals/hwcomposer/common/Android.bp
index 25d02f8..fa023f1 100644
--- a/guest/hals/hwcomposer/common/Android.bp
+++ b/guest/hals/hwcomposer/common/Android.bp
@@ -18,26 +18,31 @@
     defaults: ["cuttlefish_guest_only"],
     vendor: true,
     srcs: [
+        "base_composer.cpp",
+        "cpu_composer.cpp",
+        "drm_utils.cpp",
+        "geometry_utils.cpp",
+        "gralloc_utils.cpp",
         "hwcomposer.cpp",
         "screen_view.cpp",
-        "base_composer.cpp",
-        "geometry_utils.cpp",
-        "cpu_composer.cpp",
         "stats_keeper.cpp",
     ],
     static_libs: [
         "libyuv_static",
     ],
+    header_libs: ["libhardware_headers"],
     shared_libs: [
-        "liblog",
-        "libhardware",
+        "android.hardware.graphics.mapper@4.0",
         "libbase",
         "libcutils",
-        "libutils",
-        "libsync",
-        "libhardware",
-        "libjpeg",
         "libcuttlefish_utils",
         "libcuttlefish_fs",
+        "libdrm",
+        "libgralloctypes",
+        "libhidlbase",
+        "libjpeg",
+        "liblog",
+        "libsync",
+        "libutils",
     ],
 }
diff --git a/guest/hals/hwcomposer/common/base_composer.cpp b/guest/hals/hwcomposer/common/base_composer.cpp
index 0113849..cd3ac65 100644
--- a/guest/hals/hwcomposer/common/base_composer.cpp
+++ b/guest/hals/hwcomposer/common/base_composer.cpp
@@ -19,39 +19,78 @@
 #include <string.h>
 
 #include <cutils/properties.h>
-#include <hardware/gralloc.h>
 #include <log/log.h>
 
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
 namespace cvd {
 
 BaseComposer::BaseComposer(std::unique_ptr<ScreenView> screen_view)
-    : screen_view_(std::move(screen_view)) {
-  hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
-                reinterpret_cast<const hw_module_t**>(&gralloc_module_));
-}
+    : screen_view_(std::move(screen_view)), gralloc_() {}
 
 void BaseComposer::Dump(char* buff __unused, int buff_len __unused) {}
 
 int BaseComposer::PostFrameBufferTarget(buffer_handle_t buffer_handle) {
   auto buffer_id = screen_view_->NextBuffer();
   void* frame_buffer = screen_view_->GetBuffer(buffer_id);
-  const private_handle_t* p_handle =
-      reinterpret_cast<const private_handle_t*>(buffer_handle);
-  void* buffer;
-  int retval = gralloc_module_->lock(gralloc_module_, buffer_handle,
-                                     GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
-                                     p_handle->x_res, p_handle->y_res, &buffer);
-  if (retval != 0) {
-    ALOGE("Got error code %d from lock function", retval);
+
+  auto imported_buffer_opt = gralloc_.Import(buffer_handle);
+  if (!imported_buffer_opt) {
+    ALOGE("Failed to Import() framebuffer for post.");
     return -1;
   }
+  GrallocBuffer& imported_buffer = *imported_buffer_opt;
+
+  auto buffer_opt = imported_buffer.Lock();
+  if (!buffer_opt) {
+    ALOGE("Failed to Lock() framebuffer for post.");
+    return -1;
+  }
+
+  void* buffer = *buffer_opt;
   memcpy(frame_buffer, buffer, screen_view_->buffer_size());
+
+  imported_buffer.Unlock();
+
   screen_view_->Broadcast(buffer_id);
   return 0;
 }  // namespace cvd
 
+bool BaseComposer::IsValidLayer(const hwc_layer_1_t& layer) {
+  auto buffer_opt = gralloc_.Import(layer.handle);
+  if (!buffer_opt) {
+    ALOGE("Failed to import and validate layer buffer handle.");
+    return false;
+  }
+  GrallocBuffer& buffer = *buffer_opt;
+
+  auto buffer_width_opt = buffer.GetWidth();
+  if (!buffer_width_opt) {
+    ALOGE("Failed to get layer buffer width.");
+    return false;
+  }
+  uint32_t buffer_width = *buffer_width_opt;
+
+  auto buffer_height_opt = buffer.GetHeight();
+  if (!buffer_height_opt) {
+    ALOGE("Failed to get layer buffer height.");
+    return false;
+  }
+  uint32_t buffer_height = *buffer_height_opt;
+
+  if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
+      layer.sourceCrop.right > buffer_width ||
+      layer.sourceCrop.bottom > buffer_height) {
+    ALOGE(
+        "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
+        "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
+        "%d]",
+        __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
+        layer.sourceCrop.top, layer.sourceCrop.bottom, buffer_width,
+        buffer_height);
+    return false;
+  }
+  return true;
+}
+
 int BaseComposer::PrepareLayers(size_t num_layers, hwc_layer_1_t* layers) {
   // find unsupported overlays
   for (size_t i = 0; i < num_layers; i++) {
diff --git a/guest/hals/hwcomposer/common/base_composer.h b/guest/hals/hwcomposer/common/base_composer.h
index 69e618a..c1ffbfe 100644
--- a/guest/hals/hwcomposer/common/base_composer.h
+++ b/guest/hals/hwcomposer/common/base_composer.h
@@ -18,6 +18,7 @@
 
 #include <memory>
 
+#include "guest/hals/hwcomposer/common/gralloc_utils.h"
 #include "guest/hals/hwcomposer/common/hwcomposer.h"
 #include "guest/hals/hwcomposer/common/screen_view.h"
 
@@ -28,6 +29,7 @@
   BaseComposer(std::unique_ptr<ScreenView> screen_view);
   virtual ~BaseComposer() = default;
 
+  virtual bool IsValidLayer(const hwc_layer_1_t& layer);
   // Sets the composition type of each layer and returns the number of layers
   // to be composited by the hwcomposer.
   virtual int PrepareLayers(size_t num_layers, hwc_layer_1_t* layers);
@@ -42,7 +44,7 @@
 
  protected:
   std::unique_ptr<ScreenView> screen_view_;
-  const gralloc_module_t* gralloc_module_;
+  Gralloc gralloc_;
 
  private:
   // Returns buffer offset or negative on error.
diff --git a/guest/hals/hwcomposer/common/cpu_composer.cpp b/guest/hals/hwcomposer/common/cpu_composer.cpp
index 35bc701..966aabf 100644
--- a/guest/hals/hwcomposer/common/cpu_composer.cpp
+++ b/guest/hals/hwcomposer/common/cpu_composer.cpp
@@ -21,13 +21,14 @@
 #include <utility>
 #include <vector>
 
+#include <drm_fourcc.h>
 #include <hardware/hwcomposer.h>
 #include <hardware/hwcomposer_defs.h>
 #include <libyuv.h>
 #include <log/log.h>
-#include <system/graphics.h>
 
 #include "common/libs/utils/size_utils.h"
+#include "guest/hals/hwcomposer/common/drm_utils.h"
 #include "guest/hals/hwcomposer/common/geometry_utils.h"
 
 namespace cvd {
@@ -61,59 +62,22 @@
                                  bool v_flip);
 int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
 int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
-ConverterFunction GetConverter(uint32_t format) {
-  switch (format) {
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+
+ConverterFunction GetConverterForDrmFormat(uint32_t drm_format) {
+  switch (drm_format) {
+    case DRM_FORMAT_ABGR8888:
+    case DRM_FORMAT_XBGR8888:
       return &DoCopy;
-
-    case HAL_PIXEL_FORMAT_YV12:
+    case DRM_FORMAT_YVU420:
       return &ConvertFromYV12;
-
-    // Unsupported formats
-    // TODO(jemoreira): Conversion from these formats should be implemented as
-    // we find evidence of its usage.
-    // case HAL_PIXEL_FORMAT_BGRA_8888:
-
-    // case HAL_PIXEL_FORMAT_RGB_888:
-    // case HAL_PIXEL_FORMAT_RGB_565:
-
-    // case HAL_PIXEL_FORMAT_sRGB_A_8888:
-    // case HAL_PIXEL_FORMAT_sRGB_X_8888:
-
-    // case HAL_PIXEL_FORMAT_Y8:
-    // case HAL_PIXEL_FORMAT_Y16:
-
-    // case HAL_PIXEL_FORMAT_RAW_SENSOR:
-    // case HAL_PIXEL_FORMAT_BLOB:
-
-    // case HAL_PIXEL_FORMAT_YCbCr_420_888:
-    // case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-    // case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-    // case HAL_PIXEL_FORMAT_YCbCr_422_I:
-    default:
-      ALOGW("Unsupported format: 0x%04x, returning null converter function",
-            format);
   }
-  return NULL;
+  ALOGW("Unsupported format: %d(%s), returning null converter",
+        drm_format, GetDrmFormatString(drm_format));
+  return nullptr;
 }
 
-// Whether we support a given format
-bool IsFormatSupported(uint32_t format) { return GetConverter(format) != NULL; }
-
-bool CanCompositeLayer(const hwc_layer_1_t& layer) {
-  if (layer.handle == NULL) {
-    ALOGW("%s received a layer with a null handler", __FUNCTION__);
-    return false;
-  }
-  int format = reinterpret_cast<const private_handle_t*>(layer.handle)->format;
-  if (!IsFormatSupported(format)) {
-    ALOGD("Unsupported pixel format: 0x%x, doing software composition instead",
-          format);
-    return false;
-  }
-  return true;
+bool IsDrmFormatSupported(uint32_t drm_format) {
+  return GetConverterForDrmFormat(drm_format) != nullptr;
 }
 
 /*******************************************************************************
@@ -140,66 +104,109 @@
 
 struct BufferSpec {
   uint8_t* buffer;
-  size_t size;
+  std::optional<android_ycbcr> buffer_ycbcr;
   int width;
   int height;
-  int stride;
   int crop_x;
   int crop_y;
   int crop_width;
   int crop_height;
-  uint32_t format;
+  uint32_t drm_format;
+  int stride_bytes;
+  int sample_bytes;
 
-  BufferSpec(uint8_t* buffer, size_t size, int width, int height, int stride)
+  BufferSpec(uint8_t* buffer,
+             std::optional<android_ycbcr> buffer_ycbcr,
+             int width,
+             int height,
+             int crop_x,
+             int crop_y,
+             int crop_width,
+             int crop_height,
+             uint32_t drm_format,
+             int stride_bytes,
+             int sample_bytes)
       : buffer(buffer),
-        size(size),
+        buffer_ycbcr(buffer_ycbcr),
         width(width),
         height(height),
-        stride(stride),
-        crop_x(0),
-        crop_y(0),
-        crop_width(width),
-        crop_height(height),
-        format(HAL_PIXEL_FORMAT_RGBA_8888) {}
+        crop_x(crop_x),
+        crop_y(crop_y),
+        crop_width(crop_width),
+        crop_height(crop_height),
+        drm_format(drm_format),
+        stride_bytes(stride_bytes),
+        sample_bytes(sample_bytes) {}
+
+  BufferSpec(uint8_t* buffer,
+             int width,
+             int height,
+             int stride_bytes)
+      : BufferSpec(buffer,
+                   /*buffer_ycbcr=*/std::nullopt,
+                   width,
+                   height,
+                   /*crop_x=*/0,
+                   /*crop_y=*/0,
+                   /*crop_width=*/width,
+                   /*crop_height=*/height,
+                   /*drm_format=*/DRM_FORMAT_ABGR8888,
+                   stride_bytes,
+                   /*sample_bytes=*/4) {}
+
 };
 
 int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
-  // use the stride in pixels as the source width
-  int stride_in_pixels = src.stride / formatToBytesPerPixel(src.format);
-
   // The following calculation of plane offsets and alignments are based on
   // swiftshader's Sampler::setTextureLevel() implementation
   // (Renderer/Sampler.cpp:225)
-  uint8_t* src_y = src.buffer;
-  int stride_y = stride_in_pixels;
-  uint8_t* src_v = src_y + stride_y * src.height;
-  int stride_v = cvd::AlignToPowerOf2(stride_y / 2, 4);
-  uint8_t* src_u = src_v + stride_v * src.height / 2;
-  int stride_u = cvd::AlignToPowerOf2(stride_y / 2, 4);
+
+  auto& src_buffer_ycbcr_opt = src.buffer_ycbcr;
+  if (!src_buffer_ycbcr_opt) {
+    ALOGE("%s called on non ycbcr buffer", __FUNCTION__);
+    return -1;
+  }
+  auto& src_buffer_ycbcr = *src_buffer_ycbcr_opt;
+
+  // The libyuv::I420ToARGB() function is for tri-planar.
+  if (src_buffer_ycbcr.chroma_step != 1) {
+    ALOGE("%s called with bad chroma step", __FUNCTION__);
+    return -1;
+  }
+
+  uint8_t* src_y = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.y);
+  int stride_y = src_buffer_ycbcr.ystride;
+  uint8_t* src_u = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.cb);
+  int stride_u = src_buffer_ycbcr.cstride;
+  uint8_t* src_v = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.cr);
+  int stride_v = src_buffer_ycbcr.cstride;
 
   // Adjust for crop
   src_y += src.crop_y * stride_y + src.crop_x;
   src_v += (src.crop_y / 2) * stride_v + (src.crop_x / 2);
   src_u += (src.crop_y / 2) * stride_u + (src.crop_x / 2);
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
-                        dst.crop_x * formatToBytesPerPixel(dst.format);
+  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+                        dst.crop_x * dst.sample_bytes;
 
   // YV12 is the same as I420, with the U and V planes swapped
-  return libyuv::I420ToARGB(src_y, stride_y, src_v, stride_v, src_u, stride_u,
-                            dst_buffer, dst.stride, dst.crop_width,
+  return libyuv::I420ToARGB(src_y, stride_y,
+                            src_v, stride_v,
+                            src_u, stride_u,
+                            dst_buffer, dst.stride_bytes,
+                            dst.crop_width,
                             v_flip ? -dst.crop_height : dst.crop_height);
 }
 
 int DoConversion(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
-  return (*GetConverter(src.format))(src, dst, v_flip);
+  return (*GetConverterForDrmFormat(src.drm_format))(src, dst, v_flip);
 }
 
 int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
   // Point to the upper left corner of the crop rectangle
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
-                        src.crop_x * formatToBytesPerPixel(src.format);
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
-                        dst.crop_x * formatToBytesPerPixel(dst.format);
+  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+                        src.crop_x * src.sample_bytes;
+  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+                        dst.crop_x * dst.sample_bytes;
   int width = src.crop_width;
   int height = src.crop_height;
 
@@ -211,17 +218,19 @@
   // byte stream, while libyuv formats are named based on the order of those
   // pixel components in an integer written from left to right. So
   // libyuv::FOURCC_ARGB is equivalent to HAL_PIXEL_FORMAT_BGRA_8888.
-  return libyuv::ARGBCopy(src_buffer, src.stride, dst_buffer, dst.stride, width,
-                          height);
+  auto ret = libyuv::ARGBCopy(src_buffer, src.stride_bytes,
+                              dst_buffer, dst.stride_bytes,
+                              width, height);
+  return ret;
 }
 
 int DoRotation(const BufferSpec& src, const BufferSpec& dst,
                libyuv::RotationMode rotation, bool v_flip) {
   // Point to the upper left corner of the crop rectangles
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
-                        src.crop_x * formatToBytesPerPixel(src.format);
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
-                        dst.crop_x * formatToBytesPerPixel(dst.format);
+  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+                        src.crop_x * src.sample_bytes;
+  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+                        dst.crop_x * dst.sample_bytes;
   int width = src.crop_width;
   int height = src.crop_height;
 
@@ -229,16 +238,17 @@
     height = -height;
   }
 
-  return libyuv::ARGBRotate(src_buffer, src.stride, dst_buffer, dst.stride,
+  return libyuv::ARGBRotate(src_buffer, src.stride_bytes,
+                            dst_buffer, dst.stride_bytes,
                             width, height, rotation);
 }
 
 int DoScaling(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
   // Point to the upper left corner of the crop rectangles
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
-                        src.crop_x * formatToBytesPerPixel(src.format);
-  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
-                        dst.crop_x * formatToBytesPerPixel(dst.format);
+  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+                        src.crop_x * src.sample_bytes;
+  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+                        dst.crop_x * dst.sample_bytes;
   int src_width = src.crop_width;
   int src_height = src.crop_height;
   int dst_width = dst.crop_width;
@@ -248,36 +258,37 @@
     src_height = -src_height;
   }
 
-  return libyuv::ARGBScale(src_buffer, src.stride, src_width, src_height,
-                           dst_buffer, dst.stride, dst_width, dst_height,
+  return libyuv::ARGBScale(src_buffer, src.stride_bytes, src_width, src_height,
+                           dst_buffer, dst.stride_bytes, dst_width, dst_height,
                            libyuv::kFilterBilinear);
 }
 
-int DoAttenuation(const BufferSpec& src, const BufferSpec& dest, bool v_flip) {
+int DoAttenuation(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
   // Point to the upper left corner of the crop rectangles
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
-                        src.crop_x * formatToBytesPerPixel(src.format);
-  uint8_t* dst_buffer = dest.buffer + dest.crop_y * dest.stride +
-                        dest.crop_x * formatToBytesPerPixel(dest.format);
-  int width = dest.crop_width;
-  int height = dest.crop_height;
+  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+                        src.crop_x * src.sample_bytes;
+  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+                        dst.crop_x * dst.sample_bytes;
+  int width = dst.crop_width;
+  int height = dst.crop_height;
 
   if (v_flip) {
     height = -height;
   }
 
-  return libyuv::ARGBAttenuate(src_buffer, src.stride, dst_buffer, dest.stride,
+  return libyuv::ARGBAttenuate(src_buffer, src.stride_bytes,
+                               dst_buffer, dst.stride_bytes,
                                width, height);
 }
 
-int DoBlending(const BufferSpec& src, const BufferSpec& dest, bool v_flip) {
+int DoBlending(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
   // Point to the upper left corner of the crop rectangles
-  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
-                        src.crop_x * formatToBytesPerPixel(src.format);
-  uint8_t* dst_buffer = dest.buffer + dest.crop_y * dest.stride +
-                        dest.crop_x * formatToBytesPerPixel(dest.format);
-  int width = dest.crop_width;
-  int height = dest.crop_height;
+  uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+                        src.crop_x * src.sample_bytes;
+  uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+                        dst.crop_x * dst.sample_bytes;
+  int width = dst.crop_width;
+  int height = dst.crop_height;
 
   if (v_flip) {
     height = -height;
@@ -286,21 +297,127 @@
   // libyuv's ARGB format is hwcomposer's BGRA format, since blending only cares
   // for the position of alpha in the pixel and not the position of the colors
   // this function is perfectly usable.
-  return libyuv::ARGBBlend(src_buffer, src.stride, dst_buffer, dest.stride,
-                           dst_buffer, dest.stride, width, height);
+  return libyuv::ARGBBlend(src_buffer, src.stride_bytes,
+                           dst_buffer, dst.stride_bytes,
+                           dst_buffer, dst.stride_bytes,
+                           width, height);
+}
+
+std::optional<BufferSpec> GetBufferSpec(GrallocBuffer& buffer,
+                                        const hwc_rect_t& buffer_crop) {
+  auto buffer_format_opt = buffer.GetDrmFormat();
+  if (!buffer_format_opt) {
+    ALOGE("Failed to get gralloc buffer format.");
+    return std::nullopt;
+  }
+  uint32_t buffer_format = *buffer_format_opt;
+
+  auto buffer_width_opt = buffer.GetWidth();
+  if (!buffer_width_opt) {
+    ALOGE("Failed to get gralloc buffer width.");
+    return std::nullopt;
+  }
+  uint32_t buffer_width = *buffer_width_opt;
+
+  auto buffer_height_opt = buffer.GetHeight();
+  if (!buffer_height_opt) {
+    ALOGE("Failed to get gralloc buffer height.");
+    return std::nullopt;
+  }
+  uint32_t buffer_height = *buffer_height_opt;
+
+  uint8_t* buffer_data = nullptr;
+  uint32_t buffer_stride_bytes = 0;
+  std::optional<android_ycbcr> buffer_ycbcr_data;
+
+  if (buffer_format == DRM_FORMAT_NV12 ||
+      buffer_format == DRM_FORMAT_NV21 ||
+      buffer_format == DRM_FORMAT_YVU420) {
+    buffer_ycbcr_data = buffer.LockYCbCr();
+    if (!buffer_ycbcr_data) {
+      ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
+      return std::nullopt;
+    }
+  } else {
+    auto buffer_data_opt = buffer.Lock();
+    if (!buffer_data_opt) {
+      ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
+      return std::nullopt;
+    }
+    buffer_data = reinterpret_cast<uint8_t*>(*buffer_data_opt);
+
+    auto buffer_stride_bytes_opt = buffer.GetMonoPlanarStrideBytes();
+    if (!buffer_stride_bytes_opt) {
+      ALOGE("%s failed to get plane stride.", __FUNCTION__);
+      return std::nullopt;
+    }
+    buffer_stride_bytes = *buffer_stride_bytes_opt;
+  }
+
+  return BufferSpec(
+      buffer_data,
+      buffer_ycbcr_data,
+      buffer_width,
+      buffer_height,
+      buffer_crop.left,
+      buffer_crop.top,
+      buffer_crop.right - buffer_crop.left,
+      buffer_crop.bottom - buffer_crop.top,
+      buffer_format,
+      buffer_stride_bytes,
+      GetDrmFormatBytesPerPixel(buffer_format));
 }
 
 }  // namespace
 
+bool CpuComposer::CanCompositeLayer(const hwc_layer_1_t& layer) {
+  buffer_handle_t buffer_handle = layer.handle;
+  if (buffer_handle == nullptr) {
+    ALOGW("%s received a layer with a null handle", __FUNCTION__);
+    return false;
+  }
+
+  auto buffer_opt = gralloc_.Import(buffer_handle);
+  if (!buffer_opt) {
+    ALOGE("Failed to import layer buffer.");
+    return false;
+  }
+  GrallocBuffer& buffer = *buffer_opt;
+
+  auto buffer_format_opt = buffer.GetDrmFormat();
+  if (!buffer_format_opt) {
+    ALOGE("Failed to get layer buffer format.");
+    return false;
+  }
+  uint32_t buffer_format = *buffer_format_opt;
+
+  if (!IsDrmFormatSupported(buffer_format)) {
+    ALOGD("Unsupported pixel format: 0x%x, doing software composition instead",
+          buffer_format);
+    return false;
+  }
+  return true;
+}
+
 void CpuComposer::CompositeLayer(hwc_layer_1_t* src_layer, int buffer_idx) {
   libyuv::RotationMode rotation =
       GetRotationFromTransform(src_layer->transform);
 
-  const private_handle_t* src_priv_handle =
-      reinterpret_cast<const private_handle_t*>(src_layer->handle);
+  auto src_imported_buffer_opt = gralloc_.Import(src_layer->handle);
+  if (!src_imported_buffer_opt) {
+    ALOGE("Failed to import layer buffer.");
+    return;
+  }
+  GrallocBuffer& src_imported_buffer = *src_imported_buffer_opt;
+
+  auto src_layer_spec_opt = GetBufferSpec(src_imported_buffer, src_layer->sourceCrop);
+  if (!src_layer_spec_opt) {
+    return;
+  }
+  BufferSpec src_layer_spec = *src_layer_spec_opt;
 
   // TODO(jemoreira): Remove the hardcoded fomat.
-  bool needs_conversion = src_priv_handle->format != HAL_PIXEL_FORMAT_RGBX_8888;
+  bool needs_conversion = src_layer_spec.drm_format != DRM_FORMAT_XBGR8888;
   bool needs_scaling = LayerNeedsScaling(*src_layer);
   bool needs_rotation = rotation != libyuv::kRotate0;
   bool needs_transpose = needs_rotation && rotation != libyuv::kRotate180;
@@ -310,47 +427,21 @@
   bool needs_copy = !(needs_conversion || needs_scaling || needs_rotation ||
                       needs_vflip || needs_attenuation || needs_blending);
 
-  uint8_t* src_buffer;
   uint8_t* dst_buffer =
-      reinterpret_cast<uint8_t*>(screen_view_->GetBuffer(buffer_idx));
-  int retval = gralloc_module_->lock(
-      gralloc_module_, src_layer->handle, GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
-      src_priv_handle->x_res, src_priv_handle->y_res,
-      reinterpret_cast<void**>(&src_buffer));
-  if (retval) {
-    ALOGE("Got error code %d from lock function", retval);
-    return;
-  }
-  if (retval) {
-    ALOGE("Got error code %d from lock function", retval);
-    // TODO(jemoreira): Use a lock_guard-like object.
-    gralloc_module_->unlock(gralloc_module_, src_priv_handle);
-    return;
-  }
+    reinterpret_cast<uint8_t*>(screen_view_->GetBuffer(buffer_idx));
 
-  BufferSpec src_layer_spec(src_buffer, src_priv_handle->total_size,
-                            src_priv_handle->x_res, src_priv_handle->y_res,
-                            src_priv_handle->stride_in_pixels *
-                                formatToBytesPerPixel(src_priv_handle->format));
-  src_layer_spec.crop_x = src_layer->sourceCrop.left;
-  src_layer_spec.crop_y = src_layer->sourceCrop.top;
-  src_layer_spec.crop_width =
-      src_layer->sourceCrop.right - src_layer->sourceCrop.left;
-  src_layer_spec.crop_height =
-      src_layer->sourceCrop.bottom - src_layer->sourceCrop.top;
-  src_layer_spec.format = src_priv_handle->format;
-
-  BufferSpec dst_layer_spec(dst_buffer, screen_view_->buffer_size(),
-                            screen_view_->x_res(), screen_view_->y_res(),
-                            screen_view_->line_length());
-  dst_layer_spec.crop_x = src_layer->displayFrame.left;
-  dst_layer_spec.crop_y = src_layer->displayFrame.top;
-  dst_layer_spec.crop_width =
-      src_layer->displayFrame.right - src_layer->displayFrame.left;
-  dst_layer_spec.crop_height =
-      src_layer->displayFrame.bottom - src_layer->displayFrame.top;
-  // TODO(jemoreira): Remove the hardcoded fomat.
-  dst_layer_spec.format = HAL_PIXEL_FORMAT_RGBX_8888;
+  BufferSpec dst_layer_spec(
+      dst_buffer,
+      /*buffer_ycbcr=*/std::nullopt,
+      screen_view_->x_res(),
+      screen_view_->y_res(),
+      src_layer->displayFrame.left,
+      src_layer->displayFrame.top,
+      src_layer->displayFrame.right - src_layer->displayFrame.left,
+      src_layer->displayFrame.bottom - src_layer->displayFrame.top,
+      DRM_FORMAT_XBGR8888,
+      screen_view_->line_length(),
+      4);
 
   // Add the destination layer to the bottom of the buffer stack
   std::vector<BufferSpec> dest_buffer_stack(1, dst_layer_spec);
@@ -367,16 +458,20 @@
                            (needs_attenuation ? 1 : 0) +
                            (needs_blending ? 1 : 0) + (needs_copy ? 1 : 0) - 1;
 
-  int x_res = src_layer->displayFrame.right - src_layer->displayFrame.left;
-  int y_res = src_layer->displayFrame.bottom - src_layer->displayFrame.top;
-  size_t output_frame_size =
-      x_res * cvd::AlignToPowerOf2(y_res * screen_view_->bytes_per_pixel(), 4);
-  while (needed_tmp_buffers > 0) {
-    BufferSpec tmp(
-        RotateTmpBuffer(needed_tmp_buffers), output_frame_size, x_res, y_res,
-        cvd::AlignToPowerOf2(x_res * screen_view_->bytes_per_pixel(), 4));
-    dest_buffer_stack.push_back(tmp);
-    needed_tmp_buffers--;
+  int tmp_buffer_width =
+      src_layer->displayFrame.right - src_layer->displayFrame.left;
+  int tmp_buffer_height =
+      src_layer->displayFrame.bottom - src_layer->displayFrame.top;
+  int tmp_buffer_stride_bytes =
+      cvd::AlignToPowerOf2(tmp_buffer_width * screen_view_->bytes_per_pixel(), 4);
+
+  for (int i = 0; i < needed_tmp_buffers; i++) {
+    BufferSpec tmp_buffer_spec(
+        RotateTmpBuffer(i),
+        tmp_buffer_width,
+        tmp_buffer_height,
+        tmp_buffer_stride_bytes);
+    dest_buffer_stack.push_back(tmp_buffer_spec);
   }
 
   // Conversion and scaling should always be the first operations, so that every
@@ -395,17 +490,16 @@
       // Make width and height match the crop sizes on the source
       int src_width = src_layer_spec.crop_width;
       int src_height = src_layer_spec.crop_height;
-      int dst_stride =
+      int dst_stride_bytes =
           cvd::AlignToPowerOf2(src_width * screen_view_->bytes_per_pixel(), 4);
-      size_t needed_size = dst_stride * src_height;
+      size_t needed_size = dst_stride_bytes * src_height;
       dst_buffer_spec.width = src_width;
       dst_buffer_spec.height = src_height;
-      // Ajust the stride accordingly
-      dst_buffer_spec.stride = dst_stride;
+      // Adjust the stride accordingly
+      dst_buffer_spec.stride_bytes = dst_stride_bytes;
       // Crop sizes also need to be adjusted
       dst_buffer_spec.crop_width = src_width;
       dst_buffer_spec.crop_height = src_height;
-      dst_buffer_spec.size = needed_size;
       // crop_x and y are fine at 0, format is already set to match destination
 
       // In case of a scale, the source frame may be bigger than the default tmp
@@ -414,7 +508,8 @@
         dst_buffer_spec.buffer = GetSpecialTmpBuffer(needed_size);
       }
     }
-    retval = DoConversion(src_layer_spec, dst_buffer_spec, needs_vflip);
+
+    int retval = DoConversion(src_layer_spec, dst_buffer_spec, needs_vflip);
     if (retval) {
       ALOGE("Got error code %d from DoConversion function", retval);
     }
@@ -435,10 +530,10 @@
       std::swap(dst_buffer_spec.crop_width, dst_buffer_spec.crop_height);
       // TODO (jemoreira): Aligment (To align here may cause the needed size to
       // be bigger than the buffer, so care should be taken)
-      dst_buffer_spec.stride =
+      dst_buffer_spec.stride_bytes =
           dst_buffer_spec.width * screen_view_->bytes_per_pixel();
     }
-    retval = DoScaling(src_layer_spec, dst_buffer_spec, needs_vflip);
+    int retval = DoScaling(src_layer_spec, dst_buffer_spec, needs_vflip);
     needs_vflip = false;
     if (retval) {
       ALOGE("Got error code %d from DoScaling function", retval);
@@ -448,8 +543,8 @@
   }
 
   if (needs_rotation) {
-    retval = DoRotation(src_layer_spec, dest_buffer_stack.back(), rotation,
-                        needs_vflip);
+    int retval = DoRotation(src_layer_spec, dest_buffer_stack.back(), rotation,
+                            needs_vflip);
     needs_vflip = false;
     if (retval) {
       ALOGE("Got error code %d from DoTransform function", retval);
@@ -459,8 +554,8 @@
   }
 
   if (needs_attenuation) {
-    retval =
-        DoAttenuation(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
+    int retval = DoAttenuation(src_layer_spec, dest_buffer_stack.back(),
+                               needs_vflip);
     needs_vflip = false;
     if (retval) {
       ALOGE("Got error code %d from DoBlending function", retval);
@@ -470,7 +565,7 @@
   }
 
   if (needs_copy) {
-    retval = DoCopy(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
+    int retval = DoCopy(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
     needs_vflip = false;
     if (retval) {
       ALOGE("Got error code %d from DoBlending function", retval);
@@ -482,7 +577,8 @@
   // Blending (if needed) should always be the last operation, so that it reads
   // and writes in the destination layer and not some temporary buffer.
   if (needs_blending) {
-    retval = DoBlending(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
+    int retval = DoBlending(src_layer_spec, dest_buffer_stack.back(),
+                            needs_vflip);
     needs_vflip = false;
     if (retval) {
       ALOGE("Got error code %d from DoBlending function", retval);
@@ -491,7 +587,7 @@
     dest_buffer_stack.pop_back();
   }
 
-  gralloc_module_->unlock(gralloc_module_, src_priv_handle);
+  src_imported_buffer.Unlock();
 }
 
 /* static */ const int CpuComposer::kNumTmpBufferPieces = 2;
diff --git a/guest/hals/hwcomposer/common/cpu_composer.h b/guest/hals/hwcomposer/common/cpu_composer.h
index a4ace22..f331e2d 100644
--- a/guest/hals/hwcomposer/common/cpu_composer.h
+++ b/guest/hals/hwcomposer/common/cpu_composer.h
@@ -20,8 +20,6 @@
 
 #include <hardware/gralloc.h>
 
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
 #include "guest/hals/hwcomposer/common/base_composer.h"
 #include "guest/hals/hwcomposer/common/hwcomposer.h"
 
@@ -41,6 +39,7 @@
   static const int kNumTmpBufferPieces;
   uint8_t* RotateTmpBuffer(unsigned int order);
   uint8_t* GetSpecialTmpBuffer(size_t needed_size);
+  bool CanCompositeLayer(const hwc_layer_1_t& layer);
   void CompositeLayer(hwc_layer_1_t* src_layer, int32_t fb_offset);
   std::vector<uint8_t> tmp_buffer_;
   std::vector<uint8_t> special_tmp_buffer_;
diff --git a/guest/hals/hwcomposer/common/drm_utils.cpp b/guest/hals/hwcomposer/common/drm_utils.cpp
new file mode 100644
index 0000000..d4c864e
--- /dev/null
+++ b/guest/hals/hwcomposer/common/drm_utils.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "guest/hals/hwcomposer/common/drm_utils.h"
+
+#include <drm_fourcc.h>
+#include <log/log.h>
+#include <system/graphics.h>
+
+namespace cvd {
+
+const char* GetDrmFormatString(uint32_t drm_format) {
+  switch (drm_format) {
+    case DRM_FORMAT_ABGR1555:
+      return "DRM_FORMAT_ABGR1555";
+    case DRM_FORMAT_ABGR2101010:
+      return "DRM_FORMAT_ABGR2101010";
+    case DRM_FORMAT_ABGR4444:
+      return "DRM_FORMAT_ABGR4444";
+    case DRM_FORMAT_ABGR8888:
+      return "DRM_FORMAT_ABGR8888";
+    case DRM_FORMAT_ARGB1555:
+      return "DRM_FORMAT_ARGB1555";
+    case DRM_FORMAT_ARGB2101010:
+      return "DRM_FORMAT_ARGB2101010";
+    case DRM_FORMAT_ARGB4444:
+      return "DRM_FORMAT_ARGB4444";
+    case DRM_FORMAT_ARGB8888:
+      return "DRM_FORMAT_ARGB8888";
+    case DRM_FORMAT_AYUV:
+      return "DRM_FORMAT_AYUV";
+    case DRM_FORMAT_BGR233:
+      return "DRM_FORMAT_BGR233";
+    case DRM_FORMAT_BGR565:
+      return "DRM_FORMAT_BGR565";
+    case DRM_FORMAT_BGR888:
+      return "DRM_FORMAT_BGR888";
+    case DRM_FORMAT_BGRA1010102:
+      return "DRM_FORMAT_BGRA1010102";
+    case DRM_FORMAT_BGRA4444:
+      return "DRM_FORMAT_BGRA4444";
+    case DRM_FORMAT_BGRA5551:
+      return "DRM_FORMAT_BGRA5551";
+    case DRM_FORMAT_BGRA8888:
+      return "DRM_FORMAT_BGRA8888";
+    case DRM_FORMAT_BGRX1010102:
+      return "DRM_FORMAT_BGRX1010102";
+    case DRM_FORMAT_BGRX4444:
+      return "DRM_FORMAT_BGRX4444";
+    case DRM_FORMAT_BGRX5551:
+      return "DRM_FORMAT_BGRX5551";
+    case DRM_FORMAT_BGRX8888:
+      return "DRM_FORMAT_BGRX8888";
+    case DRM_FORMAT_C8:
+      return "DRM_FORMAT_C8";
+    case DRM_FORMAT_GR88:
+      return "DRM_FORMAT_GR88";
+    case DRM_FORMAT_NV12:
+      return "DRM_FORMAT_NV12";
+    case DRM_FORMAT_NV21:
+      return "DRM_FORMAT_NV21";
+    case DRM_FORMAT_R8:
+      return "DRM_FORMAT_R8";
+    case DRM_FORMAT_RG88:
+      return "DRM_FORMAT_RG88";
+    case DRM_FORMAT_RGB332:
+      return "DRM_FORMAT_RGB332";
+    case DRM_FORMAT_RGB565:
+      return "DRM_FORMAT_RGB565";
+    case DRM_FORMAT_RGB888:
+      return "DRM_FORMAT_RGB888";
+    case DRM_FORMAT_RGBA1010102:
+      return "DRM_FORMAT_RGBA1010102";
+    case DRM_FORMAT_RGBA4444:
+      return "DRM_FORMAT_RGBA4444";
+    case DRM_FORMAT_RGBA5551:
+      return "DRM_FORMAT_RGBA5551";
+    case DRM_FORMAT_RGBA8888:
+      return "DRM_FORMAT_RGBA8888";
+    case DRM_FORMAT_RGBX1010102:
+      return "DRM_FORMAT_RGBX1010102";
+    case DRM_FORMAT_RGBX4444:
+      return "DRM_FORMAT_RGBX4444";
+    case DRM_FORMAT_RGBX5551:
+      return "DRM_FORMAT_RGBX5551";
+    case DRM_FORMAT_RGBX8888:
+      return "DRM_FORMAT_RGBX8888";
+    case DRM_FORMAT_UYVY:
+      return "DRM_FORMAT_UYVY";
+    case DRM_FORMAT_VYUY:
+      return "DRM_FORMAT_VYUY";
+    case DRM_FORMAT_XBGR1555:
+      return "DRM_FORMAT_XBGR1555";
+    case DRM_FORMAT_XBGR2101010:
+      return "DRM_FORMAT_XBGR2101010";
+    case DRM_FORMAT_XBGR4444:
+      return "DRM_FORMAT_XBGR4444";
+    case DRM_FORMAT_XBGR8888:
+      return "DRM_FORMAT_XBGR8888";
+    case DRM_FORMAT_XRGB1555:
+      return "DRM_FORMAT_XRGB1555";
+    case DRM_FORMAT_XRGB2101010:
+      return "DRM_FORMAT_XRGB2101010";
+    case DRM_FORMAT_XRGB4444:
+      return "DRM_FORMAT_XRGB4444";
+    case DRM_FORMAT_XRGB8888:
+      return "DRM_FORMAT_XRGB8888";
+    case DRM_FORMAT_YUYV:
+      return "DRM_FORMAT_YUYV";
+    case DRM_FORMAT_YVU420:
+      return "DRM_FORMAT_YVU420";
+    case DRM_FORMAT_YVYU:
+      return "DRM_FORMAT_YVYU";
+  }
+  return "Unknown";
+}
+
+int GetDrmFormatBytesPerPixel(uint32_t drm_format) {
+  switch (drm_format) {
+    case DRM_FORMAT_ABGR8888:
+    case DRM_FORMAT_ARGB8888:
+    case DRM_FORMAT_XBGR8888:
+      return 4;
+    case DRM_FORMAT_BGR888:
+      return 3;
+    case DRM_FORMAT_RGB565:
+    case DRM_FORMAT_YVU420:
+#ifdef GRALLOC_MODULE_API_VERSION_0_2
+    case DRM_FORMAT_FLEX_YCbCr_420_888:
+#endif
+      return 2;
+    case DRM_FORMAT_R8:
+      return 1;
+  }
+  ALOGE("%s: format size unknown %d(%s)", __FUNCTION__, drm_format,
+        GetDrmFormatString(drm_format));
+  return 8;
+}
+
+int GetDrmFormatFromHalFormat(int hal_format) {
+  switch (hal_format) {
+    case HAL_PIXEL_FORMAT_RGBA_FP16:
+      return DRM_FORMAT_ABGR16161616F;
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+      return DRM_FORMAT_ABGR8888;
+    case HAL_PIXEL_FORMAT_RGBX_8888:
+      return DRM_FORMAT_XBGR8888;
+    case HAL_PIXEL_FORMAT_BGRA_8888:
+      return DRM_FORMAT_ARGB8888;
+    case HAL_PIXEL_FORMAT_RGB_888:
+      return DRM_FORMAT_BGR888;
+    case HAL_PIXEL_FORMAT_RGB_565:
+      return DRM_FORMAT_BGR565;
+    case HAL_PIXEL_FORMAT_YV12:
+      return DRM_FORMAT_YVU420;
+    case HAL_PIXEL_FORMAT_YCbCr_420_888:
+      return DRM_FORMAT_YVU420;
+    case HAL_PIXEL_FORMAT_BLOB:
+      return DRM_FORMAT_R8;
+    default:
+      break;
+  }
+  ALOGE("%s unhandled hal format: %d", __FUNCTION__, hal_format);
+  return 0;
+}
+
+}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/drm_utils.h b/guest/hals/hwcomposer/common/drm_utils.h
new file mode 100644
index 0000000..15f788d
--- /dev/null
+++ b/guest/hals/hwcomposer/common/drm_utils.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 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 <cstdlib>
+
+namespace cvd {
+
+const char* GetDrmFormatString(uint32_t drm_format);
+
+int GetDrmFormatBytesPerPixel(uint32_t drm_format);
+
+int GetDrmFormatFromHalFormat(int hal_format);
+
+}  // namespace cvd
diff --git a/guest/hals/hwcomposer/common/gralloc_utils.cpp b/guest/hals/hwcomposer/common/gralloc_utils.cpp
new file mode 100644
index 0000000..bb2350f
--- /dev/null
+++ b/guest/hals/hwcomposer/common/gralloc_utils.cpp
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "guest/hals/hwcomposer/common/gralloc_utils.h"
+
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
+#include <drm_fourcc.h>
+#include <gralloctypes/Gralloc4.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+// TODO(b/146515640): remove this.
+#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
+#include "guest/hals/hwcomposer/common/drm_utils.h"
+
+using aidl::android::hardware::graphics::common::PlaneLayout;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::IMapper;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using MetadataType =
+  android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+
+// TODO(b/146515640): remove this.
+using cuttlefish_gralloc0_buffer_handle_t = private_handle_t;
+
+namespace cvd {
+
+Gralloc::Gralloc() {
+  android::hardware::preloadPassthroughService<IMapper>();
+
+  gralloc4_ = IMapper::getService();
+  if (gralloc4_ != nullptr) {
+    ALOGE("%s using Gralloc4.", __FUNCTION__);
+    return;
+  }
+  ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+
+
+  hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+                reinterpret_cast<const hw_module_t**>(&gralloc0_));
+  if (gralloc0_ != nullptr) {
+    ALOGE("%s using Gralloc0.", __FUNCTION__);
+    return;
+  }
+  ALOGE("%s Gralloc0 not available.", __FUNCTION__);
+
+  ALOGE("%s No Grallocs available!", __FUNCTION__);
+}
+
+Error Gralloc::GetMetadata(buffer_handle_t buffer, MetadataType type,
+                           hidl_vec<uint8_t>* metadata) {
+  if (gralloc4_ == nullptr) {
+    ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+    return Error::NO_RESOURCES;
+  }
+
+  if (metadata == nullptr) {
+    return Error::BAD_VALUE;
+  }
+
+  Error error = Error::NONE;
+
+  auto native_handle = const_cast<native_handle_t*>(buffer);
+
+  auto ret = gralloc4_->get(native_handle, type,
+                            [&](const auto& get_error, const auto& get_metadata) {
+                              error = get_error;
+                              *metadata = get_metadata;
+                            });
+
+  if (!ret.isOk()) {
+    error = Error::NO_RESOURCES;
+  }
+
+  if (error != Error::NONE) {
+    ALOGE("%s failed to get metadata %s", __FUNCTION__, type.name.c_str());
+  }
+  return error;
+}
+
+std::optional<uint32_t> Gralloc::GetWidth(buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    hidl_vec<uint8_t> encoded_width;
+
+    Error error = GetMetadata(buffer, android::gralloc4::MetadataType_Width,
+                              &encoded_width);
+    if (error != Error::NONE) {
+      return std::nullopt;
+    }
+
+    uint64_t width = 0;
+    android::gralloc4::decodeWidth(encoded_width, &width);
+    return static_cast<uint32_t>(width);
+  }
+  if (gralloc0_ != nullptr) {
+    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+    return gralloc0_buffer->x_res;
+  }
+  return std::nullopt;
+}
+
+std::optional<uint32_t> Gralloc::GetHeight(buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    hidl_vec<uint8_t> encoded_height;
+
+    Error error = GetMetadata(buffer, android::gralloc4::MetadataType_Height,
+                              &encoded_height);
+    if (error != Error::NONE) {
+      return std::nullopt;
+    }
+
+    uint64_t height = 0;
+    android::gralloc4::decodeHeight(encoded_height, &height);
+    return static_cast<uint32_t>(height);
+  }
+  if (gralloc0_ != nullptr) {
+    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+    return gralloc0_buffer->y_res;
+  }
+  return std::nullopt;
+}
+
+std::optional<uint32_t> Gralloc::GetDrmFormat(buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    hidl_vec<uint8_t> encoded_format;
+
+    Error error = GetMetadata(buffer,
+                              android::gralloc4::MetadataType_PixelFormatFourCC,
+                              &encoded_format);
+    if (error != Error::NONE) {
+      return std::nullopt;
+    }
+
+    uint32_t format = 0;
+    android::gralloc4::decodePixelFormatFourCC(encoded_format, &format);
+    return static_cast<uint32_t>(format);
+  }
+  if (gralloc0_ != nullptr) {
+    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+    return GetDrmFormatFromHalFormat(gralloc0_buffer->format);
+  }
+  return std::nullopt;
+}
+
+std::optional<std::vector<PlaneLayout>> Gralloc::GetPlaneLayouts(
+    buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    hidl_vec<uint8_t> encoded_layouts;
+
+    Error error = GetMetadata(buffer,
+                              android::gralloc4::MetadataType_PlaneLayouts,
+                              &encoded_layouts);
+    if (error != Error::NONE) {
+      return std::nullopt;
+    }
+
+    std::vector<PlaneLayout> plane_layouts;
+    android::gralloc4::decodePlaneLayouts(encoded_layouts, &plane_layouts);
+    return plane_layouts;
+  }
+  return std::nullopt;
+}
+
+std::optional<uint32_t> Gralloc::GetMonoPlanarStrideBytes(
+    buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    auto plane_layouts_opt = GetPlaneLayouts(buffer);
+    if (!plane_layouts_opt) {
+      return std::nullopt;
+    }
+
+    std::vector<PlaneLayout>& plane_layouts = *plane_layouts_opt;
+    if (plane_layouts.size() != 1) {
+      return std::nullopt;
+    }
+
+    return static_cast<uint32_t>(plane_layouts[0].strideInBytes);
+  }
+  if (gralloc0_ != nullptr) {
+    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+    int bytes_per_pixel = formatToBytesPerPixel(gralloc0_buffer->format);
+    return gralloc0_buffer->stride_in_pixels * bytes_per_pixel;
+  }
+  return std::nullopt;
+}
+
+std::optional<GrallocBuffer> Gralloc::Import(buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    buffer_handle_t imported_buffer;
+
+    Error error;
+    auto ret = gralloc4_->importBuffer(buffer,
+                                       [&](const auto& err, const auto& buf) {
+                                         error = err;
+                                         if (err == Error::NONE) {
+                                           imported_buffer =
+                                             static_cast<buffer_handle_t>(buf);
+                                         }
+                                        });
+
+    if (!ret.isOk() || error != Error::NONE) {
+      ALOGE("%s failed to import buffer", __FUNCTION__);
+      return std::nullopt;
+    }
+    return GrallocBuffer(this, imported_buffer);
+  }
+  if (gralloc0_ != nullptr) {
+    return GrallocBuffer(this, buffer);
+  }
+  return std::nullopt;
+}
+
+void Gralloc::Release(buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    auto native_buffer = const_cast<native_handle_t*>(buffer);
+    auto ret = gralloc4_->freeBuffer(native_buffer);
+
+    if (!ret.isOk()) {
+      ALOGE("%s failed to release buffer", __FUNCTION__);
+    }
+    return;
+  }
+  if (gralloc0_) {
+    // no-opt
+  }
+}
+
+std::optional<void*> Gralloc::Lock(buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    auto native_buffer = const_cast<native_handle_t*>(buffer);
+
+    const auto buffer_usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN);
+
+    auto width_opt = GetWidth(buffer);
+    if (!width_opt) {
+      return std::nullopt;
+    }
+
+    auto height_opt = GetHeight(buffer);
+    if (!height_opt) {
+      return std::nullopt;
+    }
+
+    IMapper::Rect buffer_region;
+    buffer_region.left = 0;
+    buffer_region.top = 0;
+    buffer_region.width = *width_opt;
+    buffer_region.height = *height_opt;
+
+    // Empty fence, lock immedietly.
+    hidl_handle fence;
+
+    Error error = Error::NONE;
+    void* data = nullptr;
+
+    auto ret = gralloc4_->lock(native_buffer, buffer_usage, buffer_region,
+                               fence,
+                               [&](const auto& lock_error,
+                                   const auto& lock_data) {
+                                 error = lock_error;
+                                 if (lock_error == Error::NONE) {
+                                  data = lock_data;
+                                }
+                               });
+
+    if (!ret.isOk()) {
+      error = Error::NO_RESOURCES;
+    }
+
+    if (error != Error::NONE) {
+      ALOGE("%s failed to lock buffer", __FUNCTION__);
+      return std::nullopt;
+    }
+
+    return data;
+  }
+  if (gralloc0_ != nullptr) {
+    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+    void* data = nullptr;
+    int ret = gralloc0_->lock(gralloc0_,
+                              gralloc0_buffer,
+                              GRALLOC_USAGE_SW_READ_OFTEN,
+                              0,
+                              0,
+                              gralloc0_buffer->x_res,
+                              gralloc0_buffer->y_res,
+                              &data);
+
+    if (ret) {
+      ALOGE("%s failed to lock buffer", __FUNCTION__);
+      return std::nullopt;
+    }
+    return data;
+  }
+  return std::nullopt;
+}
+
+std::optional<android_ycbcr> Gralloc::LockYCbCr(buffer_handle_t buffer) {
+  auto format_opt = GetDrmFormat(buffer);
+  if (!format_opt) {
+    ALOGE("%s failed to check format of buffer", __FUNCTION__);
+    return std::nullopt;
+  }
+
+  if (*format_opt != DRM_FORMAT_NV12 &&
+      *format_opt != DRM_FORMAT_NV21 &&
+      *format_opt != DRM_FORMAT_YVU420) {
+    ALOGE("%s called on non-ycbcr buffer", __FUNCTION__);
+    return std::nullopt;
+  }
+
+  if (gralloc4_ != nullptr) {
+    auto lock_opt = Lock(buffer);
+    if (!lock_opt) {
+      ALOGE("%s failed to lock buffer", __FUNCTION__);
+      return std::nullopt;
+    }
+
+    auto plane_layouts_opt = GetPlaneLayouts(buffer);
+    if (!plane_layouts_opt) {
+      ALOGE("%s failed to get plane layouts", __FUNCTION__);
+      return std::nullopt;
+    }
+
+    android_ycbcr buffer_ycbcr;
+    buffer_ycbcr.y = nullptr;
+    buffer_ycbcr.cb = nullptr;
+    buffer_ycbcr.cr = nullptr;
+    buffer_ycbcr.ystride = 0;
+    buffer_ycbcr.cstride = 0;
+    buffer_ycbcr.chroma_step = 0;
+
+    for (const auto& plane_layout : *plane_layouts_opt) {
+      for (const auto& plane_layout_component : plane_layout.components) {
+        const auto& type = plane_layout_component.type;
+
+        if (!android::gralloc4::isStandardPlaneLayoutComponentType(type)) {
+          continue;
+        }
+
+        auto* component_data =
+          reinterpret_cast<uint8_t*>(*lock_opt) +
+          plane_layout.offsetInBytes +
+          plane_layout_component.offsetInBits / 8;
+
+        switch (static_cast<PlaneLayoutComponentType>(type.value)) {
+          case PlaneLayoutComponentType::Y:
+            buffer_ycbcr.y = component_data;
+            buffer_ycbcr.ystride = plane_layout.strideInBytes;
+            break;
+          case PlaneLayoutComponentType::CB:
+            buffer_ycbcr.cb = component_data;
+            buffer_ycbcr.cstride = plane_layout.strideInBytes;
+            buffer_ycbcr.chroma_step = plane_layout.sampleIncrementInBits / 8;
+            break;
+          case PlaneLayoutComponentType::CR:
+            buffer_ycbcr.cr = component_data;
+            buffer_ycbcr.cstride = plane_layout.strideInBytes;
+            buffer_ycbcr.chroma_step = plane_layout.sampleIncrementInBits / 8;
+            break;
+          default:
+            break;
+        }
+      }
+    }
+
+    return buffer_ycbcr;
+  }
+  if (gralloc0_ != nullptr) {
+    auto lock_opt = Lock(buffer);
+    if (!lock_opt) {
+      ALOGE("%s failed to lock buffer", __FUNCTION__);
+      return std::nullopt;
+    }
+    void* data = *lock_opt;
+
+    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+    android_ycbcr buffer_ycbcr;
+    formatToYcbcr(gralloc0_buffer->format,
+                  gralloc0_buffer->x_res,
+                  gralloc0_buffer->y_res,
+                  data,
+                  &buffer_ycbcr);
+    return buffer_ycbcr;
+  }
+  return std::nullopt;
+}
+
+void Gralloc::Unlock(buffer_handle_t buffer) {
+  if (gralloc4_ != nullptr) {
+    auto native_handle = const_cast<native_handle_t*>(buffer);
+
+    Error error = Error::NONE;
+    auto ret = gralloc4_->unlock(native_handle,
+                               [&](const auto& unlock_error, const auto&) {
+                                 error = unlock_error;
+                               });
+
+    if (!ret.isOk()) {
+      error = Error::NO_RESOURCES;
+    }
+
+    if (error != Error::NONE) {
+      ALOGE("%s failed to unlock buffer", __FUNCTION__);
+    }
+    return;
+  }
+  if (gralloc0_ != nullptr) {
+    const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+      reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+    gralloc0_->unlock(gralloc0_, gralloc0_buffer);
+    return;
+  }
+}
+
+
+GrallocBuffer::GrallocBuffer(Gralloc* gralloc, buffer_handle_t buffer) :
+  gralloc_(gralloc), buffer_(buffer) {}
+
+GrallocBuffer::~GrallocBuffer() {  Release(); }
+
+GrallocBuffer::GrallocBuffer(GrallocBuffer&& rhs) {
+  *this = std::move(rhs);
+}
+
+GrallocBuffer& GrallocBuffer::operator=(GrallocBuffer&& rhs) {
+  gralloc_ = rhs.gralloc_;
+  buffer_ = rhs.buffer_;
+  rhs.gralloc_ = nullptr;
+  rhs.buffer_ = nullptr;
+  return *this;
+}
+
+void GrallocBuffer::Release() {
+  if (gralloc_ && buffer_) {
+    gralloc_->Release(buffer_);
+    gralloc_ = nullptr;
+    buffer_ = nullptr;
+  }
+}
+
+std::optional<void*> GrallocBuffer::Lock() {
+  if (gralloc_ && buffer_) {
+    return gralloc_->Lock(buffer_);
+  }
+  return std::nullopt;
+}
+
+ std::optional<android_ycbcr> GrallocBuffer::LockYCbCr() {
+  if (gralloc_ && buffer_) {
+    return gralloc_->LockYCbCr(buffer_);
+  }
+  return std::nullopt;
+ }
+
+void GrallocBuffer::Unlock() {
+  if (gralloc_ && buffer_) {
+    gralloc_->Unlock(buffer_);
+  }
+}
+
+std::optional<uint32_t> GrallocBuffer::GetWidth() {
+  if (gralloc_ && buffer_) {
+    return gralloc_->GetWidth(buffer_);
+  }
+  return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetHeight() {
+  if (gralloc_ && buffer_) {
+    return gralloc_->GetHeight(buffer_);
+  }
+  return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetDrmFormat() {
+  if (gralloc_ && buffer_) {
+    return gralloc_->GetDrmFormat(buffer_);
+  }
+  return std::nullopt;
+}
+
+std::optional<std::vector<PlaneLayout>>
+GrallocBuffer::GetPlaneLayouts() {
+  if (gralloc_ && buffer_) {
+    return gralloc_->GetPlaneLayouts(buffer_);
+  }
+  return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetMonoPlanarStrideBytes() {
+  if (gralloc_ && buffer_) {
+    return gralloc_->GetMonoPlanarStrideBytes(buffer_);
+  }
+  return std::nullopt;
+}
+
+}  // namespace cvd
\ No newline at end of file
diff --git a/guest/hals/hwcomposer/common/gralloc_utils.h b/guest/hals/hwcomposer/common/gralloc_utils.h
new file mode 100644
index 0000000..370f2bb
--- /dev/null
+++ b/guest/hals/hwcomposer/common/gralloc_utils.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 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 <memory>
+#include <optional>
+#include <vector>
+
+#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+#include <utils/StrongPointer.h>
+
+namespace cvd {
+
+class Gralloc;
+
+// A gralloc 4.0 buffer that has been imported in the current process and
+// that will be released upon destruction. Users must ensure that the Gralloc
+// instance that this buffer is created with out lives this buffer.
+class GrallocBuffer {
+ public:
+  GrallocBuffer(Gralloc* gralloc, buffer_handle_t buffer);
+  virtual ~GrallocBuffer();
+
+  GrallocBuffer(const GrallocBuffer& rhs) = delete;
+  GrallocBuffer& operator=(const GrallocBuffer& rhs) = delete;
+
+  GrallocBuffer(GrallocBuffer&& rhs);
+  GrallocBuffer& operator=(GrallocBuffer&& rhs);
+
+  // Locks the buffer for reading and returns the mapped address if successful.
+  // Fails and returns nullopt if the underlying buffer is a YCbCr buffer.
+  std::optional<void*> Lock();
+
+  // Locks the buffer for reading and returns the mapped addresses and strides
+  // of each plane if successful. Fails and returns nullopt if the underlying
+  // buffer is not a YCbCr buffer.
+  std::optional<android_ycbcr> LockYCbCr();
+
+  // Unlocks the buffer from reading.
+  void Unlock();
+
+  std::optional<uint32_t> GetWidth();
+  std::optional<uint32_t> GetHeight();
+  std::optional<uint32_t> GetDrmFormat();
+
+  // Returns the stride of the buffer if it is a single plane buffer or fails
+  // and returns nullopt if the buffer is for a multi plane buffer.
+  std::optional<uint32_t> GetMonoPlanarStrideBytes();
+
+ private:
+  std::optional<
+    std::vector<aidl::android::hardware::graphics::common::PlaneLayout>>
+  GetPlaneLayouts();
+
+  void Release();
+
+  Gralloc* gralloc_ = nullptr;
+  buffer_handle_t buffer_ = nullptr;
+};
+
+class Gralloc {
+ public:
+  Gralloc();
+  virtual ~Gralloc() = default;
+
+  // Imports the given buffer handle into the current process and returns an
+  // imported buffer which can be used for reading. Users must ensure that the
+  // Gralloc instance outlives any GrallocBuffers.
+  std::optional<GrallocBuffer> Import(buffer_handle_t buffer);
+
+ private:
+  // The below functions are made avaialble only to GrallocBuffer so that
+  // users only call gralloc functions on *imported* buffers.
+  friend class GrallocBuffer;
+
+  // See GrallocBuffer::Release.
+  void Release(buffer_handle_t buffer);
+
+  // See GrallocBuffer::Lock.
+  std::optional<void*> Lock(buffer_handle_t buffer);
+
+  // See GrallocBuffer::LockYCbCr.
+  std::optional<android_ycbcr> LockYCbCr(buffer_handle_t buffer);
+
+  // See GrallocBuffer::Unlock.
+  void Unlock(buffer_handle_t buffer);
+
+  // See GrallocBuffer::GetWidth.
+  std::optional<uint32_t> GetWidth(buffer_handle_t buffer);
+
+  // See GrallocBuffer::GetHeight.
+  std::optional<uint32_t> GetHeight(buffer_handle_t buffer);
+
+  // See GrallocBuffer::GetDrmFormat.
+  std::optional<uint32_t> GetDrmFormat(buffer_handle_t buffer);
+
+  // See GrallocBuffer::GetPlaneLayouts.
+  std::optional<
+    std::vector<aidl::android::hardware::graphics::common::PlaneLayout>>
+  GetPlaneLayouts(buffer_handle_t buffer);
+
+  // Returns the stride of the buffer if it is a single plane buffer or fails
+  // and returns nullopt if the buffer is for a multi plane buffer.
+  std::optional<uint32_t> GetMonoPlanarStrideBytes(buffer_handle_t);
+
+  // See GrallocBuffer::GetMetadata.
+  android::hardware::graphics::mapper::V4_0::Error GetMetadata(
+    buffer_handle_t buffer,
+    android::hardware::graphics::mapper::V4_0::IMapper::MetadataType type,
+    android::hardware::hidl_vec<uint8_t>* metadata);
+
+  const gralloc_module_t* gralloc0_ = nullptr;
+
+  android::sp<android::hardware::graphics::mapper::V4_0::IMapper> gralloc4_;
+};
+
+}  // namespace cvd
\ No newline at end of file
diff --git a/guest/hals/hwcomposer/common/hwcomposer.cpp b/guest/hals/hwcomposer/common/hwcomposer.cpp
index c165f7e..4b51202 100644
--- a/guest/hals/hwcomposer/common/hwcomposer.cpp
+++ b/guest/hals/hwcomposer/common/hwcomposer.cpp
@@ -52,8 +52,6 @@
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
 #include "guest/hals/hwcomposer/common/base_composer.h"
 #include "guest/hals/hwcomposer/common/cpu_composer.h"
 #include "guest/hals/hwcomposer/common/geometry_utils.h"
@@ -181,7 +179,7 @@
 }
 
 // Ensures that the layer does not include any inconsistencies
-bool IsValidLayer(const hwc_layer_1_t& layer) {
+bool IsValidLayer(hwc_composer_device_1_t* dev, const hwc_layer_1_t& layer) {
   if (layer.flags & HWC_SKIP_LAYER) {
     // A layer we are asked to skip validate should not be marked as skip
     ALOGE("%s: Layer is marked as skip", __FUNCTION__);
@@ -197,13 +195,6 @@
         layer.displayFrame.top, layer.displayFrame.bottom);
     return false;
   }
-  // Validate the handle
-  if (private_handle_t::validate(layer.handle) != 0) {
-    ALOGE("%s: Layer contains an invalid gralloc handle.", __FUNCTION__);
-    return false;
-  }
-  const private_handle_t* p_handle =
-      reinterpret_cast<const private_handle_t*>(layer.handle);
   // Check sourceCrop
   if (layer.sourceCrop.left > layer.sourceCrop.right ||
       layer.sourceCrop.top > layer.sourceCrop.bottom) {
@@ -214,22 +205,13 @@
         layer.sourceCrop.top, layer.sourceCrop.bottom);
     return false;
   }
-  if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
-      layer.sourceCrop.right > p_handle->x_res ||
-      layer.sourceCrop.bottom > p_handle->y_res) {
-    ALOGE(
-        "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
-        "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
-        "%d]",
-        __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
-        layer.sourceCrop.top, layer.sourceCrop.bottom, p_handle->x_res,
-        p_handle->y_res);
-    return false;
-  }
-  return true;
+
+  auto* cvd_hwc_dev = reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev);
+  return cvd_hwc_dev->composer->IsValidLayer(layer);
 }
 
-bool IsValidComposition(int num_layers, hwc_layer_1_t* layers, bool on_set) {
+bool IsValidComposition(hwc_composer_device_1_t* dev, int num_layers,
+                        hwc_layer_1_t* layers, bool on_set) {
   if (num_layers == 0) {
     ALOGE("Composition requested with 0 layers");
     return false;
@@ -266,7 +248,7 @@
       case HWC_FRAMEBUFFER_TARGET:
         // In the call to prepare() the framebuffer target does not have a valid
         // buffer_handle, so we don't validate it yet.
-        if (on_set && check_fb_target && !IsValidLayer(layers[idx])) {
+        if (on_set && check_fb_target && !IsValidLayer(dev, layers[idx])) {
           ALOGE("%s: Invalid layer found", __FUNCTION__);
           LogLayers(num_layers, layers, idx);
           return false;
@@ -274,7 +256,7 @@
         break;
       case HWC_OVERLAY:
         if (!(layers[idx].flags & HWC_SKIP_LAYER) &&
-            !IsValidLayer(layers[idx])) {
+            !IsValidLayer(dev, layers[idx])) {
           ALOGE("%s: Invalid layer found", __FUNCTION__);
           LogLayers(num_layers, layers, idx);
           return false;
@@ -352,7 +334,7 @@
     hwc_display_contents_1_t* list = displays[disp];
 
     if (!list) return 0;
-    if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], false)) {
+    if (!IsValidComposition(dev, list->numHwLayers, &list->hwLayers[0], false)) {
       LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
       return -1;
     }
@@ -377,7 +359,7 @@
       ALOGW("Received request for empty composition, treating as valid noop");
       return 0;
     }
-    if (!IsValidComposition(contents->numHwLayers, layers, true)) {
+    if (!IsValidComposition(dev, contents->numHwLayers, layers, true)) {
       LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
       return -1;
     }
diff --git a/guest/hals/hwcomposer/common/hwcomposer.h b/guest/hals/hwcomposer/common/hwcomposer.h
index c7698b3..60a786c 100644
--- a/guest/hals/hwcomposer/common/hwcomposer.h
+++ b/guest/hals/hwcomposer/common/hwcomposer.h
@@ -1,4 +1,3 @@
-#pragma once
 /*
  * Copyright (C) 2019 The Android Open Source Project
  *
@@ -14,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <memory>
 
diff --git a/guest/hals/hwcomposer/cutf_cvm/Android.bp b/guest/hals/hwcomposer/cutf_cvm/Android.bp
index 8b9115a..b6ad6f7 100644
--- a/guest/hals/hwcomposer/cutf_cvm/Android.bp
+++ b/guest/hals/hwcomposer/cutf_cvm/Android.bp
@@ -19,28 +19,33 @@
     defaults: ["cuttlefish_guest_only"],
     vendor: true,
     srcs: [
-        "vsocket_screen_view.cpp",
         "hwcomposer.cpp",
+        "vsocket_screen_view.cpp",
     ],
     include_dirs: [
         "device/google/cuttlefish",
     ],
     export_include_dirs: ["."],
     static_libs: [
-        "libyuv_static", 
-        "hwcomposer_common"
+        "hwcomposer_common",
+        "libyuv_static",
     ],
     shared_libs: [
-        "liblog",
-        "libhardware",
+        "android.hardware.graphics.mapper@4.0",
         "libbase",
         "libcutils",
-        "libutils",
-        "libsync",
-        "libjpeg",
+        "libcuttlefish_device_config",
         "libcuttlefish_utils",
         "libcuttlefish_fs",
-        "libcuttlefish_device_config",
+        "libdrm",
+        "libgralloctypes",
+        "libhardware",
+        "libhidlbase",
+        "libjpeg",
+        "liblog",
+        "libminigbm",
+        "libsync",
+        "libutils",
     ],
 }
 
@@ -77,17 +82,20 @@
     export_include_dirs: ["."],
 
     static_libs: [
+        "hwcomposer_common",
         "libyuv_static",
-        "hwcomposer_common"
     ],
 
     shared_libs: [
-        "libutils",
+        "android.hardware.graphics.mapper@4.0",
         "libcutils",
-        "liblog",
-        "libhardware",
+        "libcuttlefish_device_config",
         "libcuttlefish_utils",
         "libcuttlefish_fs",
-        "libcuttlefish_device_config",
+        "libgralloctypes",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
     ],
 }
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index 827ac4f..b67c360 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -275,8 +275,9 @@
         tmp_config_obj.AssemblyPath(kKernelDefaultPath.c_str()));
     tmp_config_obj.set_use_unpacked_kernel(true);
   }
+
   tmp_config_obj.set_decompress_kernel(FLAGS_decompress_kernel);
-  if (FLAGS_decompress_kernel) {
+  if (tmp_config_obj.decompress_kernel()) {
     tmp_config_obj.set_decompressed_kernel_image_path(
         tmp_config_obj.AssemblyPath("vmlinux"));
   }
@@ -433,6 +434,16 @@
 void SetDefaultFlagsForCrosvm() {
   SetCommandLineOptionWithMode("logcat_mode", cvd::kLogcatVsockMode,
                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
+
+  // Crosvm requires a specific setting for kernel decompression; it must be
+  // on for aarch64 and off for x86, no other mode is supported.
+  bool decompress_kernel = false;
+  if (cvd::HostArch() == "aarch64") {
+    decompress_kernel = true;
+  }
+  SetCommandLineOptionWithMode("decompress_kernel",
+                               (decompress_kernel ? "true" : "false"),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
 }
 
 bool ParseCommandLineFlags(int* argc, char*** argv) {
diff --git a/host/commands/tapsetiff/Android.bp b/host/commands/tapsetiff/Android.bp
new file mode 100644
index 0000000..c860241
--- /dev/null
+++ b/host/commands/tapsetiff/Android.bp
@@ -0,0 +1,19 @@
+//
+// Copyright (C) 2020 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.
+
+sh_binary_host {
+    name: "tapsetiff",
+    src: "tapsetiff.py",
+}
diff --git a/host/commands/tapsetiff/tapsetiff.py b/host/commands/tapsetiff/tapsetiff.py
new file mode 100755
index 0000000..3e7c9e4
--- /dev/null
+++ b/host/commands/tapsetiff/tapsetiff.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+
+# Copyright (C) 2020 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.
+
+import fcntl
+import struct
+import sys
+
+TUNSETIFF = 0x400454ca
+IFF_TAP = 0x0002
+IFF_NO_PI = 0x1000
+IFF_VNET_HDR = 0x4000
+
+tun_fd = int(sys.argv[1])
+tap_name = sys.argv[2]
+
+ifr = struct.pack('16sH', tap_name, IFF_TAP | IFF_NO_PI | IFF_VNET_HDR)
+fcntl.ioctl(tun_fd, TUNSETIFF, ifr)
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index 4676915..86bc75b 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -25,6 +25,7 @@
 #include <android-base/strings.h>
 #include <glog/logging.h>
 
+#include "common/libs/utils/environment.h"
 #include "common/libs/utils/network.h"
 #include "common/libs/utils/subprocess.h"
 #include "host/libs/config/cuttlefish_config.h"
@@ -108,7 +109,11 @@
 std::vector<std::string> CrosvmManager::ConfigureBootDevices() {
   // PCI domain 0, bus 0, device 1, function 0
   // TODO There is no way to control this assignment with crosvm (yet)
-  return { "androidboot.boot_devices=pci0000:00/0000:00:01.0" };
+  if (cvd::HostArch() == "x86_64") {
+    return { "androidboot.boot_devices=pci0000:00/0000:00:01.0" };
+  } else {
+    return { "androidboot.boot_devices=10000.pci" };
+  }
 }
 
 CrosvmManager::CrosvmManager(const vsoc::CuttlefishConfig* config)
@@ -140,7 +145,6 @@
   if (!config_->final_ramdisk_path().empty()) {
     crosvm_cmd.AddParameter("--initrd=", config_->final_ramdisk_path());
   }
-  crosvm_cmd.AddParameter("--null-audio");
   crosvm_cmd.AddParameter("--mem=", config_->memory_mb());
   crosvm_cmd.AddParameter("--cpus=", config_->cpus());
   crosvm_cmd.AddParameter("--params=", kernel_cmdline_);
diff --git a/host_package.mk b/host_package.mk
index 24a5210..0644114 100644
--- a/host_package.mk
+++ b/host_package.mk
@@ -40,6 +40,11 @@
     x86_64-linux-gnu/libgbm.so.1 \
     x86_64-linux-gnu/libminijail.so \
     x86_64-linux-gnu/libvirglrenderer.so.1 \
+    x86_64-linux-gnu/libc++.so.1 \
+    x86_64-linux-gnu/libandroid-emu-shared.so \
+    x86_64-linux-gnu/libemugl_common.so \
+    x86_64-linux-gnu/libOpenglRender.so \
+    x86_64-linux-gnu/libgfxstream_backend.so \
     logcat_receiver \
     config_server \
     tombstone_receiver \
@@ -51,6 +56,7 @@
     fsck.f2fs \
     resize.f2fs \
     make_f2fs \
+    tapsetiff
 
 cvd_host_tests := \
     monotonic_time_test \
diff --git a/shared/auto/OWNERS b/shared/auto/OWNERS
index 53bbd52..1b990ef 100644
--- a/shared/auto/OWNERS
+++ b/shared/auto/OWNERS
@@ -1,3 +1,5 @@
 # Android Auto leads
 ankitarora@google.com
 egranata@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/shared/device.mk b/shared/device.mk
index 3a9797c..02e002d 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -28,6 +28,8 @@
 PRODUCT_USE_DYNAMIC_PARTITIONS := true
 DISABLE_RILD_OEM_HOOK := true
 
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for vulkan
+
 TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE ?= f2fs
 
 TARGET_VULKAN_SUPPORT ?= true
diff --git a/shared/sepolicy/vendor/genfs_contexts b/shared/sepolicy/vendor/genfs_contexts
index 5ac5257..82dea3d 100644
--- a/shared/sepolicy/vendor/genfs_contexts
+++ b/shared/sepolicy/vendor/genfs_contexts
@@ -6,7 +6,15 @@
 genfscon sysfs /devices/pci0000:00/0000:00:0a.0/subsystem_vendor u:object_r:sysfs_gpu:s0
 genfscon sysfs /devices/pci0000:00/0000:00:0a.0/uevent u:object_r:sysfs_gpu:s0
 genfscon sysfs /devices/pci0000:00/0000:00:0a.0/vendor u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/pnp0/00:00/rtc  u:object_r:sysfs_rtc:s0 # also used by qemu
+## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
+## x86 rtc_cmos on crosvm does not currently expose rtcN/hctosys
+## find /sys/devices/platform/* -type d -name 'wakeup[0-9]'
+genfscon sysfs /devices/platform/rtc_cmos/wakeup/wakeup0 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup1 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/wakeup2 u:object_r:sysfs_wakeup:s0 # <= 5.5
+genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/alarmtimer.0.auto/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0 # >5.5
+genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup3 u:object_r:sysfs_wakeup:s0
+
 # crosvm (arm64)
 genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:07.0/virtio6/net u:object_r:sysfs_net:s0 # buried_eth0 & wlan0
 genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:08.0/virtio7/net u:object_r:sysfs_net:s0 # rmnet0
@@ -15,21 +23,32 @@
 genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0a.0/subsystem_vendor u:object_r:sysfs_gpu:s0
 genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0a.0/uevent u:object_r:sysfs_gpu:s0
 genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0a.0/vendor u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/platform/2000.rtc/rtc  u:object_r:sysfs_rtc:s0
+## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
+genfscon sysfs /devices/platform/2000.rtc/rtc u:object_r:sysfs_rtc:s0
+## find /sys/devices/platform/* -type d -name 'wakeup[0-9]'
+## arm64 2000.rtc on crosvm does not currently expose a wakeup node
+genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc2/wakeup1 u:object_r:sysfs_wakeup:s0 # <= 5.5
+genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc2/alarmtimer.0.auto/wakeup/wakeup1 u:object_r:sysfs_wakeup:s0 # >5.5
+
 # qemu (x86)
 genfscon sysfs /devices/pci0000:00/0000:00:04.0/virtio2/net u:object_r:sysfs_net:s0 # buried_eth0 & wlan0
 genfscon sysfs /devices/pci0000:00/0000:00:05.0/virtio3/net u:object_r:sysfs_net:s0 # rmnet0
+# FIXME: Add sysfs_gpu labels for qemu
+## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
+genfscon sysfs /devices/pnp0/00:00/rtc u:object_r:sysfs_rtc:s0
+## find /sys/devices/platform/* -type d -name 'wakeup[0-9][0-9]'
+genfscon sysfs /devices/pnp0/00:00/wakeup/wakeup13 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/pnp0/00:00/rtc/rtc0/wakeup14 u:object_r:sysfs_wakeup:s0 # <= 5.5
+genfscon sysfs /devices/pnp0/00:00/rtc/rtc0/alarmtimer.0.auto/wakeup/wakeup14 u:object_r:sysfs_wakeup:s0 # >5.5
+genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup15 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup16 u:object_r:sysfs_wakeup:s0
+
+# common to qemu (x86) and crosvm (arm64)
+genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup0 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0
 
 # common on all platforms / vm managers
+genfscon sysfs /devices/platform/rtc-test.0/rtc u:object_r:sysfs_rtc:s0
+genfscon sysfs /devices/platform/rtc-test.1/rtc u:object_r:sysfs_rtc:s0
+genfscon sysfs /devices/platform/rtc-test.2/rtc u:object_r:sysfs_rtc:s0
 genfscon sysfs /bus/iio/devices u:object_r:sysfs_iio_devices:s0
-genfscon sysfs /devices/platform/rtc-test.0/rtc/rtc0/hctosys u:object_r:sysfs_rtc:s0
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/hctosys u:object_r:sysfs_rtc:s0
-genfscon sysfs /devices/platform/rtc-test.2/rtc/rtc2/hctosys u:object_r:sysfs_rtc:s0
-# TODO(b/148802006): Work around core policy sysfs_wakeup label not working
-# All kernels
-genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup0  u:object_r:sysfs_wakeup:s0
-genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0
-# Kernels <=5.5
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/wakeup1  u:object_r:sysfs_wakeup:s0
-# Kernels >5.5
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/alarmtimer.0.auto/wakeup/wakeup1  u:object_r:sysfs_wakeup:s0
diff --git a/vsoc_arm64/auto/OWNERS b/vsoc_arm64/auto/OWNERS
index 53bbd52..1b990ef 100644
--- a/vsoc_arm64/auto/OWNERS
+++ b/vsoc_arm64/auto/OWNERS
@@ -1,3 +1,5 @@
 # Android Auto leads
 ankitarora@google.com
 egranata@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/vsoc_x86/auto/OWNERS b/vsoc_x86/auto/OWNERS
index 53bbd52..1b990ef 100644
--- a/vsoc_x86/auto/OWNERS
+++ b/vsoc_x86/auto/OWNERS
@@ -1,3 +1,5 @@
 # Android Auto leads
 ankitarora@google.com
 egranata@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml b/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
index 99af23c..9893ad9 100644
--- a/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
+++ b/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
@@ -61,12 +61,16 @@
         <install-in user-type="FULL" />
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
-
     <!-- Required in SettingHelperImpl to start settings with shell command.-->
     <install-in-user-type package="com.android.car.settings">
         <install-in user-type="FULL" />
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
+    <!-- Required for Wifi -->
+    <install-in-user-type package="com.android.networkstack">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
 
 <!--
   Apps that do need to run on SYSTEM and evaluated by package owner.
@@ -224,9 +228,6 @@
     <install-in-user-type package="com.android.musicfx">
         <install-in user-type="FULL" />
     </install-in-user-type>
-    <install-in-user-type package="com.android.networkstack">
-        <install-in user-type="FULL" />
-    </install-in-user-type>
     <install-in-user-type package="com.google.android.marvin.talkback">
         <install-in user-type="FULL" />
     </install-in-user-type>