Add IAllocator@3.0 and IMapper@3.0 implementations

This change adds HIDL IAllocator and IMapper to replace
gralloc-based (deprecated) ones.

Bug: 145244672
Bug: 144386336
Test: boot, check if youtube and the virtualscene camera works
Test: CtsNativeHardwareTestCases
Test: CtsDeqpTestCases -t dEQP-VK.api.external*
Change-Id: I380a5a6a6dd88ff9c968ba5f738b3cb6ff93e9e1
Signed-off-by: Roman Kiryanov <rkir@google.com>
diff --git a/Android.mk b/Android.mk
index 2c0a5c2..ce83f67 100644
--- a/Android.mk
+++ b/Android.mk
@@ -149,6 +149,7 @@
 include $(GOLDFISH_OPENGL_PATH)/system/GLESv2/Android.mk
 
 include $(GOLDFISH_OPENGL_PATH)/system/gralloc/Android.mk
+include $(GOLDFISH_OPENGL_PATH)/system/hals/Android.mk
 include $(GOLDFISH_OPENGL_PATH)/system/cbmanager/Android.mk
 
 include $(GOLDFISH_OPENGL_PATH)/system/egl/Android.mk
diff --git a/system/hals/Android.mk b/system/hals/Android.mk
new file mode 100644
index 0000000..912a362
--- /dev/null
+++ b/system/hals/Android.mk
@@ -0,0 +1,74 @@
+#
+# Copyright 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.hardware.graphics.allocator@3.0-service
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := allocator3.cpp
+LOCAL_INIT_RC := android.hardware.graphics.allocator@3.0-service.rc
+
+LOCAL_SHARED_LIBRARIES += \
+    android.hardware.graphics.allocator@3.0 \
+    android.hardware.graphics.mapper@3.0 \
+    libOpenglSystemCommon \
+    libOpenglCodecCommon$(GOLDFISH_OPENGL_LIB_SUFFIX) \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libutils
+
+LOCAL_C_INCLUDES += \
+    device/generic/goldfish-opengl/system/include \
+    device/generic/goldfish-opengl/system/OpenglSystemCommon \
+    device/generic/goldfish-opengl/shared/OpenglCodecCommon \
+    device/generic/goldfish-opengl/host/include/libOpenglRender \
+    device/generic/goldfish-opengl/system/renderControl_enc \
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.hardware.graphics.mapper@3.0-impl
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := mapper3.cpp
+
+#     android.hardware.graphics.allocator@3.0 \
+
+LOCAL_SHARED_LIBRARIES += \
+    android.hardware.graphics.mapper@3.0 \
+    libOpenglSystemCommon \
+    libOpenglCodecCommon$(GOLDFISH_OPENGL_LIB_SUFFIX) \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libutils \
+    libsync
+
+LOCAL_C_INCLUDES += \
+    device/generic/goldfish-opengl/system/include \
+    device/generic/goldfish-opengl/system/OpenglSystemCommon \
+    device/generic/goldfish-opengl/shared/OpenglCodecCommon \
+    device/generic/goldfish-opengl/host/include/libOpenglRender \
+    device/generic/goldfish-opengl/system/renderControl_enc \
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/system/hals/allocator3.cpp b/system/hals/allocator3.cpp
new file mode 100644
index 0000000..e5e182d
--- /dev/null
+++ b/system/hals/allocator3.cpp
@@ -0,0 +1,425 @@
+/*
+* 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 <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <hidl/LegacySupport.h>
+
+#include "glUtils.h"
+#include "cb_handle_30.h"
+#include "host_connection_session.h"
+#include "types.h"
+#include "debug.h"
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::graphics::common::V1_2::PixelFormat;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+
+namespace AllocatorV3 = ::android::hardware::graphics::allocator::V3_0;
+namespace MapperV3 = ::android::hardware::graphics::mapper::V3_0;
+
+using IAllocator3 = AllocatorV3::IAllocator;
+using IMapper3 = MapperV3::IMapper;
+using Error3 = MapperV3::Error;
+using BufferDescriptorInfo = IMapper3::BufferDescriptorInfo;
+
+class GoldfishAllocator : public IAllocator3 {
+public:
+    GoldfishAllocator() : m_hostConn(HostConnection::createUnique()) {}
+
+    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+        hidl_cb("GoldfishAllocator::dumpDebugInfo is not implemented");
+        return {};
+    }
+
+    Return<void> allocate(const hidl_vec<uint32_t>& rawDescriptor,
+                          uint32_t count,
+                          allocate_cb hidl_cb) {
+        uint32_t stride = 0;
+        std::vector<cb_handle_30_t*> cbs;
+        cbs.reserve(count);
+
+        const Error3 e = allocateImpl(rawDescriptor, count, &stride, &cbs);
+        if (e == Error3::NONE) {
+            hidl_vec<hidl_handle> handles(cbs.cbegin(), cbs.cend());
+            hidl_cb(Error3::NONE, stride, handles);
+        } else {
+            hidl_cb(e, 0, {});
+        }
+
+        for (cb_handle_30_t* cb : cbs) {
+            freeCb(std::unique_ptr<cb_handle_30_t>(cb));
+        }
+
+        return {};
+    }
+
+private:
+    // this function should be in sync with GoldfishMapper::isSupportedImpl
+    Error3 allocateImpl(const hidl_vec<uint32_t>& rawDescriptor,
+                        uint32_t count,
+                        uint32_t* pStride,
+                        std::vector<cb_handle_30_t*>* cbs) {
+        BufferDescriptorInfo descriptor;
+        if (!decodeBufferDescriptorInfo(rawDescriptor, &descriptor)) {
+            RETURN_ERROR(Error3::BAD_DESCRIPTOR);
+        }
+
+        if (!descriptor.width) { RETURN_ERROR(Error3::UNSUPPORTED); }
+        if (!descriptor.height) { RETURN_ERROR(Error3::UNSUPPORTED); }
+        if (descriptor.layerCount != 1) { RETURN_ERROR(Error3::UNSUPPORTED); }
+
+        const uint32_t usage = descriptor.usage;
+        const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
+        const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
+        const bool usageHwCamWrite = usage & BufferUsage::CAMERA_OUTPUT;
+        const bool usageHwCamRead = usage & BufferUsage::CAMERA_INPUT;
+
+        int bpp = 1;
+        int glFormat = 0;
+        int glType = 0;
+        int align = 1;
+        bool yuv_format = false;
+        EmulatorFrameworkFormat emulatorFrameworkFormat =
+            EmulatorFrameworkFormat::GL_COMPATIBLE;
+
+        PixelFormat format;
+        Error3 e = getBufferFormat(descriptor.format, usage, &format);
+        if (e != Error3::NONE) {
+            ALOGE("%s:%d Unsupported format: frameworkFormat=%d, usage=%x",
+                  __func__, __LINE__, descriptor.format, usage);
+            return e;
+        }
+
+        switch (format) {
+        case PixelFormat::RGBA_8888:
+        case PixelFormat::RGBX_8888:
+        case PixelFormat::BGRA_8888:
+            bpp = 4;
+            glFormat = GL_RGBA;
+            glType = GL_UNSIGNED_BYTE;
+            break;
+
+        case PixelFormat::RGB_888:
+            if (usage & (BufferUsage::GPU_TEXTURE |
+                         BufferUsage::GPU_RENDER_TARGET |
+                         BufferUsage::COMPOSER_OVERLAY |
+                         BufferUsage::COMPOSER_CLIENT_TARGET)) {
+                RETURN_ERROR(Error3::UNSUPPORTED);
+            } else {
+                bpp = 3;
+                glFormat = GL_RGB;
+                glType = GL_UNSIGNED_BYTE;
+            }
+            break;
+
+        case PixelFormat::RGB_565:
+            bpp = 2;
+            glFormat = GL_RGB565;
+            glType = GL_UNSIGNED_SHORT_5_6_5;
+            break;
+
+        case PixelFormat::RGBA_FP16:
+            bpp = 8;
+            glFormat = GL_RGBA16F;
+            glType = GL_HALF_FLOAT;
+            break;
+
+        case PixelFormat::RGBA_1010102:
+            bpp = 4;
+            glFormat = GL_RGB10_A2;
+            glType = GL_UNSIGNED_INT_2_10_10_10_REV;
+            break;
+
+        case PixelFormat::RAW16:
+        case PixelFormat::Y16:
+            bpp = 2;
+            align = 16 * bpp;
+            if (!((usageSwRead || usageHwCamRead) && (usageSwWrite || usageHwCamWrite))) {
+                // Raw sensor data or Y16 only goes between camera and CPU
+                RETURN_ERROR(Error3::UNSUPPORTED);
+            }
+            // Not expecting to actually create any GL surfaces for this
+            glFormat = GL_LUMINANCE;
+            glType = GL_UNSIGNED_SHORT;
+            break;
+
+        case PixelFormat::BLOB:
+            if (!usageSwRead) {
+                // Blob data cannot be used by HW other than camera emulator
+                // But there is a CTS test trying to have access to it
+                // BUG: https://buganizer.corp.google.com/issues/37719518
+                RETURN_ERROR(Error3::UNSUPPORTED);
+            }
+            // Not expecting to actually create any GL surfaces for this
+            glFormat = GL_LUMINANCE;
+            glType = GL_UNSIGNED_BYTE;
+            break;
+
+        case PixelFormat::YCRCB_420_SP:
+            yuv_format = true;
+            // Not expecting to actually create any GL surfaces for this
+            break;
+
+        case PixelFormat::YV12:
+            align = 16;
+            yuv_format = true;
+            // We are going to use RGB8888 on the host for Vulkan
+            glFormat = GL_RGBA;
+            glType = GL_UNSIGNED_BYTE;
+            emulatorFrameworkFormat = EmulatorFrameworkFormat::YV12;
+            break;
+
+        case PixelFormat::YCBCR_420_888:
+            yuv_format = true;
+            // We are going to use RGB888 on the host
+            glFormat = GL_RGB;
+            glType = GL_UNSIGNED_BYTE;
+            emulatorFrameworkFormat = EmulatorFrameworkFormat::YUV_420_888;
+            break;
+
+        default:
+            ALOGE("%s:%d Unsupported format: format=%d, frameworkFormat=%d, usage=%x",
+                  __func__, __LINE__, format, descriptor.format, usage);
+            RETURN_ERROR(Error3::UNSUPPORTED);
+        }
+
+        const size_t align1 = align - 1;
+        const uint32_t width = descriptor.width;
+        const uint32_t height = descriptor.height;
+        uint32_t stride;
+        size_t bufferSize;
+
+        if (yuv_format) {
+            const size_t yStride = (width * bpp + align1) & ~align1;
+            const size_t uvStride = (yStride / 2 + align1) & ~align1;
+            const size_t uvHeight = height / 2;
+            bufferSize = yStride * height + 2 * (uvHeight * uvStride);
+            stride = yStride / bpp;
+        } else {
+            const size_t bpr = (width * bpp + align1) & ~align1;
+            bufferSize = bpr * height;
+            stride = bpr / bpp;
+        }
+
+        *pStride = stride;
+
+        return allocateImpl2(usage,
+                             width, height,
+                             format, emulatorFrameworkFormat,
+                             glFormat, glType,
+                             bufferSize,
+                             bpp, stride,
+                             count, cbs);
+    }
+
+    Error3 allocateImpl2(const uint32_t usage,
+                         const uint32_t width, const uint32_t height,
+                         const PixelFormat format,
+                         const EmulatorFrameworkFormat emulatorFrameworkFormat,
+                         const int glFormat, const int glType,
+                         const size_t bufferSize,
+                         const uint32_t bytesPerPixel,
+                         const uint32_t stride,
+                         const uint32_t count,
+                         std::vector<cb_handle_30_t*>* cbs) {
+        for (uint32_t i = 0; i < count; ++i) {
+            cb_handle_30_t* cb;
+            Error3 e = allocateCb(usage,
+                                  width, height,
+                                  format, emulatorFrameworkFormat,
+                                  glFormat, glType,
+                                  bufferSize,
+                                  bytesPerPixel, stride,
+                                  &cb);
+            if (e == Error3::NONE) {
+                cbs->push_back(cb);
+            } else {
+                return e;
+            }
+        }
+
+        RETURN(Error3::NONE);
+    }
+
+    // see GoldfishMapper::encodeBufferDescriptorInfo
+    static bool decodeBufferDescriptorInfo(const hidl_vec<uint32_t>& raw,
+                                           BufferDescriptorInfo* d) {
+        if (raw.size() == 5) {
+            d->width = raw[0];
+            d->height = raw[1];
+            d->layerCount = raw[2];
+            d->format = static_cast<PixelFormat>(raw[3]);
+            d->usage = raw[4];
+
+            RETURN(true);
+        } else {
+            RETURN_ERROR(false);
+        }
+    }
+
+    static Error3 getBufferFormat(const PixelFormat frameworkFormat,
+                                  const uint32_t usage,
+                                  PixelFormat* format) {
+        if (frameworkFormat == PixelFormat::IMPLEMENTATION_DEFINED) {
+            if (usage & BufferUsage::CAMERA_OUTPUT) {
+                if (usage & BufferUsage::GPU_TEXTURE) {
+                    // Camera-to-display is RGBA
+                    *format = PixelFormat::RGBA_8888;
+                    RETURN(Error3::NONE);
+                } else if (usage & BufferUsage::VIDEO_ENCODER) {
+                    // Camera-to-encoder is NV21
+                    *format = PixelFormat::YCRCB_420_SP;
+                    RETURN(Error3::NONE);
+                }
+            }
+            RETURN_ERROR(Error3::UNSUPPORTED);
+        } else  {
+            *format = frameworkFormat;
+            RETURN(Error3::NONE);
+        }
+    }
+
+    static bool needHostCb(const uint32_t usage, const PixelFormat format) {
+        return ((usage & BufferUsage::GPU_DATA_BUFFER)
+                   || (format != PixelFormat::BLOB &&
+                       format != PixelFormat::RAW16 &&
+                       format != PixelFormat::Y16))
+               && (usage & (BufferUsage::GPU_TEXTURE
+                            | BufferUsage::GPU_RENDER_TARGET
+                            | BufferUsage::COMPOSER_OVERLAY
+                            | BufferUsage::VIDEO_ENCODER
+                            | BufferUsage::COMPOSER_CLIENT_TARGET
+                            | BufferUsage::CPU_READ_MASK));
+    }
+
+    Error3 allocateCb(const uint32_t usage,
+                      const uint32_t width, const uint32_t height,
+                      const PixelFormat format,
+                      const EmulatorFrameworkFormat emulatorFrameworkFormat,
+                      const int glFormat, const int glType,
+                      const size_t bufferSize,
+                      const int32_t bytesPerPixel,
+                      const int32_t stride,
+                      cb_handle_30_t** cb) {
+        GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator;
+        if (!host_memory_allocator.is_opened()) {
+            RETURN_ERROR(Error3::NO_RESOURCES);
+        }
+
+        GoldfishAddressSpaceBlock bufferBits;
+        if (host_memory_allocator.hostMalloc(&bufferBits, bufferSize)) {
+            RETURN_ERROR(Error3::NO_RESOURCES);
+        }
+
+        uint32_t hostHandle = 0;
+        QEMU_PIPE_HANDLE hostHandleRefCountFd = QEMU_PIPE_INVALID_HANDLE;
+        if (needHostCb(usage, format)) {
+            hostHandleRefCountFd = qemu_pipe_open("refcount");
+            if (!qemu_pipe_valid(hostHandleRefCountFd)) {
+                RETURN_ERROR(Error3::NO_RESOURCES);
+            }
+
+            const GLenum allocFormat =
+                (PixelFormat::RGBX_8888 == format) ? GL_RGB : glFormat;
+
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            CRASH_IF(!rcEnc, "conn.getRcEncoder() failed");
+
+            hostHandle = rcEnc->rcCreateColorBufferDMA(
+                rcEnc,
+                width, height,
+                allocFormat, static_cast<int>(emulatorFrameworkFormat));
+
+            if (!hostHandle) {
+                qemu_pipe_close(hostHandleRefCountFd);
+                RETURN_ERROR(Error3::NO_RESOURCES);
+            }
+
+            if (qemu_pipe_write(hostHandleRefCountFd,
+                                &hostHandle,
+                                sizeof(hostHandle)) != sizeof(hostHandle)) {
+                rcEnc->rcCloseColorBuffer(rcEnc, hostHandle);
+                qemu_pipe_close(hostHandleRefCountFd);
+                RETURN_ERROR(Error3::NO_RESOURCES);
+            }
+        }
+
+        std::unique_ptr<cb_handle_30_t> handle =
+            std::make_unique<cb_handle_30_t>(
+                host_memory_allocator.release(),
+                hostHandleRefCountFd,
+                hostHandle,
+                usage,
+                width,
+                height,
+                static_cast<int>(format),
+                glFormat,
+                glType,
+                bufferSize,
+                bufferBits.guestPtr(),
+                bufferBits.size(),
+                bufferBits.offset(),
+                bytesPerPixel,
+                stride);
+
+        bufferBits.release();
+        *cb = handle.release();
+        RETURN(Error3::NONE);
+    }
+
+    void freeCb(std::unique_ptr<cb_handle_30_t> cb) {
+        // no need to undo .hostMalloc: the kernel will take care of it once the
+        // last bufferFd (duped) is closed.
+
+        if (qemu_pipe_valid(cb->hostHandleRefCountFd)) {
+            qemu_pipe_close(cb->hostHandleRefCountFd);
+        }
+        GoldfishAddressSpaceBlock::memoryUnmap(cb->getBufferPtr(), cb->mmapedSize);
+        GoldfishAddressSpaceHostMemoryAllocator::closeHandle(cb->bufferFd);
+    }
+
+    HostConnectionSession getHostConnectionSession() const {
+        return HostConnectionSession(m_hostConn);
+    }
+
+    //std::unique_ptr<HostConnection> m_hostConn;  // b/142677230
+    HostConnection* m_hostConn;
+};
+
+int main(int, char**) {
+    using ::android::sp;
+
+    ::android::hardware::configureRpcThreadpool(4, true /* callerWillJoin */);
+
+    sp<IAllocator3> allocator(new GoldfishAllocator());
+    if (allocator->registerAsService() != ::android::NO_ERROR) {
+        ALOGE("failed to register graphics IAllocator@3.0 service");
+        return -EINVAL;
+    }
+
+    ALOGI("graphics IAllocator@3.0 service is initialized");
+    ::android::hardware::joinRpcThreadpool();
+
+    ALOGI("graphics IAllocator@3.0 service is terminating");
+    return 0;
+}
diff --git a/system/hals/android.hardware.graphics.allocator@3.0-service.rc b/system/hals/android.hardware.graphics.allocator@3.0-service.rc
new file mode 100644
index 0000000..8b9e13a
--- /dev/null
+++ b/system/hals/android.hardware.graphics.allocator@3.0-service.rc
@@ -0,0 +1,8 @@
+service vendor.gralloc-3-0 /vendor/bin/hw/android.hardware.graphics.allocator@3.0-service
+    interface android.hardware.graphics.allocator@3.0::IAllocator default
+    class hal animation
+    interface android.hardware.graphics.allocator@3.0::IAllocator default
+    user system
+    group graphics drmrpc
+    capabilities SYS_NICE
+    onrestart restart surfaceflinger
diff --git a/system/hals/cb_handle_30.h b/system/hals/cb_handle_30.h
new file mode 100644
index 0000000..11ce322
--- /dev/null
+++ b/system/hals/cb_handle_30.h
@@ -0,0 +1,81 @@
+/*
+* Copyright 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef SYSTEM_HALS_CB_HANDLE_30_H
+#define SYSTEM_HALS_CB_HANDLE_30_H
+
+#include "gralloc_cb.h"
+#include "goldfish_address_space.h"
+
+const uint32_t CB_HANDLE_MAGIC_30 = CB_HANDLE_MAGIC_BASE | 0x2;
+
+struct cb_handle_30_t : public cb_handle_t {
+    cb_handle_30_t(address_space_handle_t p_bufferFd,
+                   QEMU_PIPE_HANDLE p_hostHandleRefCountFd,
+                   uint32_t p_hostHandle,
+                   int32_t p_usage,
+                   int32_t p_width,
+                   int32_t p_height,
+                   int32_t p_format,
+                   int32_t p_glFormat,
+                   int32_t p_glType,
+                   uint32_t p_bufSize,
+                   void* p_bufPtr,
+                   uint32_t p_mmapedSize,
+                   uint64_t p_mmapedOffset,
+                   uint32_t p_bytesPerPixel,
+                   uint32_t p_stride)
+            : cb_handle_t(p_bufferFd,
+                          p_hostHandleRefCountFd,
+                          CB_HANDLE_MAGIC_30,
+                          p_hostHandle,
+                          p_usage,
+                          p_width,
+                          p_height,
+                          p_format,
+                          p_glFormat,
+                          p_glType,
+                          p_bufSize,
+                          p_bufPtr,
+                          p_mmapedOffset),
+              mmapedSize(p_mmapedSize),
+              bytesPerPixel(p_bytesPerPixel),
+              stride(p_stride) {
+        numInts = CB_HANDLE_NUM_INTS(numFds);
+    }
+
+    bool isValid() const { return (version == sizeof(native_handle_t)) && (magic == CB_HANDLE_MAGIC_30); }
+
+    static cb_handle_30_t* from(void* p) {
+        if (!p) { return nullptr; }
+        cb_handle_30_t* cb = static_cast<cb_handle_30_t*>(p);
+        return cb->isValid() ? cb : nullptr;
+    }
+
+    static const cb_handle_30_t* from(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    static cb_handle_30_t* from_unconst(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    uint32_t mmapedSize;            // real allocation side
+    uint32_t bytesPerPixel;
+    uint32_t stride;
+};
+
+#endif // SYSTEM_HALS_CB_HANDLE_30_H
diff --git a/system/hals/debug.h b/system/hals/debug.h
new file mode 100644
index 0000000..f8e41b4
--- /dev/null
+++ b/system/hals/debug.h
@@ -0,0 +1,44 @@
+/*
+* 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.
+*/
+
+#ifndef GOLDFISH_OPENGL_SYSTEM_HALS_DEBUG_H_INCLUDED
+#define GOLDFISH_OPENGL_SYSTEM_HALS_DEBUG_H_INCLUDED
+
+#include <log/log.h>
+
+#define RETURN(X) return (X)
+
+#define RETURN_ERROR(X) \
+    do { \
+        ALOGE("%s:%d failed with '%s'", __func__, __LINE__, #X); \
+        return (X); \
+    } while (false)
+
+#define CRASH(MSG) \
+    do { \
+        ALOGE("%s:%d crashed with '%s'", __func__, __LINE__, MSG); \
+        ::abort(); \
+    } while (false)
+
+#define CRASH_IF(COND, MSG) \
+    do { \
+        if ((COND)) { \
+            ALOGE("%s:%d crashed on '%s' with '%s'", __func__, __LINE__, #COND, MSG); \
+            ::abort(); \
+        } \
+    } while (false)
+
+#endif  // GOLDFISH_OPENGL_SYSTEM_HALS_DEBUG_H_INCLUDED
diff --git a/system/hals/host_connection_session.h b/system/hals/host_connection_session.h
new file mode 100644
index 0000000..12d3b76
--- /dev/null
+++ b/system/hals/host_connection_session.h
@@ -0,0 +1,56 @@
+/*
+* 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.
+*/
+
+#ifndef GOLDFISH_OPENGL_SYSTEM_HALS_HOST_CONNECTION_SESSION_H_INCLUDED
+#define GOLDFISH_OPENGL_SYSTEM_HALS_HOST_CONNECTION_SESSION_H_INCLUDED
+
+#include "HostConnection.h"
+
+class HostConnectionSession {
+public:
+    explicit HostConnectionSession(HostConnection* hc) : conn(hc) {
+        hc->lock();
+    }
+
+    ~HostConnectionSession() {
+        if (conn) {
+            conn->unlock();
+        }
+     }
+
+    HostConnectionSession(HostConnectionSession&& rhs) : conn(rhs.conn) {
+        rhs.conn = nullptr;
+    }
+
+    HostConnectionSession& operator=(HostConnectionSession&& rhs) {
+        if (this != &rhs) {
+            std::swap(conn, rhs.conn);
+        }
+        return *this;
+    }
+
+    HostConnectionSession(const HostConnectionSession&) = delete;
+    HostConnectionSession& operator=(const HostConnectionSession&) = delete;
+
+    ExtendedRCEncoderContext* getRcEncoder() const {
+        return conn->rcEncoder();
+    }
+
+private:
+    HostConnection* conn;
+};
+
+#endif  // GOLDFISH_OPENGL_SYSTEM_HALS_HOST_CONNECTION_SESSION_H_INCLUDED
diff --git a/system/hals/mapper3.cpp b/system/hals/mapper3.cpp
new file mode 100644
index 0000000..99c6514
--- /dev/null
+++ b/system/hals/mapper3.cpp
@@ -0,0 +1,615 @@
+/*
+* 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 <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <cutils/native_handle.h>
+#include <sync/sync.h>
+
+#include "cb_handle_30.h"
+#include "host_connection_session.h"
+#include "FormatConversions.h"
+#include "debug.h"
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::graphics::common::V1_2::PixelFormat;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+
+namespace MapperV3 = ::android::hardware::graphics::mapper::V3_0;
+
+using IMapper3 = MapperV3::IMapper;
+using Error3 = MapperV3::Error;
+using YCbCrLayout3 = MapperV3::YCbCrLayout;
+
+namespace {
+size_t align(const size_t v, const size_t a) { return (v + a - 1) & ~(a - 1); }
+
+static int waitFenceFd(const int fd, const char* logname) {
+    const int warningTimeout = 5000;
+    if (sync_wait(dup(fd), warningTimeout) < 0) {
+        if (errno == ETIME) {
+            ALOGW("%s: fence %d didn't signal in %d ms", logname, fd, warningTimeout);
+            if (sync_wait(fd, -1) < 0) {
+                RETURN_ERROR(errno);
+            } else {
+                RETURN(0);
+            }
+        } else {
+            RETURN_ERROR(errno);
+        }
+    } else {
+        RETURN(0);
+    }
+}
+
+int waitHidlFence(const hidl_handle& hidlHandle, const char* logname) {
+    const native_handle_t* nativeHandle = hidlHandle.getNativeHandle();
+
+    if (!nativeHandle) {
+        RETURN(0);
+    }
+    if (nativeHandle->numFds > 1) {
+        RETURN_ERROR(-EINVAL);
+    }
+    if (nativeHandle->numInts != 0) {
+        RETURN_ERROR(-EINVAL);
+    }
+
+    return waitFenceFd(nativeHandle->data[0], logname);
+}
+
+class GoldfishMapper : public IMapper3 {
+public:
+    GoldfishMapper() : m_hostConn(HostConnection::createUnique()) {
+        GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator;
+        CRASH_IF(!host_memory_allocator.is_opened(),
+                 "GoldfishAddressSpaceHostMemoryAllocator failed to open");
+
+        GoldfishAddressSpaceBlock bufferBits;
+        CRASH_IF(host_memory_allocator.hostMalloc(&bufferBits, 256),
+                 "hostMalloc failed");
+
+        m_physAddrToOffset = bufferBits.physAddr() - bufferBits.offset();
+    }
+
+    Return<void> importBuffer(const hidl_handle& hh,
+                              importBuffer_cb hidl_cb) {
+        native_handle_t* imported = nullptr;
+        const Error3 e = importBufferImpl(hh.getNativeHandle(), &imported);
+        if (e == Error3::NONE) {
+            hidl_cb(Error3::NONE, imported);
+        } else {
+            hidl_cb(e, nullptr);
+        }
+        return {};
+    }
+
+    Return<Error3> freeBuffer(void* raw) {
+        if (!raw) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(raw);
+        if (!cb) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+
+        if (cb->hostHandle) {
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            rcEnc->rcCloseColorBuffer(rcEnc, cb->hostHandle);
+        }
+
+        if (cb->mmapedSize > 0) {
+            GoldfishAddressSpaceBlock::memoryUnmap(cb->getBufferPtr(), cb->mmapedSize);
+        }
+
+        native_handle_close(cb);
+        native_handle_delete(cb);
+
+        RETURN(Error3::NONE);
+    }
+
+    Return<void> lock(void* raw,
+                      uint64_t cpuUsage,
+                      const Rect& accessRegion,
+                      const hidl_handle& acquireFence,
+                      lock_cb hidl_cb) {
+        void* ptr = nullptr;
+        int32_t bytesPerPixel = 0;
+        int32_t bytesPerStride = 0;
+
+        const Error3 e = lockImpl(raw, cpuUsage, accessRegion, acquireFence,
+                                  &ptr, &bytesPerPixel, &bytesPerStride);
+        if (e == Error3::NONE) {
+            hidl_cb(Error3::NONE, ptr, bytesPerPixel, bytesPerStride);
+        } else {
+            hidl_cb(e, nullptr, 0, 0);
+        }
+        return {};
+    }
+
+    Return<void> lockYCbCr(void* raw,
+                           uint64_t cpuUsage,
+                           const Rect& accessRegion,
+                           const hidl_handle& acquireFence,
+                           lockYCbCr_cb hidl_cb) {
+        YCbCrLayout3 ycbcr = {};
+        const Error3 e = lockYCbCrImpl(raw, cpuUsage, accessRegion, acquireFence,
+                                       &ycbcr);
+        if (e == Error3::NONE) {
+            hidl_cb(Error3::NONE, ycbcr);
+        } else {
+            hidl_cb(e, {});
+        }
+        return {};
+    }
+
+    Return<void> unlock(void* raw, unlock_cb hidl_cb) {
+        hidl_cb(unlockImpl(raw), {});
+        return {};
+
+    }
+
+    Return<void> createDescriptor(const BufferDescriptorInfo& description,
+                                  createDescriptor_cb hidl_cb) {
+        hidl_vec<uint32_t> raw;
+        encodeBufferDescriptorInfo(description, &raw);
+        hidl_cb(Error3::NONE, raw);
+        return {};
+    }
+
+    Return<void> isSupported(const IMapper::BufferDescriptorInfo& description,
+                             isSupported_cb hidl_cb) {
+        hidl_cb(Error3::NONE, isSupportedImpl(description));
+        return {};
+    }
+
+    Return<Error3> validateBufferSize(void* buffer,
+                                      const BufferDescriptorInfo& descriptor,
+                                      uint32_t stride) {
+        const cb_handle_30_t* cb = cb_handle_30_t::from(buffer);
+        if (cb) {
+            return validateBufferSizeImpl(*cb, descriptor, stride);
+        } else {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+    }
+
+    Return<void> getTransportSize(void* buffer,
+                                  getTransportSize_cb hidl_cb) {
+        const cb_handle_30_t* cb = cb_handle_30_t::from(buffer);
+        if (cb) {
+            hidl_cb(Error3::NONE, cb->numFds, cb->numInts);
+        } else {
+            hidl_cb(Error3::BAD_BUFFER, 0, 0);
+        }
+
+        return {};
+    }
+
+private:  // **** impl ****
+    Error3 importBufferImpl(const native_handle_t* nh, native_handle_t** phandle) {
+        if (!nh) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        native_handle_t* imported = native_handle_clone(nh);
+        if (!imported) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(imported);
+        if (!cb) {
+            native_handle_close(imported);
+            native_handle_delete(imported);
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+
+        if (cb->mmapedSize > 0) {
+            void* ptr;
+            const int res = GoldfishAddressSpaceBlock::memoryMap(
+                cb->getBufferPtr(),
+                cb->mmapedSize,
+                cb->bufferFd,
+                cb->getMmapedOffset(),
+                &ptr);
+            if (res) {
+                native_handle_close(imported);
+                native_handle_delete(imported);
+                RETURN_ERROR(Error3::NO_RESOURCES);
+            }
+            cb->setBufferPtr(ptr);
+        }
+
+        if (cb->hostHandle) {
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            rcEnc->rcOpenColorBuffer2(rcEnc, cb->hostHandle);
+        }
+
+        *phandle = imported;
+        RETURN(Error3::NONE);
+    }
+
+    Error3 lockImpl(void* raw,
+                    uint64_t cpuUsage,
+                    const Rect& accessRegion,
+                    const hidl_handle& acquireFence,
+                    void** pptr,
+                    int32_t* pBytesPerPixel,
+                    int32_t* pBytesPerStride) {
+        if (!raw) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(raw);
+        if (!cb) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (!cb->bufferSize) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
+        if (!bufferBits) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (waitHidlFence(acquireFence, __func__)) {
+            RETURN_ERROR(Error3::BAD_VALUE);
+        }
+
+        if (cb->hostHandle) {
+            const Error3 e = lockHostImpl(*cb, cpuUsage, accessRegion, bufferBits);
+            if (e != Error3::NONE) {
+                return e;
+            }
+        }
+
+        *pptr = bufferBits;
+        *pBytesPerPixel = cb->bytesPerPixel;
+        *pBytesPerStride = cb->bytesPerPixel * cb->stride;
+        RETURN(Error3::NONE);
+    }
+
+    Error3 lockYCbCrImpl(void* raw,
+                         uint64_t cpuUsage,
+                         const Rect& accessRegion,
+                         const hidl_handle& acquireFence,
+                         YCbCrLayout3* pYcbcr) {
+        if (!raw) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(raw);
+        if (!cb) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (!cb->bufferSize) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
+        if (!bufferBits) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (waitHidlFence(acquireFence, __func__)) {
+            RETURN_ERROR(Error3::BAD_VALUE);
+        }
+
+        size_t uOffset;
+        size_t vOffset;
+        size_t yStride;
+        size_t cStride;
+        size_t cStep;
+        switch (static_cast<PixelFormat>(cb->format)) {
+        case PixelFormat::YCRCB_420_SP:
+            yStride = cb->width;
+            cStride = yStride;
+            vOffset = yStride * cb->height;
+            uOffset = vOffset + 1;
+            cStep = 2;
+            break;
+
+        case PixelFormat::YV12:
+            // https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12
+            yStride = align(cb->width, 16);
+            cStride = align(yStride / 2, 16);
+            vOffset = yStride * cb->height;
+            uOffset = vOffset + (cStride * cb->height / 2);
+            cStep = 1;
+            break;
+
+        case PixelFormat::YCBCR_420_888:
+            yStride = cb->width;
+            cStride = yStride / 2;
+            uOffset = cb->height * yStride;
+            vOffset = uOffset + cStride * cb->height / 2;
+            cStep = 1;
+            break;
+
+        default:
+            ALOGE("%s:%d unexpected format (%d)", __func__, __LINE__, cb->format);
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+
+        if (cb->hostHandle) {
+            const Error3 e = lockHostImpl(*cb, cpuUsage, accessRegion, bufferBits);
+            if (e != Error3::NONE) {
+                return e;
+            }
+        }
+
+        pYcbcr->y = bufferBits;
+        pYcbcr->cb = bufferBits + uOffset;
+        pYcbcr->cr = bufferBits + vOffset;
+        pYcbcr->yStride = yStride;
+        pYcbcr->cStride = cStride;
+        pYcbcr->chromaStep = cStep;
+
+        RETURN(Error3::NONE);
+    }
+
+    Error3 lockHostImpl(cb_handle_30_t& cb,
+                        const uint32_t usage,
+                        const Rect& accessRegion,
+                        char* const bufferBits) {
+        const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
+        const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
+        const bool usageHwCamera = usage & (BufferUsage::CAMERA_INPUT | BufferUsage::CAMERA_OUTPUT);
+        const bool usageHwCameraWrite = usage & BufferUsage::CAMERA_OUTPUT;
+
+        const HostConnectionSession conn = getHostConnectionSession();
+        ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+
+        const int res = rcEnc->rcColorBufferCacheFlush(
+            rcEnc, cb.hostHandle, 0, usageSwRead);
+        if (res < 0) {
+            RETURN_ERROR(Error3::NO_RESOURCES);
+        }
+
+        // camera delivers bits to the buffer directly and does not require
+        // an explicit read.
+        if (usageSwRead && !usageHwCamera) {
+            if (gralloc_is_yuv_format(cb.format)) {
+                if (rcEnc->hasYUVCache()) {
+                    uint32_t bufferSize;
+                    switch (static_cast<PixelFormat>(cb.format)) {
+                    case PixelFormat::YV12:
+                        get_yv12_offsets(cb.width, cb.height,
+                                         nullptr, nullptr, &bufferSize);
+                        break;
+                    case PixelFormat::YCBCR_420_888:
+                        get_yuv420p_offsets(cb.width, cb.height,
+                                            nullptr, nullptr, &bufferSize);
+                        break;
+                    default:
+                        CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                        break;
+                    }
+
+                    rcEnc->rcReadColorBufferYUV(rcEnc, cb.hostHandle,
+                        0, 0, cb.width, cb.height,
+                        bufferBits, bufferSize);
+                } else {
+                    // We are using RGB888
+                    std::vector<char> tmpBuf(cb.width * cb.height * 3);
+                    rcEnc->rcReadColorBuffer(rcEnc, cb.hostHandle,
+                                             0, 0, cb.width, cb.height,
+                                             cb.glFormat, cb.glType,
+                                             tmpBuf.data());
+                    switch (static_cast<PixelFormat>(cb.format)) {
+                    case PixelFormat::YV12:
+                        rgb888_to_yv12(bufferBits, tmpBuf.data(),
+                                       cb.width, cb.height,
+                                       accessRegion.left,
+                                       accessRegion.top,
+                                       accessRegion.left + accessRegion.width - 1,
+                                       accessRegion.top + accessRegion.height - 1);
+                        break;
+                    case PixelFormat::YCBCR_420_888:
+                        rgb888_to_yuv420p(bufferBits, tmpBuf.data(),
+                                          cb.width, cb.height,
+                                          accessRegion.left,
+                                          accessRegion.top,
+                                          accessRegion.left + accessRegion.width - 1,
+                                          accessRegion.top + accessRegion.height - 1);
+                        break;
+                    default:
+                        CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                        break;
+                    }
+                }
+            } else {
+                rcEnc->rcReadColorBuffer(rcEnc,
+                                         cb.hostHandle,
+                                         0, 0, cb.width, cb.height,
+                                         cb.glFormat, cb.glType,
+                                         bufferBits);
+            }
+        }
+
+        if (usageSwWrite || usageHwCameraWrite) {
+            cb.lockedLeft = accessRegion.left;
+            cb.lockedTop = accessRegion.top;
+            cb.lockedWidth = accessRegion.width;
+            cb.lockedHeight = accessRegion.height;
+        } else {
+            cb.lockedLeft = 0;
+            cb.lockedTop = 0;
+            cb.lockedWidth = cb.width;
+            cb.lockedHeight = cb.height;
+        }
+
+        RETURN(Error3::NONE);
+    }
+
+    Error3 unlockImpl(void* raw) {
+        if (!raw) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        cb_handle_30_t* cb = cb_handle_30_t::from(raw);
+        if (!cb) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        if (!cb->bufferSize) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+        char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
+        if (!bufferBits) {
+            RETURN_ERROR(Error3::BAD_BUFFER);
+        }
+
+        if (cb->hostHandle) {
+            unlockHostImpl(*cb, bufferBits);
+        }
+
+        RETURN(Error3::NONE);
+    }
+
+    void unlockHostImpl(cb_handle_30_t& cb, char* const bufferBits) {
+        const int bpp = glUtilsPixelBitSize(cb.glFormat, cb.glType) >> 3;
+        const int left = cb.lockedLeft;
+        const int top = cb.lockedTop;
+        const int width = cb.lockedWidth;
+        const int height = cb.lockedHeight;
+        const uint32_t rgbSize = width * height * bpp;
+        std::vector<char> convertedBuf;
+        const char* bitsToSend;
+        uint32_t sizeToSend;
+
+        if (gralloc_is_yuv_format(cb.format)) {
+            bitsToSend = bufferBits;
+            switch (static_cast<PixelFormat>(cb.format)) {
+            case PixelFormat::YV12:
+                get_yv12_offsets(width, height, nullptr, nullptr, &sizeToSend);
+                break;
+            case PixelFormat::YCBCR_420_888:
+                get_yuv420p_offsets(width, height, nullptr, nullptr, &sizeToSend);
+                break;
+            default:
+                CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
+                break;
+            }
+        } else {
+            convertedBuf.resize(rgbSize);
+            copy_rgb_buffer_from_unlocked(
+                convertedBuf.data(), bufferBits,
+                cb.width,
+                width, height, top, left, bpp);
+            bitsToSend = convertedBuf.data();
+            sizeToSend = rgbSize;
+        }
+
+        {
+            const HostConnectionSession conn = getHostConnectionSession();
+            ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
+            rcEnc->bindDmaDirectly(bufferBits,
+                                   getMmapedPhysAddr(cb.getMmapedOffset()));
+            rcEnc->rcUpdateColorBufferDMA(rcEnc, cb.hostHandle,
+                    left, top, width, height,
+                    cb.glFormat, cb.glType,
+                    const_cast<char*>(bitsToSend), sizeToSend);
+        }
+
+        cb.lockedLeft = 0;
+        cb.lockedTop = 0;
+        cb.lockedWidth = 0;
+        cb.lockedHeight = 0;
+    }
+
+    bool isSupportedImpl(const IMapper::BufferDescriptorInfo& descriptor) const {
+        if (!descriptor.width) { RETURN(false); }
+        if (!descriptor.height) { RETURN(false); }
+        if (descriptor.layerCount != 1) { RETURN(false); }
+
+        const uint32_t usage = descriptor.usage;
+        const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
+        const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
+        const bool usageHwCamWrite = usage & BufferUsage::CAMERA_OUTPUT;
+        const bool usageHwCamRead = usage & BufferUsage::CAMERA_INPUT;
+
+        switch (descriptor.format) {
+        case PixelFormat::RGBA_8888:
+        case PixelFormat::RGBX_8888:
+        case PixelFormat::BGRA_8888:
+        case PixelFormat::RGB_565:
+        case PixelFormat::RGBA_FP16:
+        case PixelFormat::RGBA_1010102:
+        case PixelFormat::YCRCB_420_SP:
+        case PixelFormat::YV12:
+        case PixelFormat::YCBCR_420_888:
+            RETURN(true);
+
+        case PixelFormat::IMPLEMENTATION_DEFINED:
+            if (usage & BufferUsage::CAMERA_OUTPUT) {
+                if (usage & BufferUsage::GPU_TEXTURE) {
+                    RETURN(true);
+                } else if (usage & BufferUsage::VIDEO_ENCODER) {
+                    RETURN(true);
+                }
+            }
+            RETURN(false);
+
+        case PixelFormat::RGB_888:
+            RETURN(0 == (usage & (BufferUsage::GPU_TEXTURE |
+                                  BufferUsage::GPU_RENDER_TARGET |
+                                  BufferUsage::COMPOSER_OVERLAY |
+                                  BufferUsage::COMPOSER_CLIENT_TARGET)));
+
+        case PixelFormat::RAW16:
+        case PixelFormat::Y16:
+            RETURN((usageSwRead || usageHwCamRead) &&
+                   (usageSwWrite || usageHwCamWrite));
+
+        case PixelFormat::BLOB:
+            RETURN(usageSwRead);
+
+        default:
+            RETURN(false);
+        }
+    }
+
+    Error3 validateBufferSizeImpl(const cb_handle_t& /*cb*/,
+                                  const BufferDescriptorInfo& /*descriptor*/,
+                                  uint32_t /*stride*/) {
+        RETURN(Error3::NONE);
+    }
+
+    HostConnectionSession getHostConnectionSession() const {
+        return HostConnectionSession(m_hostConn);
+    }
+
+    static void encodeBufferDescriptorInfo(const BufferDescriptorInfo& d,
+                                           hidl_vec<uint32_t>* raw) {
+        raw->resize(5);
+
+        (*raw)[0] = d.width;
+        (*raw)[1] = d.height;
+        (*raw)[2] = d.layerCount;
+        (*raw)[3] = static_cast<uint32_t>(d.format);
+        (*raw)[4] = d.usage & UINT32_MAX;
+    }
+
+    uint64_t getMmapedPhysAddr(uint64_t offset) const {
+        return m_physAddrToOffset + offset;
+    }
+
+    //std::unique_ptr<HostConnection> m_hostConn;  // b/142677230
+    HostConnection* m_hostConn;
+    uint64_t m_physAddrToOffset;
+};
+}  // namespace
+
+extern "C" IMapper3* HIDL_FETCH_IMapper(const char* /*name*/) {
+    return new GoldfishMapper;
+}
diff --git a/system/hals/types.h b/system/hals/types.h
new file mode 100644
index 0000000..c7d2646
--- /dev/null
+++ b/system/hals/types.h
@@ -0,0 +1,43 @@
+/*
+* 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.
+*/
+
+#ifndef GOLDFISH_OPENGL_SYSTEM_HALS_TYPES_H_INCLUDED
+#define GOLDFISH_OPENGL_SYSTEM_HALS_TYPES_H_INCLUDED
+
+/* Tell the emulator which formats need special handling. */
+enum class EmulatorFrameworkFormat {
+    GL_COMPATIBLE = 0,
+    YV12 = 1,
+    YUV_420_888 = 2, // (Y+)(U+)(V+)
+};
+
+#ifndef GL_RGBA16F
+#define GL_RGBA16F                        0x881A
+#endif // GL_RGBA16F
+
+#ifndef GL_HALF_FLOAT
+#define GL_HALF_FLOAT                     0x140B
+#endif // GL_HALF_FLOAT
+
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2                       0x8059
+#endif // GL_RGB10_A2
+
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
+#endif // GL_UNSIGNED_INT_2_10_10_10_REV
+
+#endif  // GOLDFISH_OPENGL_SYSTEM_HALS_TYPES_H_INCLUDED