Snap for 5949240 from 858a972d1ce2eb048066c8a136e28f24bda5dc24 to sdk-release

Change-Id: I0524f6eefdb739f976075141907fa5824f6ca064
diff --git a/BUILD.gn b/BUILD.gn
index 52f4635..c6e0201 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -4,6 +4,7 @@
     "android-emu/android/base/AlignedBuf.h",
     "android-emu/android/base/Pool.cpp",
     "android-emu/android/base/Pool.h",
+    "android-emu/android/base/ring_buffer.c",
     "android-emu/android/base/SubAllocator.cpp",
     "android-emu/android/base/SubAllocator.h",
     "android-emu/android/base/files/MemStream.cpp",
@@ -91,6 +92,14 @@
     "PAGE_SIZE=4096",
   ]
 
+  cflags_c = [
+    "-Wno-missing-field-initializers",
+    "-Wno-newline-eof",
+    "-Wno-unused-function",
+    "-Wno-unused-value",
+    "-Wno-unused-variable",
+  ]
+
   cflags_cc = [
     "-Wno-missing-field-initializers",
     "-Wno-newline-eof",
diff --git a/android-emu/Android.mk b/android-emu/Android.mk
index 9ef32cd..6de495e 100644
--- a/android-emu/Android.mk
+++ b/android-emu/Android.mk
@@ -16,6 +16,7 @@
     android/base/files/Stream.cpp \
     android/base/files/StreamSerializing.cpp \
     android/base/Pool.cpp \
+    android/base/ring_buffer.c \
     android/base/StringFormat.cpp \
     android/base/SubAllocator.cpp \
     android/base/synchronization/AndroidMessageChannel.cpp \
diff --git a/android-emu/CMakeLists.txt b/android-emu/CMakeLists.txt
index ffa1fd2..e6482d8 100644
--- a/android-emu/CMakeLists.txt
+++ b/android-emu/CMakeLists.txt
@@ -1,8 +1,8 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/android-emu/Android.mk" "74426692eff285e93994e82bdc6a648312c8a6e7f0b2daf22fe255ac5bfd3b64")
-set(androidemu_src android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/StringFormat.cpp android/base/SubAllocator.cpp android/base/synchronization/AndroidMessageChannel.cpp android/base/threads/AndroidFunctorThread.cpp android/base/threads/AndroidThreadStore.cpp android/base/threads/AndroidThread_pthread.cpp android/base/threads/AndroidWorkPool.cpp android/base/Tracing.cpp android/utils/debug.c)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/android-emu/Android.mk" "3654f06acfa661c75b91fe271337a63a77326a69b4247026996c40bff8138bde")
+set(androidemu_src android/base/AlignedBuf.cpp android/base/files/MemStream.cpp android/base/files/Stream.cpp android/base/files/StreamSerializing.cpp android/base/Pool.cpp android/base/ring_buffer.c android/base/StringFormat.cpp android/base/SubAllocator.cpp android/base/synchronization/AndroidMessageChannel.cpp android/base/threads/AndroidFunctorThread.cpp android/base/threads/AndroidThreadStore.cpp android/base/threads/AndroidThread_pthread.cpp android/base/threads/AndroidWorkPool.cpp android/base/Tracing.cpp android/utils/debug.c)
 android_add_shared_library(androidemu)
 target_include_directories(androidemu PRIVATE ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(androidemu PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"androidemu\"")
diff --git a/android-emu/android/base/ring_buffer.c b/android-emu/android/base/ring_buffer.c
new file mode 100644
index 0000000..ef26d1d
--- /dev/null
+++ b/android-emu/android/base/ring_buffer.c
@@ -0,0 +1,521 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "android/base/ring_buffer.h"
+
+#include <errno.h>
+#include <string.h>
+#ifdef _MSC_VER
+#include "msvc-posix.h"
+#else
+#include <sys/time.h>
+#endif
+
+#if (defined(__i386__) || defined(__x86_64__))
+#define RING_BUFFER_X86 1
+#else
+#define RING_BUFFER_X86 0
+#endif
+
+#if RING_BUFFER_X86
+#include <emmintrin.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sched.h>
+#include <unistd.h>
+#endif
+
+#define RING_BUFFER_MASK (RING_BUFFER_SIZE - 1)
+
+#define RING_BUFFER_VERSION 1
+
+static inline void ring_buffer_pause() {
+#if RING_BUFFER_X86
+    _mm_pause();
+#else
+    // TODO(lfy) analog of pause on ARM
+#endif
+}
+
+void ring_buffer_init(struct ring_buffer* r) {
+    r->guest_version = 1;
+    r->write_pos = 0;
+    r->read_pos = 0;
+
+    r->read_live_count = 0;
+    r->read_yield_count = 0;
+    r->read_sleep_us_count = 0;
+
+    r->state = 0;
+}
+
+static uint32_t get_ring_pos(uint32_t index) {
+    return index & RING_BUFFER_MASK;
+}
+
+bool ring_buffer_can_write(const struct ring_buffer* r, uint32_t bytes) {
+    uint32_t read_view;
+    __atomic_load(&r->read_pos, &read_view, __ATOMIC_SEQ_CST);
+    return get_ring_pos(read_view - r->write_pos - 1) >= bytes;
+}
+
+bool ring_buffer_can_read(const struct ring_buffer* r, uint32_t bytes) {
+    uint32_t write_view;
+    __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST);
+    return get_ring_pos(write_view - r->read_pos) >= bytes;
+}
+
+long ring_buffer_write(
+    struct ring_buffer* r, const void* data, uint32_t step_size, uint32_t steps) {
+    const uint8_t* data_bytes = (const uint8_t*)data;
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_can_write(r, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        // Needs to be split up into 2 writes for the edge case.
+        uint32_t available_at_end =
+            RING_BUFFER_SIZE - get_ring_pos(r->write_pos);
+
+        if (step_size > available_at_end) {
+            uint32_t remaining = step_size - available_at_end;
+            memcpy(
+                &r->buf[get_ring_pos(r->write_pos)],
+                data_bytes + i * step_size,
+                available_at_end);
+            memcpy(
+                &r->buf[get_ring_pos(r->write_pos + available_at_end)],
+                data_bytes + i * step_size + available_at_end,
+                remaining);
+        } else {
+            memcpy(
+                &r->buf[get_ring_pos(r->write_pos)],
+                data_bytes + i * step_size,
+                step_size);
+        }
+
+        __atomic_add_fetch(&r->write_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+}
+
+long ring_buffer_read(
+    struct ring_buffer* r, void* data, uint32_t step_size, uint32_t steps) {
+    uint8_t* data_bytes = (uint8_t*)data;
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_can_read(r, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        // Needs to be split up into 2 reads for the edge case.
+        uint32_t available_at_end =
+            RING_BUFFER_SIZE - get_ring_pos(r->read_pos);
+
+        if (step_size > available_at_end) {
+            uint32_t remaining = step_size - available_at_end;
+            memcpy(
+                data_bytes + i * step_size,
+                &r->buf[get_ring_pos(r->read_pos)],
+                available_at_end);
+            memcpy(
+                data_bytes + i * step_size + available_at_end,
+                &r->buf[get_ring_pos(r->read_pos + available_at_end)],
+                remaining);
+        } else {
+            memcpy(
+                data_bytes + i * step_size,
+                &r->buf[get_ring_pos(r->read_pos)],
+                step_size);
+        }
+
+        __atomic_add_fetch(&r->read_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+}
+
+uint32_t ring_buffer_calc_shift(uint32_t size) {
+    uint32_t shift = 0;
+    while ((1 << shift) < size) {
+        ++shift;
+    }
+
+    // if size is not a power of 2,
+    if ((1 << shift) > size) {
+        --shift;
+    }
+    return shift;
+}
+
+void ring_buffer_view_init(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    uint8_t* buf,
+    uint32_t size) {
+
+    uint32_t shift = ring_buffer_calc_shift(size);
+
+    ring_buffer_init(r);
+
+    v->buf = buf;
+    v->size = (1 << shift);
+    v->mask = (1 << shift) - 1;
+}
+
+void ring_buffer_init_view_only(
+    struct ring_buffer_view* v,
+    uint8_t* buf,
+    uint32_t size) {
+
+    uint32_t shift = ring_buffer_calc_shift(size);
+
+    v->buf = buf;
+    v->size = (1 << shift);
+    v->mask = (1 << shift) - 1;
+}
+
+static uint32_t ring_buffer_view_get_ring_pos(
+    const struct ring_buffer_view* v,
+    uint32_t index) {
+    return index & v->mask;
+}
+
+bool ring_buffer_view_can_write(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes) {
+    uint32_t read_view;
+    __atomic_load(&r->read_pos, &read_view, __ATOMIC_SEQ_CST);
+    return ring_buffer_view_get_ring_pos(
+            v, read_view - r->write_pos - 1) >= bytes;
+}
+
+bool ring_buffer_view_can_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes) {
+    uint32_t write_view;
+    __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST);
+    return ring_buffer_view_get_ring_pos(
+            v, write_view - r->read_pos) >= bytes;
+}
+
+uint32_t ring_buffer_available_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v) {
+    uint32_t write_view;
+    __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST);
+    if (v) {
+        return ring_buffer_view_get_ring_pos(
+                v, write_view - r->read_pos);
+    } else {
+        return get_ring_pos(write_view - r->read_pos);
+    }
+}
+
+long ring_buffer_view_write(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data, uint32_t step_size, uint32_t steps) {
+
+    uint8_t* data_bytes = (uint8_t*)data;
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_view_can_write(r, v, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        // Needs to be split up into 2 writes for the edge case.
+        uint32_t available_at_end =
+            v->size - ring_buffer_view_get_ring_pos(v, r->write_pos);
+
+        if (step_size > available_at_end) {
+            uint32_t remaining = step_size - available_at_end;
+            memcpy(
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos)],
+                data_bytes + i * step_size,
+                available_at_end);
+            memcpy(
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos + available_at_end)],
+                data_bytes + i * step_size + available_at_end,
+                remaining);
+        } else {
+            memcpy(
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos)],
+                data_bytes + i * step_size,
+                step_size);
+        }
+
+        __atomic_add_fetch(&r->write_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+
+}
+
+long ring_buffer_view_read(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data, uint32_t step_size, uint32_t steps) {
+    uint8_t* data_bytes = (uint8_t*)data;
+    uint32_t i;
+
+    for (i = 0; i < steps; ++i) {
+        if (!ring_buffer_view_can_read(r, v, step_size)) {
+            errno = -EAGAIN;
+            return (long)i;
+        }
+
+        // Needs to be split up into 2 reads for the edge case.
+        uint32_t available_at_end =
+            v->size - ring_buffer_view_get_ring_pos(v, r->read_pos);
+
+        if (step_size > available_at_end) {
+            uint32_t remaining = step_size - available_at_end;
+            memcpy(
+                data_bytes + i * step_size,
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)],
+                available_at_end);
+            memcpy(
+                data_bytes + i * step_size + available_at_end,
+                &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos + available_at_end)],
+                remaining);
+        } else {
+            memcpy(data_bytes + i * step_size,
+                   &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)],
+                   step_size);
+        }
+        __atomic_add_fetch(&r->read_pos, step_size, __ATOMIC_SEQ_CST);
+    }
+
+    errno = 0;
+    return (long)steps;
+}
+
+void ring_buffer_yield() {
+#ifdef _WIN32
+    if (!SwitchToThread()) {
+        Sleep(0);
+    }
+#else
+    sched_yield();
+#endif
+}
+
+static void ring_buffer_sleep() {
+#ifdef _WIN32
+    Sleep(2);
+#else
+    usleep(2000);
+#endif
+}
+
+static uint64_t ring_buffer_curr_us() {
+    uint64_t res;
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    res = tv.tv_sec * 1000000ULL + tv.tv_usec;
+    return res;
+}
+
+static const uint32_t yield_backoff_us = 1000;
+static const uint32_t sleep_backoff_us = 2000;
+
+bool ring_buffer_wait_write(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes,
+    uint64_t timeout_us) {
+
+    bool can_write =
+        v ? ring_buffer_view_can_write(r, v, bytes) :
+            ring_buffer_can_write(r, bytes);
+
+    while (!can_write) {
+        ring_buffer_yield();
+        can_write =
+            v ? ring_buffer_view_can_write(r, v, bytes) :
+                ring_buffer_can_write(r, bytes);
+    }
+
+    return true;
+}
+
+bool ring_buffer_wait_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes,
+    uint64_t timeout_us) {
+
+    bool can_read =
+        v ? ring_buffer_view_can_read(r, v, bytes) :
+            ring_buffer_can_read(r, bytes);
+
+    while (!can_read) {
+        ring_buffer_yield();
+        can_read =
+            v ? ring_buffer_view_can_read(r, v, bytes) :
+                ring_buffer_can_read(r, bytes);
+    }
+
+    ((struct ring_buffer*)r)->read_live_count++;
+    return true;
+}
+
+static uint32_t get_step_size(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    uint32_t bytes) {
+
+    uint32_t step_shift = 0;
+    uint32_t available = v ? (v->size >> 1) : (RING_BUFFER_SIZE >> 1);
+    uint32_t res = available < bytes ? available : bytes;
+
+    return res;
+}
+
+void ring_buffer_write_fully(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data,
+    uint32_t bytes) {
+
+    uint32_t candidate_step = get_step_size(r, v, bytes);
+    uint32_t processed = 0;
+
+    uint8_t* dst = (uint8_t*)data;
+
+    while (processed < bytes) {
+        if (bytes - processed < candidate_step) {
+            candidate_step = bytes - processed;
+        }
+
+        long processed_here = 0;
+        ring_buffer_wait_write(r, v, candidate_step, (uint64_t)(-1));
+
+        if (v) {
+            processed_here = ring_buffer_view_write(r, v, dst + processed, candidate_step, 1);
+        } else {
+            processed_here = ring_buffer_write(r, dst + processed, candidate_step, 1);
+        }
+
+        processed += processed_here ? candidate_step : 0;
+    }
+}
+
+void ring_buffer_read_fully(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data,
+    uint32_t bytes) {
+
+    uint32_t candidate_step = get_step_size(r, v, bytes);
+    uint32_t processed = 0;
+
+    uint8_t* dst = (uint8_t*)data;
+
+    while (processed < bytes) {
+        ring_buffer_pause();
+        if (bytes - processed < candidate_step) {
+            candidate_step = bytes - processed;
+        }
+
+        long processed_here = 0;
+        ring_buffer_wait_read(r, v, candidate_step, (uint64_t)(-1));
+
+        if (v) {
+            processed_here = ring_buffer_view_read(r, v, dst + processed, candidate_step, 1);
+        } else {
+            processed_here = ring_buffer_read(r, dst + processed, candidate_step, 1);
+        }
+
+        processed += processed_here ? candidate_step : 0;
+    }
+}
+
+void ring_buffer_sync_init(struct ring_buffer* r) {
+    __atomic_store_n(&r->state, RING_BUFFER_SYNC_PRODUCER_IDLE, __ATOMIC_SEQ_CST);
+}
+
+bool ring_buffer_producer_acquire(struct ring_buffer* r) {
+    uint32_t expected_idle = RING_BUFFER_SYNC_PRODUCER_IDLE;
+    bool success = __atomic_compare_exchange_n(
+        &r->state,
+        &expected_idle,
+        RING_BUFFER_SYNC_PRODUCER_ACTIVE,
+        false /* strong */,
+        __ATOMIC_SEQ_CST,
+        __ATOMIC_SEQ_CST);
+    return success;
+}
+
+bool ring_buffer_producer_acquire_from_hangup(struct ring_buffer* r) {
+    uint32_t expected_hangup = RING_BUFFER_SYNC_CONSUMER_HUNG_UP;
+    bool success = __atomic_compare_exchange_n(
+        &r->state,
+        &expected_hangup,
+        RING_BUFFER_SYNC_PRODUCER_ACTIVE,
+        false /* strong */,
+        __ATOMIC_SEQ_CST,
+        __ATOMIC_SEQ_CST);
+    return success;
+}
+
+void ring_buffer_producer_wait_hangup(struct ring_buffer* r) {
+    while (__atomic_load_n(&r->state, __ATOMIC_SEQ_CST) !=
+           RING_BUFFER_SYNC_CONSUMER_HUNG_UP) {
+        ring_buffer_yield();
+    }
+}
+
+void ring_buffer_producer_idle(struct ring_buffer* r) {
+    __atomic_store_n(&r->state, RING_BUFFER_SYNC_PRODUCER_IDLE, __ATOMIC_SEQ_CST);
+}
+
+bool ring_buffer_consumer_hangup(struct ring_buffer* r) {
+    uint32_t expected_idle = RING_BUFFER_SYNC_PRODUCER_IDLE;
+    bool success = __atomic_compare_exchange_n(
+        &r->state,
+        &expected_idle,
+        RING_BUFFER_SYNC_CONSUMER_HANGING_UP,
+        false /* strong */,
+        __ATOMIC_SEQ_CST,
+        __ATOMIC_SEQ_CST);
+    return success;
+}
+
+void ring_buffer_consumer_wait_producer_idle(struct ring_buffer* r) {
+    while (__atomic_load_n(&r->state, __ATOMIC_SEQ_CST) !=
+           RING_BUFFER_SYNC_PRODUCER_IDLE) {
+        ring_buffer_yield();
+    }
+}
+
+void ring_buffer_consumer_hung_up(struct ring_buffer* r) {
+    __atomic_store_n(&r->state, RING_BUFFER_SYNC_CONSUMER_HUNG_UP, __ATOMIC_SEQ_CST);
+}
diff --git a/android-emu/android/base/ring_buffer.h b/android-emu/android/base/ring_buffer.h
new file mode 100644
index 0000000..34c0666
--- /dev/null
+++ b/android-emu/android/base/ring_buffer.h
@@ -0,0 +1,185 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define RING_BUFFER_SHIFT 11
+#define RING_BUFFER_SIZE (1 << RING_BUFFER_SHIFT)
+#define NUM_CONFIG_FIELDS 32
+
+// Single producer/consumer ring buffer struct that can be shared
+// between host and guest as-is.
+struct ring_buffer {
+    uint32_t host_version;
+    uint32_t guest_version;
+    uint32_t write_pos; // Atomically updated for the consumer
+    uint32_t unused0[13]; // Separate cache line
+    uint32_t read_pos; // Atomically updated for the producer
+    uint32_t read_live_count;
+    uint32_t read_yield_count;
+    uint32_t read_sleep_us_count;
+    uint32_t unused1[12]; // Separate cache line
+    uint8_t buf[RING_BUFFER_SIZE];
+    uint32_t state; // An atomically updated variable from both
+                    // producer and consumer for other forms of
+                    // coordination.
+    // Configuration fields
+    uint32_t config[NUM_CONFIG_FIELDS];
+};
+
+void ring_buffer_init(struct ring_buffer* r);
+
+// Writes or reads step_size at a time. Sets errno=EAGAIN if full or empty.
+// Returns the number of step_size steps read.
+long ring_buffer_write(
+    struct ring_buffer* r, const void* data, uint32_t step_size, uint32_t steps);
+long ring_buffer_read(
+    struct ring_buffer* r, void* data, uint32_t step_size, uint32_t steps);
+
+// If we want to work with dynamically allocated buffers, a separate struct is
+// needed; the host and guest are in different address spaces and thus have
+// different views of the same memory, with the host and guest having different
+// copies of this struct.
+struct ring_buffer_view {
+    uint8_t* buf;
+    uint32_t size;
+    uint32_t mask;
+};
+
+
+// Calculates the highest power of 2 so that
+// (1 << shift) <= size.
+uint32_t ring_buffer_calc_shift(uint32_t size);
+
+// Initializes ring buffer with view using |buf|. If |size| is not a power of
+// two, then the buffer will assume a size equal to the greater power of two
+// less than |size|.
+void ring_buffer_view_init(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    uint8_t* buf,
+    uint32_t size);
+
+void ring_buffer_init_view_only(
+    struct ring_buffer_view* v,
+    uint8_t* buf,
+    uint32_t size);
+
+// Read/write functions with the view.
+long ring_buffer_view_write(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data, uint32_t step_size, uint32_t steps);
+long ring_buffer_view_read(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data, uint32_t step_size, uint32_t steps);
+
+// Usage of ring_buffer as a waitable object.
+// These functions will back off if spinning too long.
+//
+// if |v| is null, it is assumed that the statically allocated ring buffer is
+// used.
+//
+// Returns true if ring buffer became available, false if timed out.
+bool ring_buffer_wait_write(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes,
+    uint64_t timeout_us);
+bool ring_buffer_wait_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes,
+    uint64_t timeout_us);
+
+// read/write fully, blocking if there is nothing to read/write.
+void ring_buffer_write_fully(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    const void* data,
+    uint32_t bytes);
+void ring_buffer_read_fully(
+    struct ring_buffer* r,
+    struct ring_buffer_view* v,
+    void* data,
+    uint32_t bytes);
+
+bool ring_buffer_can_write(
+    const struct ring_buffer* r, uint32_t bytes);
+bool ring_buffer_can_read(
+    const struct ring_buffer* r, uint32_t bytes);
+bool ring_buffer_view_can_write(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes);
+bool ring_buffer_view_can_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v,
+    uint32_t bytes);
+uint32_t ring_buffer_available_read(
+    const struct ring_buffer* r,
+    const struct ring_buffer_view* v);
+
+// Lockless synchronization where the consumer is allowed to hang up and go to
+// sleep. This can be considered a sort of asymmetric lock for two threads,
+// where the consumer can be more sleepy. It captures the pattern we usually use
+// for emulator devices; the guest asks the host for something, and some host
+// thread services the request and goes back to sleep.
+enum ring_buffer_sync_state {
+    RING_BUFFER_SYNC_PRODUCER_IDLE = 0,
+    RING_BUFFER_SYNC_PRODUCER_ACTIVE = 1,
+    RING_BUFFER_SYNC_CONSUMER_HANGING_UP = 2,
+    RING_BUFFER_SYNC_CONSUMER_HUNG_UP = 3,
+};
+
+// Sync state is RING_BUFFER_SYNC_PRODUCER_IDLE.
+void ring_buffer_sync_init(struct ring_buffer* r);
+
+// Tries to acquire the channel for sending.
+// Returns false if the consumer was in the middle of hanging up,
+// true if the producer successfully acquired the channel
+// (put it in the RING_BUFFER_SYNC_PRODUCER_ACTIVE state).
+bool ring_buffer_producer_acquire(struct ring_buffer* r);
+// Same as above, but acquires from RING_BUFFER_SYNC_CONSUMER_HUNG_UP.
+bool ring_buffer_producer_acquire_from_hangup(struct ring_buffer* r);
+// Waits until the consumer hangs up.
+void ring_buffer_producer_wait_hangup(struct ring_buffer* r);
+// Sets the state back to RING_BUFFER_SYNC_PRODUCER_IDLE.
+void ring_buffer_producer_idle(struct ring_buffer* r);
+
+// There is no symmetric consumer acquire because the consumer can consume with
+// the ring buffer being in any state (albeit with long waiting if the producer
+// does not send anything)
+
+// Tries to acquire the channel on the consumer side for
+// hanging up. Returns false if the producer is in the middle of sending,
+// true if the consumer successfully hung up the channel
+// (put it in the RING_BUFFER_SYNC_CONSUMER_HUNG_UP state).
+bool ring_buffer_consumer_hangup(struct ring_buffer* r);
+// Waits until the producer has set the state to
+// RING_BUFFER_SYNC_PRODUCER_IDLE.
+void ring_buffer_consumer_wait_producer_idle(struct ring_buffer* r);
+// Sets the state to hung up.
+void ring_buffer_consumer_hung_up(struct ring_buffer* r);
+
+// Convenient function to reschedule thread
+void ring_buffer_yield();
+ANDROID_END_HEADER
diff --git a/host/include/libOpenglRender/IOStream.h b/host/include/libOpenglRender/IOStream.h
index ad82072..2f699bc 100644
--- a/host/include/libOpenglRender/IOStream.h
+++ b/host/include/libOpenglRender/IOStream.h
@@ -25,11 +25,15 @@
 public:
 
     IOStream(size_t bufSize) {
-        m_buf = NULL;
+        m_iostreamBuf = NULL;
         m_bufsize = bufSize;
         m_free = 0;
     }
 
+    virtual size_t idealAllocSize(size_t len) {
+        return m_bufsize < len ? len : m_bufsize;
+    }
+
     virtual void *allocBuffer(size_t minSize) = 0;
     virtual int commitBuffer(size_t size) = 0;
     virtual const unsigned char *readFully( void *buf, size_t len) = 0;
@@ -39,22 +43,22 @@
 
     virtual ~IOStream() {
 
-        // NOTE: m_buf is 'owned' by the child class thus we expect it to be released by it
+        // NOTE: m_iostreamBuf is 'owned' by the child class thus we expect it to be released by it
     }
 
     virtual unsigned char *alloc(size_t len) {
 
-        if (m_buf && len > m_free) {
+        if (m_iostreamBuf && len > m_free) {
             if (flush() < 0) {
                 ERR("Failed to flush in alloc\n");
                 return NULL; // we failed to flush so something is wrong
             }
         }
 
-        if (!m_buf || len > m_bufsize) {
-            int allocLen = m_bufsize < len ? len : m_bufsize;
-            m_buf = (unsigned char *)allocBuffer(allocLen);
-            if (!m_buf) {
+        if (!m_iostreamBuf || len > m_bufsize) {
+            int allocLen = this->idealAllocSize(len);
+            m_iostreamBuf = (unsigned char *)allocBuffer(allocLen);
+            if (!m_iostreamBuf) {
                 ERR("Alloc (%u bytes) failed\n", allocLen);
                 return NULL;
             }
@@ -63,7 +67,7 @@
 
         unsigned char *ptr;
 
-        ptr = m_buf + (m_bufsize - m_free);
+        ptr = m_iostreamBuf + (m_bufsize - m_free);
         m_free -= len;
 
         return ptr;
@@ -71,18 +75,18 @@
 
     virtual int flush() {
 
-        if (!m_buf || m_free == m_bufsize) return 0;
+        if (!m_iostreamBuf || m_free == m_bufsize) return 0;
 
         int stat = commitBuffer(m_bufsize - m_free);
-        m_buf = NULL;
+        m_iostreamBuf = NULL;
         m_free = 0;
         return stat;
     }
 
     const unsigned char *readback(void *buf, size_t len) {
-        if (m_buf && m_free != m_bufsize) {
+        if (m_iostreamBuf && m_free != m_bufsize) {
             size_t size = m_bufsize - m_free;
-            m_buf = NULL;
+            m_iostreamBuf = NULL;
             m_free = 0;
             return commitBufferAndReadFully(size, buf, len);
         }
@@ -93,7 +97,7 @@
 
 
 private:
-    unsigned char *m_buf;
+    unsigned char *m_iostreamBuf;
     size_t m_bufsize;
     size_t m_free;
 };
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.h b/shared/OpenglCodecCommon/goldfish_address_space.h
index 6b2576d..f02fa2e 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space.h
+++ b/shared/OpenglCodecCommon/goldfish_address_space.h
@@ -45,13 +45,9 @@
 
 class GoldfishAddressSpaceBlockProvider {
 public:
-#ifdef __Fuchsia__
-    GoldfishAddressSpaceBlockProvider();
-#else
     static const uint64_t SUBDEVICE_TYPE_NO_SUBDEVICE_ID = -1;
     static const uint64_t SUBDEVICE_TYPE_HOST_MEMORY_ALLOCATOR_ID = 5;
     GoldfishAddressSpaceBlockProvider(uint64_t subdevice);
-#endif  // __Fuchsia__
     ~GoldfishAddressSpaceBlockProvider();
 
 private:
@@ -61,6 +57,7 @@
     bool is_opened() const;
     void close();
     address_space_handle_t release();
+    static void closeHandle(address_space_handle_t handle);
 
 #ifdef __Fuchsia__
     fuchsia::hardware::goldfish::address::space::DeviceSyncPtr m_device;
@@ -86,6 +83,8 @@
     void *guestPtr() const;
     void replace(GoldfishAddressSpaceBlock *other);
     void release();
+    static int memoryMap(void *addr, size_t len, address_space_handle_t fd, uint64_t off, void** dst);
+    static void memoryUnmap(void *ptr, size_t size);
 
 private:
     void destroy();
@@ -114,6 +113,7 @@
 
     bool is_opened() const;
     address_space_handle_t release() { return m_provider.release(); }
+    static void closeHandle(address_space_handle_t handle) { GoldfishAddressSpaceBlockProvider::closeHandle(handle); }
 
 private:
     GoldfishAddressSpaceBlockProvider m_provider;
diff --git a/shared/OpenglCodecCommon/goldfish_address_space_android.impl b/shared/OpenglCodecCommon/goldfish_address_space_android.impl
index f0abf04..90fc097 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space_android.impl
+++ b/shared/OpenglCodecCommon/goldfish_address_space_android.impl
@@ -97,7 +97,7 @@
 GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(uint64_t subdevice)
   : m_handle(create_address_space_fd())
 {
-    if ((subdevice != SUBDEVICE_TYPE_HOST_MEMORY_ALLOCATOR_ID) && is_opened()) {
+    if ((subdevice != SUBDEVICE_TYPE_NO_SUBDEVICE_ID) && is_opened()) {
         const long ret = set_address_space_subdevice_type(m_handle, subdevice);
         if (ret) {
             ALOGE("%s: set_address_space_subdevice_type failed for device_type=%lu, ret=%ld",
@@ -134,6 +134,11 @@
     return handle;
 }
 
+void GoldfishAddressSpaceBlockProvider::closeHandle(address_space_handle_t handle)
+{
+    ::close(handle);
+}
+
 GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
     : m_handle(-1)
     , m_mmaped_ptr(NULL)
@@ -212,13 +217,14 @@
         ::abort();
     }
 
-    void *result = ::mmap64(NULL, m_size, PROT_WRITE, MAP_SHARED, m_handle, m_offset);
-    if (result == MAP_FAILED) {
+    void *result;
+    const int res = memoryMap(NULL, m_size, m_handle, m_offset, &result);
+    if (res) {
         ALOGE("%s: host memory map failed with size 0x%llx "
               "off 0x%llx errno %d\n",
               __func__,
               (unsigned long long)m_size,
-              (unsigned long long)m_offset, errno);
+              (unsigned long long)m_offset, res);
         return NULL;
     } else {
         m_mmaped_ptr = result;
@@ -235,7 +241,7 @@
 void GoldfishAddressSpaceBlock::destroy()
 {
     if (m_mmaped_ptr && m_size) {
-        ::munmap(m_mmaped_ptr, m_size);
+        memoryUnmap(m_mmaped_ptr, m_size);
         m_mmaped_ptr = NULL;
     }
 
@@ -263,6 +269,25 @@
     m_size = 0;
 }
 
+int GoldfishAddressSpaceBlock::memoryMap(void *addr,
+                                         size_t len,
+                                         address_space_handle_t fd,
+                                         uint64_t off,
+                                         void** dst) {
+    void* ptr = ::mmap64(addr, len, PROT_WRITE, MAP_SHARED, fd, off);
+    if (MAP_FAILED == ptr) {
+        return errno;
+    } else {
+        *dst = ptr;
+        return 0;
+    }
+}
+
+void GoldfishAddressSpaceBlock::memoryUnmap(void *ptr, size_t size)
+{
+    ::munmap(ptr, size);
+}
+
 GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
   : m_provider(GoldfishAddressSpaceBlockProvider::SUBDEVICE_TYPE_HOST_MEMORY_ALLOCATOR_ID) {}
 
diff --git a/shared/OpenglCodecCommon/goldfish_address_space_fuchsia.impl b/shared/OpenglCodecCommon/goldfish_address_space_fuchsia.impl
index 711dfa4..d11fcd1 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space_fuchsia.impl
+++ b/shared/OpenglCodecCommon/goldfish_address_space_fuchsia.impl
@@ -29,7 +29,13 @@
 
 #include "goldfish_address_space.h"
 
-GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider() {
+GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(uint64_t subdevice) {
+
+    if (subdevice != SUBDEVICE_TYPE_NO_SUBDEVICE_ID) {
+        ALOGE("%s: Tried to use a nontrivial subdevice when support has not been added\n", __func__);
+        abort();
+    }
+
     zx::channel channel;
     zx_status_t status =
         fdio_get_service_handle(::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR),
@@ -187,6 +193,7 @@
 }
 
 GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
+  : m_provider(GoldfishAddressSpaceBlockProvider::SUBDEVICE_TYPE_HOST_MEMORY_ALLOCATOR_ID)
 {
 }
 
diff --git a/shared/OpenglCodecCommon/goldfish_address_space_host.impl b/shared/OpenglCodecCommon/goldfish_address_space_host.impl
index 99e1b0c..7d07d8b 100644
--- a/shared/OpenglCodecCommon/goldfish_address_space_host.impl
+++ b/shared/OpenglCodecCommon/goldfish_address_space_host.impl
@@ -37,7 +37,7 @@
 GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(uint64_t subdevice)
     : m_handle(HostAddressSpaceDevice::get()->open())
 {
-    if ((subdevice != SUBDEVICE_TYPE_HOST_MEMORY_ALLOCATOR_ID) && is_opened()) {
+    if ((subdevice != SUBDEVICE_TYPE_NO_SUBDEVICE_ID) && is_opened()) {
         AddressSpaceDevicePingInfo request;
         ::memset(&request, 0, sizeof(request));
         request.metadata = subdevice;
@@ -73,6 +73,11 @@
     return handle;
 }
 
+void GoldfishAddressSpaceBlockProvider::closeHandle(address_space_handle_t handle)
+{
+    HostAddressSpaceDevice::get()->close(handle);
+}
+
 GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
     : m_handle(0)
     , m_mmaped_ptr(NULL)
@@ -175,6 +180,17 @@
     m_size = 0;
 }
 
+int GoldfishAddressSpaceBlock::memoryMap(void *addr,
+                                         size_t,
+                                         address_space_handle_t,
+                                         uint64_t,
+                                         void** dst) {
+    *dst = addr;
+    return 0;
+}
+
+void GoldfishAddressSpaceBlock::memoryUnmap(void *ptr, size_t size) {}
+
 GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
   : m_provider(GoldfishAddressSpaceBlockProvider::SUBDEVICE_TYPE_HOST_MEMORY_ALLOCATOR_ID) {}
 
diff --git a/shared/OpenglCodecCommon/gralloc_cb.h b/shared/OpenglCodecCommon/gralloc_cb.h
index 2d80f26..3167ca0 100644
--- a/shared/OpenglCodecCommon/gralloc_cb.h
+++ b/shared/OpenglCodecCommon/gralloc_cb.h
@@ -17,7 +17,103 @@
 #ifndef __GRALLOC_CB_H__
 #define __GRALLOC_CB_H__
 
-#include "gralloc_cb_old.h"
-typedef cb_handle_old_t cb_handle_t;
+#include <cutils/native_handle.h>
+#include "qemu_pipe.h"
+
+const uint32_t CB_HANDLE_MAGIC_MASK = 0xFFFFFFF0;
+const uint32_t CB_HANDLE_MAGIC_BASE = 0xABFABFA0;
+
+#define CB_HANDLE_NUM_INTS(nfd) \
+    ((sizeof(*this)-sizeof(native_handle_t)-nfd*sizeof(int32_t))/sizeof(int32_t))
+
+struct cb_handle_t : public native_handle_t {
+    cb_handle_t(int32_t p_bufferFd,
+                QEMU_PIPE_HANDLE p_hostHandleRefCountFd,
+                uint32_t p_magic,
+                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)
+        : bufferFd(p_bufferFd),
+          hostHandleRefCountFd(p_hostHandleRefCountFd),
+          magic(p_magic),
+          hostHandle(p_hostHandle),
+          usage(p_usage),
+          width(p_width),
+          height(p_height),
+          format(p_format),
+          glFormat(p_glFormat),
+          glType(p_glType),
+          bufferSize(p_bufSize),
+          lockedLeft(0),
+          lockedTop(0),
+          lockedWidth(0),
+          lockedHeight(0) {
+        version = sizeof(native_handle);
+        numFds = ((bufferFd >= 0) ? 1 : 0) + (qemu_pipe_valid(hostHandleRefCountFd) ? 1 : 0);
+        numInts = 0; // has to be overwritten in children classes
+        setBufferPtr(p_bufPtr);
+    }
+
+    void* getBufferPtr() const {
+        const uint64_t addr = (uint64_t(bufferPtrHi) << 32) | bufferPtrLo;
+        return reinterpret_cast<void*>(static_cast<uintptr_t>(addr));
+    }
+
+    void setBufferPtr(void* ptr) {
+        const uint64_t addr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr));
+        bufferPtrLo = uint32_t(addr);
+        bufferPtrHi = uint32_t(addr >> 32);
+    }
+
+    uint32_t allocatedSize() const {
+        return getBufferPtr() ? bufferSize : 0;
+    }
+
+    bool isValid() const {
+        return (version == sizeof(native_handle))
+               && (magic & CB_HANDLE_MAGIC_MASK) == CB_HANDLE_MAGIC_BASE;
+    }
+
+    static cb_handle_t* from(void* p) {
+        if (!p) { return nullptr; }
+        cb_handle_t* cb = static_cast<cb_handle_t*>(p);
+        return cb->isValid() ? cb : nullptr;
+    }
+
+    static const cb_handle_t* from(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    static cb_handle_t* from_unconst(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    // fds
+    int32_t bufferFd;       // underlying buffer file handle
+    QEMU_PIPE_HANDLE hostHandleRefCountFd; // guest side refcounter to hostHandle
+
+    // ints
+    uint32_t magic;         // magic number in order to validate a pointer
+    uint32_t hostHandle;    // the host reference to this buffer
+    int32_t  usage;         // usage bits the buffer was created with
+    int32_t  width;         // buffer width
+    int32_t  height;        // buffer height
+    int32_t  format;        // real internal pixel format format
+    int32_t  glFormat;      // OpenGL format enum used for host h/w color buffer
+    int32_t  glType;        // OpenGL type enum used when uploading to host
+    uint32_t bufferSize;    // buffer size and location
+    uint32_t bufferPtrLo;
+    uint32_t bufferPtrHi;
+    int32_t  lockedLeft;    // region of buffer locked for s/w write
+    int32_t  lockedTop;
+    int32_t  lockedWidth;
+    int32_t  lockedHeight;
+};
 
 #endif //__GRALLOC_CB_H__
diff --git a/shared/OpenglCodecCommon/gralloc_cb_common.h b/shared/OpenglCodecCommon/gralloc_cb_common.h
deleted file mode 100644
index 94ada2f..0000000
--- a/shared/OpenglCodecCommon/gralloc_cb_common.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
-* 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 __GRALLOC_CB_COMMON_H__
-#define __GRALLOC_CB_COMMON_H__
-
-// Tell the emulator which gralloc formats
-// need special handling.
-enum EmulatorFrameworkFormat {
-    FRAMEWORK_FORMAT_GL_COMPATIBLE = 0,
-    FRAMEWORK_FORMAT_YV12 = 1,
-    FRAMEWORK_FORMAT_YUV_420_888 = 2,              // (Y+)(U+)(V+)
-};
-
-#endif //__GRALLOC_CB_COMMON_H__
diff --git a/shared/OpenglCodecCommon/gralloc_cb_old.h b/shared/OpenglCodecCommon/gralloc_cb_old.h
deleted file mode 100644
index ab01537..0000000
--- a/shared/OpenglCodecCommon/gralloc_cb_old.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
-* 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 __GRALLOC_CB_OLD_H__
-#define __GRALLOC_CB_OLD_H__
-
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
-#include <cutils/native_handle.h>
-
-#include "gralloc_cb_common.h"
-#include "qemu_pipe.h"
-
-#define BUFFER_HANDLE_MAGIC ((int)0xabfabfab)
-#define CB_HANDLE_NUM_INTS(nfds) (int)((sizeof(cb_handle_old_t) - (nfds)*sizeof(int)) / sizeof(int))
-
-//
-// Our buffer handle structure
-//
-struct cb_handle_old_t : public native_handle {
-
-    cb_handle_old_t(int p_fd, int p_ashmemSize, int p_usage,
-                    int p_width, int p_height,
-                    int p_format, int p_glFormat, int p_glType,
-                    EmulatorFrameworkFormat p_emuFrameworkFormat) :
-        fd(p_fd),
-        magic(BUFFER_HANDLE_MAGIC),
-        usage(p_usage),
-        width(p_width),
-        height(p_height),
-        format(p_format),
-        glFormat(p_glFormat),
-        glType(p_glType),
-        ashmemSize(p_ashmemSize),
-        ashmemBase(0),
-        ashmemBasePid(0),
-        mappedPid(0),
-        lockedLeft(0),
-        lockedTop(0),
-        lockedWidth(0),
-        lockedHeight(0),
-        hostHandle(0),
-        emuFrameworkFormat(p_emuFrameworkFormat)
-    {
-        refcount_pipe_fd = QEMU_PIPE_INVALID_HANDLE;
-        version = sizeof(native_handle);
-        numFds = 0;
-        numInts = CB_HANDLE_NUM_INTS(numFds);
-    }
-
-    ~cb_handle_old_t() {
-        magic = 0;
-    }
-
-    static cb_handle_old_t* from_native_handle(native_handle* n) {
-        return static_cast<cb_handle_old_t*>(n);
-    }
-
-    static const cb_handle_old_t* from_native_handle(const native_handle* n) {
-        return static_cast<const cb_handle_old_t*>(n);
-    }
-
-    static cb_handle_old_t* from_raw_pointer(void* ptr) {
-        return from_native_handle(static_cast<native_handle*>(ptr));
-    }
-
-    static const cb_handle_old_t* from_raw_pointer(const void* ptr) {
-        return from_native_handle(static_cast<const native_handle*>(ptr));
-    }
-
-    void setFd(int p_fd) {
-        if (p_fd >= 0) {
-            numFds++;
-        }
-        fd = p_fd;
-        numInts = CB_HANDLE_NUM_INTS(numFds);
-    }
-
-    bool hasRefcountPipe() {
-        return qemu_pipe_valid(refcount_pipe_fd);
-    }
-
-    void setRefcountPipeFd(QEMU_PIPE_HANDLE fd) {
-        if (qemu_pipe_valid(fd)) {
-            numFds++;
-        }
-        refcount_pipe_fd = fd;
-        numInts = CB_HANDLE_NUM_INTS(numFds);
-    }
-
-    static bool validate(const cb_handle_old_t* hnd) {
-        return (hnd &&
-                hnd->version == sizeof(native_handle) &&
-                hnd->magic == BUFFER_HANDLE_MAGIC &&
-                hnd->numInts == CB_HANDLE_NUM_INTS(hnd->numFds));
-    }
-
-    bool canBePosted() {
-        return (0 != (usage & GRALLOC_USAGE_HW_FB));
-    }
-
-    uint32_t allocationSize() const {
-        return ashmemBase ? ashmemSize : 0;
-    }
-
-    // file-descriptors
-    int fd;  // ashmem fd (-1 of ashmem region did not allocated, i.e. no SW access needed)
-    QEMU_PIPE_HANDLE refcount_pipe_fd; // goldfish pipe service for gralloc refcounting fd.
-
-    // ints
-    int magic;              // magic number in order to validate a pointer to be a cb_handle_old_t
-    int usage;              // usage bits the buffer was created with
-    int width;              // buffer width
-    int height;             // buffer height
-    int format;             // real internal pixel format format
-    int glFormat;           // OpenGL format enum used for host h/w color buffer
-    int glType;             // OpenGL type enum used when uploading to host
-    int ashmemSize;         // ashmem region size for the buffer (0 unless is HW_FB buffer or
-                            //                                    s/w access is needed)
-    union {
-        intptr_t ashmemBase;    // CPU address of the mapped ashmem region
-        uint64_t padding;       // enforce same size on 32-bit/64-bit
-    } __attribute__((aligned(8)));
-
-    int ashmemBasePid;      // process id which mapped the ashmem region
-    int mappedPid;          // process id which succeeded gralloc_register call
-    int lockedLeft;         // region of buffer locked for s/w write
-    int lockedTop;
-    int lockedWidth;
-    int lockedHeight;
-    uint32_t hostHandle;
-
-    EmulatorFrameworkFormat emuFrameworkFormat;
-};
-
-
-#endif //__GRALLOC_CB_OLD_H__
diff --git a/system/GLESv2_enc/GL2Encoder.cpp b/system/GLESv2_enc/GL2Encoder.cpp
index 208173e..2f20516 100755
--- a/system/GLESv2_enc/GL2Encoder.cpp
+++ b/system/GLESv2_enc/GL2Encoder.cpp
@@ -72,6 +72,7 @@
 {
     m_currMajorVersion = 2;
     m_currMinorVersion = 0;
+    m_hasAsyncUnmapBuffer = false;
     m_initialized = false;
     m_noHostError = false;
     m_state = NULL;
@@ -101,6 +102,7 @@
     m_ssbo_offset_align = 0;
     m_ubo_offset_align = 0;
 
+    m_drawCallFlushInterval = 800;
     m_drawCallFlushCount = 0;
     m_primitiveRestartEnabled = false;
     m_primitiveRestartIndex = 0;
@@ -1302,11 +1304,7 @@
 }
 
 void GL2Encoder::flushDrawCall() {
-    // This used to be every other draw call, but
-    // now that we are using real GPU buffers on host,
-    // set this to every 200 draw calls
-    // (tuned on z840 linux NVIDIA Quadro K2200)
-    if (m_drawCallFlushCount % 200 == 0) {
+    if (m_drawCallFlushCount % m_drawCallFlushInterval == 0) {
         m_stream->flush();
     }
     m_drawCallFlushCount++;
@@ -1463,6 +1461,7 @@
         ctx->sendVertexAttributes(0, count, false);
         ctx->m_glDrawArraysNullAEMU_enc(ctx, mode, first, count);
     }
+    ctx->flushDrawCall();
 }
 
 void GL2Encoder::s_glDrawElementsNullAEMU(void *self, GLenum mode, GLsizei count, GLenum type, const void *indices)
@@ -2955,11 +2954,16 @@
                                              GLbitfield access, BufferData* buf) {
     char* bits = (char*)buf->m_fixedBuffer.ptr() + offset;
 
-    ctx->glMapBufferRangeAEMU(
-            ctx, target,
-            offset, length,
-            access,
-            bits);
+    if ((access & GL_MAP_READ_BIT) ||
+        ((access & GL_MAP_WRITE_BIT) &&
+        (!(access & GL_MAP_INVALIDATE_RANGE_BIT) &&
+         !(access & GL_MAP_INVALIDATE_BUFFER_BIT)))) {
+        ctx->glMapBufferRangeAEMU(
+                ctx, target,
+                offset, length,
+                access,
+                bits);
+    }
 
     return bits;
 }
@@ -3071,13 +3075,25 @@
             goldfish_dma_guest_paddr(&buf->dma_buffer.get()),
             &host_res);
     } else {
-        ctx->glUnmapBufferAEMU(
-                ctx, target,
-                buf->m_mappedOffset,
-                buf->m_mappedLength,
-                buf->m_mappedAccess,
-                (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
-                &host_res);
+        if (ctx->m_hasAsyncUnmapBuffer) {
+            ctx->glUnmapBufferAsyncAEMU(
+                    ctx, target,
+                    buf->m_mappedOffset,
+                    buf->m_mappedLength,
+                    buf->m_mappedAccess,
+                    (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
+                    &host_res);
+        } else {
+            if (buf->m_mappedAccess & GL_MAP_WRITE_BIT) {
+                ctx->glUnmapBufferAEMU(
+                        ctx, target,
+                        buf->m_mappedOffset,
+                        buf->m_mappedLength,
+                        buf->m_mappedAccess,
+                        (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
+                        &host_res);
+            }
+        }
     }
 
     buf->m_mapped = false;
@@ -3109,12 +3125,21 @@
 
     buf->m_indexRangeCache.invalidateRange(totalOffset, length);
 
-    ctx->glFlushMappedBufferRangeAEMU(
-            ctx, target,
-            totalOffset,
-            length,
-            buf->m_mappedAccess,
-            (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    if (ctx->m_hasAsyncUnmapBuffer) {
+        ctx->glFlushMappedBufferRangeAEMU2(
+                ctx, target,
+                totalOffset,
+                length,
+                buf->m_mappedAccess,
+                (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    } else {
+        ctx->glFlushMappedBufferRangeAEMU(
+                ctx, target,
+                totalOffset,
+                length,
+                buf->m_mappedAccess,
+                (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    }
 }
 
 void GL2Encoder::s_glCompressedTexImage2D(void* self, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {
diff --git a/system/GLESv2_enc/GL2Encoder.h b/system/GLESv2_enc/GL2Encoder.h
index c617a36..d016898 100644
--- a/system/GLESv2_enc/GL2Encoder.h
+++ b/system/GLESv2_enc/GL2Encoder.h
@@ -28,6 +28,12 @@
 public:
     GL2Encoder(IOStream *stream, ChecksumCalculator* protocol);
     virtual ~GL2Encoder();
+    void setDrawCallFlushInterval(uint32_t interval) {
+        m_drawCallFlushInterval = interval;
+    }
+    void setHasAsyncUnmapBuffer(int version) {
+        m_hasAsyncUnmapBuffer = version;
+    }
     void setNoHostError(bool noHostError) {
         m_noHostError = noHostError;
     }
@@ -98,6 +104,7 @@
     std::string m_currExtensions;
     std::vector<std::string> m_currExtensionsArray;
 
+    bool    m_hasAsyncUnmapBuffer;
     bool    m_initialized;
     bool    m_noHostError;
     GLClientState *m_state;
@@ -131,7 +138,8 @@
 
     FixedBuffer m_fixedBuffer;
 
-    int m_drawCallFlushCount;
+    uint32_t m_drawCallFlushInterval;
+    uint32_t m_drawCallFlushCount;
 
     bool m_primitiveRestartEnabled;
     GLuint m_primitiveRestartIndex;
diff --git a/system/GLESv2_enc/gl2_client_context.cpp b/system/GLESv2_enc/gl2_client_context.cpp
index c811b66..aaa0325 100644
--- a/system/GLESv2_enc/gl2_client_context.cpp
+++ b/system/GLESv2_enc/gl2_client_context.cpp
@@ -434,6 +434,8 @@
 	glDrawElementsNullAEMU = (glDrawElementsNullAEMU_client_proc_t) getProc("glDrawElementsNullAEMU", userData);
 	glDrawElementsOffsetNullAEMU = (glDrawElementsOffsetNullAEMU_client_proc_t) getProc("glDrawElementsOffsetNullAEMU", userData);
 	glDrawElementsDataNullAEMU = (glDrawElementsDataNullAEMU_client_proc_t) getProc("glDrawElementsDataNullAEMU", userData);
+	glUnmapBufferAsyncAEMU = (glUnmapBufferAsyncAEMU_client_proc_t) getProc("glUnmapBufferAsyncAEMU", userData);
+	glFlushMappedBufferRangeAEMU2 = (glFlushMappedBufferRangeAEMU2_client_proc_t) getProc("glFlushMappedBufferRangeAEMU2", userData);
 	return 0;
 }
 
diff --git a/system/GLESv2_enc/gl2_client_context.h b/system/GLESv2_enc/gl2_client_context.h
index ce0cf47..575395a 100644
--- a/system/GLESv2_enc/gl2_client_context.h
+++ b/system/GLESv2_enc/gl2_client_context.h
@@ -434,6 +434,8 @@
 	glDrawElementsNullAEMU_client_proc_t glDrawElementsNullAEMU;
 	glDrawElementsOffsetNullAEMU_client_proc_t glDrawElementsOffsetNullAEMU;
 	glDrawElementsDataNullAEMU_client_proc_t glDrawElementsDataNullAEMU;
+	glUnmapBufferAsyncAEMU_client_proc_t glUnmapBufferAsyncAEMU;
+	glFlushMappedBufferRangeAEMU2_client_proc_t glFlushMappedBufferRangeAEMU2;
 	virtual ~gl2_client_context_t() {}
 
 	typedef gl2_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
diff --git a/system/GLESv2_enc/gl2_client_proc.h b/system/GLESv2_enc/gl2_client_proc.h
index dea6d12..615b123 100644
--- a/system/GLESv2_enc/gl2_client_proc.h
+++ b/system/GLESv2_enc/gl2_client_proc.h
@@ -436,6 +436,8 @@
 typedef void (gl2_APIENTRY *glDrawElementsNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, const GLvoid*);
 typedef void (gl2_APIENTRY *glDrawElementsOffsetNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, GLuint);
 typedef void (gl2_APIENTRY *glDrawElementsDataNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, void*, GLuint);
+typedef void (gl2_APIENTRY *glUnmapBufferAsyncAEMU_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, void*, GLboolean*);
+typedef void (gl2_APIENTRY *glFlushMappedBufferRangeAEMU2_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, void*);
 
 
 #endif
diff --git a/system/GLESv2_enc/gl2_enc.cpp b/system/GLESv2_enc/gl2_enc.cpp
index 17b3cba..0df93f8 100644
--- a/system/GLESv2_enc/gl2_enc.cpp
+++ b/system/GLESv2_enc/gl2_enc.cpp
@@ -11482,6 +11482,87 @@
 
 }
 
+void glUnmapBufferAsyncAEMU_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res)
+{
+
+	gl2_encoder_context_t *ctx = (gl2_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_guest_buffer = ((guest_buffer != NULL) ?  length : 0);
+	const unsigned int __size_out_res =  (sizeof(GLboolean));
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + __size_guest_buffer + __size_out_res + 2*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(8 + 4 + 4 + 4 + 4);
+	ptr = buf;
+	int tmp = OP_glUnmapBufferAsyncAEMU;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &target, 4); ptr += 4;
+		memcpy(ptr, &offset, 4); ptr += 4;
+		memcpy(ptr, &length, 4); ptr += 4;
+		memcpy(ptr, &access, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	stream->flush();
+	stream->writeFully(&__size_guest_buffer,4);
+	if (useChecksum) checksumCalculator->addBuffer(&__size_guest_buffer,4);
+	if (guest_buffer != NULL) {
+		stream->writeFully(guest_buffer, __size_guest_buffer);
+		if (useChecksum) checksumCalculator->addBuffer(guest_buffer, __size_guest_buffer);
+	}
+	buf = stream->alloc(__size_out_res + 1*4);
+	ptr = buf;
+	*(unsigned int *)(ptr) = __size_out_res; ptr += 4;
+	memcpy(ptr, out_res, __size_out_res);ptr += __size_out_res;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	buf = stream->alloc(checksumSize);
+	if (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);
+
+}
+
+void glFlushMappedBufferRangeAEMU2_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer)
+{
+
+	gl2_encoder_context_t *ctx = (gl2_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_guest_buffer = ((guest_buffer != NULL) ?  length : 0);
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + __size_guest_buffer + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(8 + 4 + 4 + 4 + 4);
+	ptr = buf;
+	int tmp = OP_glFlushMappedBufferRangeAEMU2;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &target, 4); ptr += 4;
+		memcpy(ptr, &offset, 4); ptr += 4;
+		memcpy(ptr, &length, 4); ptr += 4;
+		memcpy(ptr, &access, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	stream->flush();
+	stream->writeFully(&__size_guest_buffer,4);
+	if (useChecksum) checksumCalculator->addBuffer(&__size_guest_buffer,4);
+	if (guest_buffer != NULL) {
+		stream->writeFully(guest_buffer, __size_guest_buffer);
+		if (useChecksum) checksumCalculator->addBuffer(guest_buffer, __size_guest_buffer);
+	}
+	buf = stream->alloc(checksumSize);
+	if (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);
+
+}
+
 }  // namespace
 
 gl2_encoder_context_t::gl2_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
@@ -11913,5 +11994,7 @@
 	this->glDrawElementsNullAEMU = (glDrawElementsNullAEMU_client_proc_t) &enc_unsupported;
 	this->glDrawElementsOffsetNullAEMU = &glDrawElementsOffsetNullAEMU_enc;
 	this->glDrawElementsDataNullAEMU = &glDrawElementsDataNullAEMU_enc;
+	this->glUnmapBufferAsyncAEMU = &glUnmapBufferAsyncAEMU_enc;
+	this->glFlushMappedBufferRangeAEMU2 = &glFlushMappedBufferRangeAEMU2_enc;
 }
 
diff --git a/system/GLESv2_enc/gl2_entry.cpp b/system/GLESv2_enc/gl2_entry.cpp
index 69ce39d..a5d6c87 100644
--- a/system/GLESv2_enc/gl2_entry.cpp
+++ b/system/GLESv2_enc/gl2_entry.cpp
@@ -429,6 +429,8 @@
 	void glDrawElementsNullAEMU(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
 	void glDrawElementsOffsetNullAEMU(GLenum mode, GLsizei count, GLenum type, GLuint offset);
 	void glDrawElementsDataNullAEMU(GLenum mode, GLsizei count, GLenum type, void* data, GLuint datalen);
+	void glUnmapBufferAsyncAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res);
+	void glFlushMappedBufferRangeAEMU2(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer);
 };
 
 #ifndef GET_CONTEXT
@@ -3018,3 +3020,15 @@
 	ctx->glDrawElementsDataNullAEMU(ctx, mode, count, type, data, datalen);
 }
 
+void glUnmapBufferAsyncAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res)
+{
+	GET_CONTEXT;
+	ctx->glUnmapBufferAsyncAEMU(ctx, target, offset, length, access, guest_buffer, out_res);
+}
+
+void glFlushMappedBufferRangeAEMU2(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer)
+{
+	GET_CONTEXT;
+	ctx->glFlushMappedBufferRangeAEMU2(ctx, target, offset, length, access, guest_buffer);
+}
+
diff --git a/system/GLESv2_enc/gl2_opcodes.h b/system/GLESv2_enc/gl2_opcodes.h
index 7628a2e..9c619e1 100644
--- a/system/GLESv2_enc/gl2_opcodes.h
+++ b/system/GLESv2_enc/gl2_opcodes.h
@@ -427,7 +427,9 @@
 #define OP_glDrawElementsNullAEMU 					2469
 #define OP_glDrawElementsOffsetNullAEMU 					2470
 #define OP_glDrawElementsDataNullAEMU 					2471
-#define OP_last 					2472
+#define OP_glUnmapBufferAsyncAEMU 					2472
+#define OP_glFlushMappedBufferRangeAEMU2 					2473
+#define OP_last 					2474
 
 
 #endif
diff --git a/system/OpenglSystemCommon/EmulatorFeatureInfo.h b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
index 422812c..9df134f 100644
--- a/system/OpenglSystemCommon/EmulatorFeatureInfo.h
+++ b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
@@ -87,12 +87,12 @@
 // Vulkan create resources with requirements
 static const char kVulkanCreateResourcesWithRequirements[] = "ANDROID_EMU_vulkan_create_resources_with_requirements";
 
-// YUV420_888 to NV21
-static const char kYUV420888toNV21[] = "ANDROID_EMU_YUV420_888_to_NV21";
-
 // YUV host cache
 static const char kYUVCache[] = "ANDROID_EMU_YUV_Cache";
 
+// GL protocol v2
+static const char kAsyncUnmapBuffer[] = "ANDROID_EMU_async_unmap_buffer";
+
 // Struct describing available emulator features
 struct EmulatorFeatureInfo {
 
@@ -106,8 +106,8 @@
         hasDeferredVulkanCommands(false),
         hasVulkanNullOptionalStrings(false),
         hasVulkanCreateResourcesWithRequirements(false),
-        hasYUV420888toNV21(false),
-        hasYUVCache (false) { }
+        hasYUVCache (false),
+        hasAsyncUnmapBuffer (false) { }
 
     SyncImpl syncImpl;
     DmaImpl dmaImpl;
@@ -118,8 +118,8 @@
     bool hasDeferredVulkanCommands;
     bool hasVulkanNullOptionalStrings;
     bool hasVulkanCreateResourcesWithRequirements;
-    bool hasYUV420888toNV21;
     bool hasYUVCache;
+    bool hasAsyncUnmapBuffer;
 };
 
 #endif // __COMMON_EMULATOR_FEATURE_INFO_H
diff --git a/system/OpenglSystemCommon/FormatConversions.cpp b/system/OpenglSystemCommon/FormatConversions.cpp
index 83aff9c..ca4286c 100644
--- a/system/OpenglSystemCommon/FormatConversions.cpp
+++ b/system/OpenglSystemCommon/FormatConversions.cpp
@@ -68,9 +68,9 @@
                                 uint32_t* totalSz_out) {
     uint32_t align = 1;
     uint32_t yStride = (width + (align - 1)) & ~(align-1);
-    uint32_t uvStride = yStride;
+    uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1);
     uint32_t uvHeight = height / 2;
-    uint32_t sz = yStride * height + uvHeight * uvStride;
+    uint32_t sz = yStride * height + 2 * (uvHeight * uvStride);
 
     if (yStride_out) *yStride_out = yStride;
     if (cStride_out) *cStride_out = uvStride;
@@ -229,42 +229,6 @@
     }
 }
 
-//HAL_PIXEL_FORMAT_YCbCr_420_888, or yuv420p is treated as NV21 across our
-//gralloc and camera module when feature YUV420888toNV21 enabled
-void rgb888_to_nv21(char* dest, char* src, int width, int height,
-                    int left, int top, int right, int bottom) {
-    const int rgb_stride = 3;
-
-    DD("%s convert %d by %d", __func__, width, height);
-    int yStride = width;
-    int cStride = yStride;
-
-    uint8_t *rgb_ptr0 = (uint8_t *)src;
-    uint8_t *nv21_y0 = (uint8_t *)dest;
-    uint8_t *nv21_v0 = nv21_y0 + yStride * height;
-
-    for (int j = top; j <= bottom; ++j) {
-        uint8_t *nv21_y = nv21_y0 + j * yStride;
-        uint8_t *nv21_v = nv21_v0 + (j/2) * cStride;
-        uint8_t *nv21_u = nv21_v + 1;
-        uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride);
-        bool jeven = (j & 1) == 0;
-        for (int i = left; i <= right; ++i) {
-            uint8_t R = rgb_ptr[i*rgb_stride];
-            uint8_t G = rgb_ptr[i*rgb_stride+1];
-            uint8_t B = rgb_ptr[i*rgb_stride+2];
-            // convert to YV12
-            // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
-            nv21_y[i] = clamp_rgb((77 * R + 150 * G +  29 * B) >> 8);
-            bool ieven = (i & 1) == 0;
-            if (jeven && ieven) {
-                nv21_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
-                nv21_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
-            }
-        }
-    }
-}
-
 // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
 // certain stride requirements for Y and UV respectively.
 void yv12_to_rgb565(char* dest, char* src, int width, int height,
@@ -350,6 +314,8 @@
     }
 }
 
+// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
+// certain stride requirements for Y and UV respectively.
 void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
         int left, int top, int right, int bottom) {
     const int rgb_stride = 3;
@@ -392,49 +358,6 @@
     }
 }
 
-//HAL_PIXEL_FORMAT_YCbCr_420_888, or yuv420p is treated as NV21 across our
-//gralloc and camera module when feature YUV420888toNV21 enabled
-void nv21_to_rgb888(char* dest, char* src, int width, int height,
-                    int left, int top, int right, int bottom) {
-    const int rgb_stride = 3;
-
-    DD("%s convert %d by %d", __func__, width, height);
-    int yStride = width;
-    int cStride = yStride;
-
-    uint8_t *rgb_ptr0 = (uint8_t *)dest;
-    uint8_t *nv21_y0 = (uint8_t *)src;
-    uint8_t *nv21_v0 = nv21_y0 + yStride * height;
-
-    for (int j = top; j <= bottom; ++j) {
-        uint8_t *nv21_y = nv21_y0 + j * yStride;
-        uint8_t *nv21_v = nv21_v0 + (j/2) * cStride;
-        uint8_t *nv21_u = nv21_v + 1;
-        uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j - top, right - left + 1, rgb_stride);
-        for (int i = left; i <= right; ++i) {
-            // convert to rgb
-            // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
-            signed y1 = (signed)nv21_y[i] - 16;
-            signed u = (signed)nv21_u[i / 2] - 128;
-            signed v = (signed)nv21_v[i / 2] - 128;
-
-            signed u_b = u * 517;
-            signed u_g = -u * 100;
-            signed v_g = -v * 208;
-            signed v_r = v * 409;
-
-            signed tmp1 = y1 * 298;
-            signed b1 = clamp_rgb((tmp1 + u_b) / 256);
-            signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
-            signed r1 = clamp_rgb((tmp1 + v_r) / 256);
-
-            rgb_ptr[(i-left)*rgb_stride] = r1;
-            rgb_ptr[(i-left)*rgb_stride+1] = g1;
-            rgb_ptr[(i-left)*rgb_stride+2] = b1;
-        }
-    }
-}
-
 void copy_rgb_buffer_from_unlocked(
         char* dst, const char* raw_data,
         int unlockedWidth,
diff --git a/system/OpenglSystemCommon/FormatConversions.h b/system/OpenglSystemCommon/FormatConversions.h
index 2a8da2b..f9d7806 100644
--- a/system/OpenglSystemCommon/FormatConversions.h
+++ b/system/OpenglSystemCommon/FormatConversions.h
@@ -35,16 +35,12 @@
                     int left, int top, int right, int bottom);
 void rgb888_to_yuv420p(char* dest, char* src, int width, int height,
                        int left, int top, int right, int bottom);
-void rgb888_to_nv21(char* dest, char* src, int width, int height,
-                    int left, int top, int right, int bottom);
 void yv12_to_rgb565(char* dest, char* src, int width, int height,
                     int left, int top, int right, int bottom);
 void yv12_to_rgb888(char* dest, char* src, int width, int height,
                     int left, int top, int right, int bottom);
 void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
                        int left, int top, int right, int bottom);
-void nv21_to_rgb888(char* dest, char* src, int width, int height,
-                    int left, int top, int right, int bottom);
 void copy_rgb_buffer_from_unlocked(char* _dst, const char* raw_data,
                                    int unlockedWidth,
                                    int width, int height, int top, int left,
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index 9708829..2cd1d38 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -15,6 +15,8 @@
 */
 #include "HostConnection.h"
 
+#include "cutils/properties.h"
+
 #ifdef GOLDFISH_NO_GL
 struct gl_client_context_t {
     int placeholder;
@@ -32,6 +34,8 @@
     GL2Encoder(IOStream*, ChecksumCalculator*) { }
     void setContextAccessor(gl2_client_context_t *()) { }
     void setNoHostError(bool) { }
+    void setDrawCallFlushInterval(uint32_t) { }
+    void setHasAsyncUnmapBuffer(int) { }
 };
 #else
 #include "GLEncoder.h"
@@ -73,23 +77,47 @@
 #define STREAM_BUFFER_SIZE  (4*1024*1024)
 #define STREAM_PORT_NUM     22468
 
-enum HostConnectionType {
-    HOST_CONNECTION_TCP = 0,
-    HOST_CONNECTION_QEMU_PIPE = 1,
-    HOST_CONNECTION_VIRTIO_GPU = 2,
-};
+static HostConnectionType getConnectionTypeFromProperty() {
+    char transportValue[PROPERTY_VALUE_MAX] = "";
+    property_get("ro.kernel.qemu.gltransport", transportValue, "");
+
+    bool isValid = transportValue[0] != '\0';
+    if (!isValid) return HOST_CONNECTION_QEMU_PIPE;
+
+    if (!strcmp("tcp", transportValue)) return HOST_CONNECTION_TCP;
+    if (!strcmp("pipe", transportValue)) return HOST_CONNECTION_QEMU_PIPE;
+    if (!strcmp("virtio-gpu", transportValue)) return HOST_CONNECTION_VIRTIO_GPU;
+    if (!strcmp("asg", transportValue)) return HOST_CONNECTION_ADDRESS_SPACE;
+
+    return HOST_CONNECTION_QEMU_PIPE;
+}
+
+static uint32_t getDrawCallFlushIntervalFromProperty() {
+    char flushValue[PROPERTY_VALUE_MAX] = "";
+    property_get("ro.kernel.qemu.gltransport.drawFlushInterval", flushValue, "");
+
+    bool isValid = flushValue[0] != '\0';
+    if (!isValid) return 800;
+
+    long interval = strtol(flushValue, 0, 10);
+
+    if (!interval) return 800;
+
+    return (uint32_t)interval;
+}
+
 
 class GoldfishGralloc : public Gralloc
 {
 public:
     uint32_t getHostHandle(native_handle_t const* handle)
     {
-        return cb_handle_t::from_native_handle(handle)->hostHandle;
+        return cb_handle_t::from(handle)->hostHandle;
     }
 
     int getFormat(native_handle_t const* handle)
     {
-        return cb_handle_t::from_native_handle(handle)->format;
+        return cb_handle_t::from(handle)->format;
     }
 };
 
@@ -114,9 +142,7 @@
     m_checksumHelper(),
     m_glExtensions(),
     m_grallocOnly(true),
-    m_noHostError(false)
-{
-}
+    m_noHostError(false) { }
 
 HostConnection::~HostConnection()
 {
@@ -135,10 +161,12 @@
 HostConnection* HostConnection::connect(HostConnection* con) {
     if (!con) return con;
 
-    const enum HostConnectionType connType = HOST_CONNECTION_VIRTIO_GPU;
+    const enum HostConnectionType connType = getConnectionTypeFromProperty();
 
     switch (connType) {
         default:
+        case HOST_CONNECTION_ADDRESS_SPACE: // Not implemented yet
+            ALOGE("Trying to use address space graphics device, not implemented yet\n");
         case HOST_CONNECTION_QEMU_PIPE: {
             QemuPipeStream *stream = new QemuPipeStream(STREAM_BUFFER_SIZE);
             if (!stream) {
@@ -152,12 +180,19 @@
                 delete con;
                 return NULL;
             }
+            con->m_connectionType = HOST_CONNECTION_QEMU_PIPE;
             con->m_stream = stream;
             con->m_grallocHelper = &m_goldfishGralloc;
             con->m_processPipe = &m_goldfishProcessPipe;
             break;
         }
         case HOST_CONNECTION_TCP: {
+#ifdef __Fuchsia__
+            ALOGE("Fuchsia doesn't support HOST_CONNECTION_TCP!!!\n");
+            delete con;
+            return NULL;
+            break;
+#else
             TcpStream *stream = new TcpStream(STREAM_BUFFER_SIZE);
             if (!stream) {
                 ALOGE("Failed to create TcpStream for host connection!!!\n");
@@ -171,10 +206,12 @@
                 delete con;
                 return NULL;
             }
+            con->m_connectionType = HOST_CONNECTION_TCP;
             con->m_stream = stream;
             con->m_grallocHelper = &m_goldfishGralloc;
             con->m_processPipe = &m_goldfishProcessPipe;
             break;
+#endif
         }
 #ifdef VIRTIO_GPU
         case HOST_CONNECTION_VIRTIO_GPU: {
@@ -190,6 +227,7 @@
                 delete con;
                 return NULL;
             }
+            con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU;
             con->m_stream = stream;
             con->m_grallocHelper = stream->getGralloc();
             con->m_processPipe = stream->getProcessPipe();
@@ -271,6 +309,9 @@
             m_gl2Enc, getCurrentThreadId());
         m_gl2Enc->setContextAccessor(s_getGL2Context);
         m_gl2Enc->setNoHostError(m_noHostError);
+        m_gl2Enc->setDrawCallFlushInterval(
+            getDrawCallFlushIntervalFromProperty());
+        m_gl2Enc->setHasAsyncUnmapBuffer(m_rcEnc->hasAsyncUnmapBuffer());
     }
     return m_gl2Enc;
 }
@@ -298,8 +339,8 @@
         queryAndSetDeferredVulkanCommandsSupport(m_rcEnc);
         queryAndSetVulkanNullOptionalStringsSupport(m_rcEnc);
         queryAndSetVulkanCreateResourcesWithRequirementsSupport(m_rcEnc);
-        queryAndSetYUV420888toNV21(m_rcEnc);
         queryAndSetYUVCache(m_rcEnc);
+        queryAndSetAsyncUnmapBuffer(m_rcEnc);
         if (m_processPipe) {
             m_processPipe->processPipeInit(m_rcEnc);
         }
@@ -474,16 +515,17 @@
     }
 }
 
-void HostConnection::queryAndSetYUV420888toNV21(ExtendedRCEncoderContext* rcEnc) {
-    std::string glExtensions = queryGLExtensions(rcEnc);
-    if (glExtensions.find(kYUV420888toNV21) != std::string::npos) {
-        rcEnc->featureInfo()->hasYUV420888toNV21 = true;
-    }
-}
-
 void HostConnection::queryAndSetYUVCache(ExtendedRCEncoderContext* rcEnc) {
     std::string glExtensions = queryGLExtensions(rcEnc);
     if (glExtensions.find(kYUVCache) != std::string::npos) {
         rcEnc->featureInfo()->hasYUVCache = true;
     }
 }
+
+void HostConnection::queryAndSetAsyncUnmapBuffer(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kAsyncUnmapBuffer) != std::string::npos) {
+        rcEnc->featureInfo()->hasAsyncUnmapBuffer = true;
+    }
+}
+
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index a6424ab..c7547ca 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -58,10 +58,10 @@
         return m_featureInfo.hostComposition == HOST_COMPOSITION_V1; }
     bool hasHostCompositionV2() const {
         return m_featureInfo.hostComposition == HOST_COMPOSITION_V2; }
-    bool hasYUV420toNV21() const {
-        return m_featureInfo.hasYUV420888toNV21; }
     bool hasYUVCache() const {
         return m_featureInfo.hasYUVCache; }
+    bool hasAsyncUnmapBuffer() const {
+        return m_featureInfo.hasAsyncUnmapBuffer; }
     DmaImpl getDmaVersion() const { return m_featureInfo.dmaImpl; }
     void bindDmaContext(struct goldfish_dma_context* cxt) { m_dmaCxt = cxt; }
     void bindDmaDirectly(void* dmaPtr, uint64_t dmaPhysAddr) {
@@ -127,6 +127,13 @@
 
 struct EGLThreadInfo;
 
+enum HostConnectionType {
+    HOST_CONNECTION_TCP = 0,
+    HOST_CONNECTION_QEMU_PIPE = 1,
+    HOST_CONNECTION_VIRTIO_GPU = 2,
+    HOST_CONNECTION_ADDRESS_SPACE = 3,
+};
+
 class HostConnection
 {
 public:
@@ -139,6 +146,10 @@
 
     ~HostConnection();
 
+    HostConnectionType connectionType() const {
+        return m_connectionType;
+    }
+
     GLEncoder *glEncoder();
     GL2Encoder *gl2Encoder();
     goldfish_vk::VkEncoder *vkEncoder();
@@ -191,10 +202,11 @@
     void queryAndSetDeferredVulkanCommandsSupport(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetVulkanNullOptionalStringsSupport(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetVulkanCreateResourcesWithRequirementsSupport(ExtendedRCEncoderContext *rcEnc);
-    void queryAndSetYUV420888toNV21(ExtendedRCEncoderContext *mrcEnc);
     void queryAndSetYUVCache(ExtendedRCEncoderContext *mrcEnc);
+    void queryAndSetAsyncUnmapBuffer(ExtendedRCEncoderContext *rcEnc);
 
 private:
+    HostConnectionType m_connectionType;
     IOStream *m_stream;
     GLEncoder   *m_glEnc;
     GL2Encoder  *m_gl2Enc;
diff --git a/system/gralloc/gralloc_common.h b/system/gralloc/gralloc_common.h
index 574e659..6dba9cd 100644
--- a/system/gralloc/gralloc_common.h
+++ b/system/gralloc/gralloc_common.h
@@ -17,6 +17,14 @@
 #ifndef __GRALLOC_COMMON_H__
 #define __GRALLOC_COMMON_H__
 
+// Tell the emulator which gralloc formats
+// need special handling.
+enum EmulatorFrameworkFormat {
+    FRAMEWORK_FORMAT_GL_COMPATIBLE = 0,
+    FRAMEWORK_FORMAT_YV12 = 1,
+    FRAMEWORK_FORMAT_YUV_420_888 = 2,              // (Y+)(U+)(V+)
+};
+
 #ifndef GL_RGBA16F
 #define GL_RGBA16F                        0x881A
 #endif // GL_RGBA16F
diff --git a/system/gralloc/gralloc_old.cpp b/system/gralloc/gralloc_old.cpp
index 773f786..6ab38a2 100644
--- a/system/gralloc/gralloc_old.cpp
+++ b/system/gralloc/gralloc_old.cpp
@@ -1,4 +1,4 @@
-/*
+ /*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,6 +13,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+
 #include <string.h>
 #include <pthread.h>
 #include <limits.h>
@@ -21,11 +22,12 @@
 #include <errno.h>
 #include <dlfcn.h>
 #include <sys/mman.h>
+#include <hardware/gralloc.h>
 
 #if PLATFORM_SDK_VERSION < 28
-#include "gralloc_cb_old.h"
+#include "gralloc_cb.h"
 #else
-#include "../../shared/OpenglCodecCommon/gralloc_cb_old.h"
+#include "../../shared/OpenglCodecCommon/gralloc_cb.h"
 #endif
 
 #include "gralloc_common.h"
@@ -81,8 +83,69 @@
 static const bool isHidlGralloc = false;
 #endif
 
-int32_t* getOpenCountPtr(cb_handle_old_t* cb) {
-    return ((int32_t*)cb->ashmemBase) + 1;
+const uint32_t CB_HANDLE_MAGIC_OLD = CB_HANDLE_MAGIC_BASE | 0x1;
+
+struct cb_handle_old_t : public cb_handle_t {
+    cb_handle_old_t(int p_fd, int p_ashmemSize, int p_usage,
+                    int p_width, int p_height,
+                    int p_format, int p_glFormat, int p_glType)
+            : cb_handle_t(p_fd,
+                          QEMU_PIPE_INVALID_HANDLE,
+                          CB_HANDLE_MAGIC_OLD,
+                          0,
+                          p_usage,
+                          p_width,
+                          p_height,
+                          p_format,
+                          p_glFormat,
+                          p_glType,
+                          p_ashmemSize,
+                          nullptr),
+              ashmemBasePid(0),
+              mappedPid(0) {
+        numInts = CB_HANDLE_NUM_INTS(numFds);
+    }
+
+    bool hasRefcountPipe() const {
+        return qemu_pipe_valid(hostHandleRefCountFd);
+    }
+
+    void setRefcountPipeFd(QEMU_PIPE_HANDLE fd) {
+        if (qemu_pipe_valid(fd)) {
+            numFds++;
+        }
+        hostHandleRefCountFd = fd;
+        numInts = CB_HANDLE_NUM_INTS(numFds);
+    }
+
+    bool canBePosted() const {
+        return (0 != (usage & GRALLOC_USAGE_HW_FB));
+    }
+
+    bool isValid() const {
+        return (version == sizeof(native_handle)) && (magic == CB_HANDLE_MAGIC_OLD);
+    }
+
+    static cb_handle_old_t* from(void* p) {
+        if (!p) { return nullptr; }
+        cb_handle_old_t* cb = static_cast<cb_handle_old_t*>(p);
+        return cb->isValid() ? cb : nullptr;
+    }
+
+    static const cb_handle_old_t* from(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    static cb_handle_old_t* from_unconst(const void* p) {
+        return from(const_cast<void*>(p));
+    }
+
+    int32_t ashmemBasePid;      // process id which mapped the ashmem region
+    int32_t mappedPid;          // process id which succeeded gralloc_register call
+};
+
+int32_t* getOpenCountPtr(const cb_handle_old_t* cb) {
+    return ((int32_t*)cb->getBufferPtr()) + 1;
 }
 
 uint32_t getAshmemColorOffset(cb_handle_old_t* cb) {
@@ -331,7 +394,7 @@
     dump_regions(rcEnc);
 #endif
 
-    get_mem_region((void*)cb->ashmemBase);
+    get_mem_region(cb->getBufferPtr());
 
 #if DEBUG
     dump_regions(rcEnc);
@@ -345,13 +408,13 @@
     dump_regions(rcEnc);
 #endif
 
-    const bool should_unmap = put_mem_region(rcEnc, (void*)cb->ashmemBase);
+    const bool should_unmap = put_mem_region(rcEnc, cb->getBufferPtr());
 
 #if DEBUG
     dump_regions(rcEnc);
 #endif
 
-    put_gralloc_region(rcEnc, cb->ashmemSize);
+    put_gralloc_region(rcEnc, cb->bufferSize);
 
     return should_unmap;
 }
@@ -365,21 +428,21 @@
 
 static int map_buffer(cb_handle_old_t *cb, void **vaddr)
 {
-    if (cb->fd < 0 || cb->ashmemSize <= 0) {
+    if (cb->bufferFd < 0) {
         return -EINVAL;
     }
 
-    void *addr = mmap(0, cb->ashmemSize, PROT_READ | PROT_WRITE,
-                      MAP_SHARED, cb->fd, 0);
+    void *addr = mmap(0, cb->bufferSize, PROT_READ | PROT_WRITE,
+                      MAP_SHARED, cb->bufferFd, 0);
     if (addr == MAP_FAILED) {
         ALOGE("%s: failed to map ashmem region!", __FUNCTION__);
         return -errno;
     }
 
-    cb->ashmemBase = intptr_t(addr);
+    cb->setBufferPtr(addr);
     cb->ashmemBasePid = getpid();
     D("%s: %p mapped ashmem base %p size %d\n", __FUNCTION__,
-      cb, cb->ashmemBase, cb->ashmemSize);
+      cb, addr, cb->bufferSize);
 
     *vaddr = addr;
     return 0;
@@ -496,17 +559,12 @@
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
             convertedBuf.resize(rgbSz);
             to_send = &convertedBuf.front();
-            if (rcEnc->hasYUV420toNV21()) {
-                nv21_to_rgb888(to_send, pixels,
-                               width, height, left, top,
-                               left + width - 1, top + height - 1);
-            } else {
-                yuv420p_to_rgb888(to_send, pixels,
-                                  width, height, left, top,
-                                  left + width - 1, top + height - 1);
-            }
+            yuv420p_to_rgb888(to_send, pixels,
+                              width, height, left, top,
+                              left + width - 1, top + height - 1);
             break;
         }
+
         rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle,
                 left, top, width, height,
                 cb->glFormat, cb->glType, to_send);
@@ -780,8 +838,7 @@
 
     cb_handle_old_t *cb = new cb_handle_old_t(fd, ashmem_size, usage,
                                               w, h, format,
-                                              glFormat, glType,
-                                              selectedEmuFrameworkFormat);
+                                              glFormat, glType);
 
     if (ashmem_size > 0) {
         //
@@ -794,7 +851,6 @@
             delete cb;
             return err;
         }
-        cb->setFd(fd);
     }
 
     const bool hasDMA = has_DMA_support(rcEnc);
@@ -813,7 +869,7 @@
 
             hostCon->lock();
             if (hasDMA) {
-                cb->hostHandle = rcEnc->rcCreateColorBufferDMA(rcEnc, w, h, allocFormat, cb->emuFrameworkFormat);
+                cb->hostHandle = rcEnc->rcCreateColorBufferDMA(rcEnc, w, h, allocFormat, selectedEmuFrameworkFormat);
             } else {
                 cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, allocFormat);
             }
@@ -871,20 +927,20 @@
 {
     DEFINE_AND_VALIDATE_HOST_CONNECTION;
 
-    cb_handle_old_t *cb = (cb_handle_old_t *)handle;
-    if (!cb_handle_old_t::validate((cb_handle_old_t*)cb)) {
-        ERR("gralloc_free: invalid handle");
+    const cb_handle_old_t *cb = cb_handle_old_t::from(handle);
+    if (!cb) {
+        ERR("gralloc_free: invalid handle %p", handle);
         return -EINVAL;
     }
 
     D("%s: for buf %p ptr %p size %d\n",
-      __FUNCTION__, handle, cb->ashmemBase, cb->ashmemSize);
+      __FUNCTION__, handle, cb->getBufferPtr(), cb->bufferSize);
 
     if (cb->hostHandle && !cb->hasRefcountPipe()) {
         int32_t openCount = 1;
         int32_t* openCountPtr = &openCount;
 
-        if (isHidlGralloc && cb->ashmemBase) {
+        if (isHidlGralloc && cb->getBufferPtr()) {
             openCountPtr = getOpenCountPtr(cb);
         }
 
@@ -902,17 +958,17 @@
     //
     // detach and unmap ashmem area if present
     //
-    if (cb->fd > 0) {
-        if (cb->ashmemSize > 0 && cb->ashmemBase) {
-            D("%s: unmapped %p", __FUNCTION__, cb->ashmemBase);
-            munmap((void *)cb->ashmemBase, cb->ashmemSize);
-            put_gralloc_region(rcEnc, cb->ashmemSize);
+    if (cb->bufferFd > 0) {
+        if (cb->bufferSize > 0 && cb->getBufferPtr()) {
+            D("%s: unmapped %p", __FUNCTION__, cb->getBufferPtr());
+            munmap(cb->getBufferPtr(), cb->bufferSize);
+            put_gralloc_region(rcEnc, cb->bufferSize);
         }
-        close(cb->fd);
+        close(cb->bufferFd);
     }
 
-    if(qemu_pipe_valid(cb->refcount_pipe_fd)) {
-        qemu_pipe_close(cb->refcount_pipe_fd);
+    if(qemu_pipe_valid(cb->hostHandleRefCountFd)) {
+        qemu_pipe_close(cb->hostHandleRefCountFd);
     }
     D("%s: done", __FUNCTION__);
     // remove it from the allocated list
@@ -955,9 +1011,14 @@
 static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
 {
     fb_device_t *fbdev = (fb_device_t *)dev;
-    cb_handle_old_t *cb = (cb_handle_old_t *)buffer;
-
-    if (!fbdev || !cb_handle_old_t::validate(cb) || !cb->canBePosted()) {
+    if (!fbdev) {
+        return -EINVAL;
+    }
+    const cb_handle_old_t *cb = cb_handle_old_t::from(buffer);
+    if (!cb) {
+        return -EINVAL;
+    }
+    if (!cb->canBePosted()) {
         return -EINVAL;
     }
 
@@ -965,7 +1026,7 @@
     DEFINE_AND_VALIDATE_HOST_CONNECTION;
 
     // increment the post count of the buffer
-    intptr_t *postCountPtr = (intptr_t *)cb->ashmemBase;
+    int32_t *postCountPtr = (int32_t *)cb->getBufferPtr();
     if (!postCountPtr) {
         // This should not happen
         return -EINVAL;
@@ -1053,9 +1114,12 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_old_t *cb = (cb_handle_old_t *)handle;
+    if (!gr) {
+        return -EINVAL;
+    }
 
-    if (!gr || !cb_handle_old_t::validate(cb)) {
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
         ERR("gralloc_register_buffer(%p): invalid buffer", cb);
         return -EINVAL;
     }
@@ -1074,7 +1138,7 @@
     // if the color buffer has ashmem region and it is not mapped in this
     // process map it now.
     //
-    if (cb->ashmemSize > 0 && cb->mappedPid != getpid()) {
+    if (cb->bufferSize > 0 && cb->mappedPid != getpid()) {
         void *vaddr;
         int err = map_buffer(cb, &vaddr);
         if (err) {
@@ -1089,7 +1153,7 @@
         }
     }
 
-    if (cb->ashmemSize > 0) {
+    if (cb->bufferSize > 0) {
         get_ashmem_region(rcEnc, cb);
     }
 
@@ -1106,9 +1170,12 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_old_t *cb = (cb_handle_old_t *)handle;
+    if (!gr) {
+        return -EINVAL;
+    }
 
-    if (!gr || !cb_handle_old_t::validate(cb)) {
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
         ERR("gralloc_unregister_buffer(%p): invalid buffer", cb);
         return -EINVAL;
     }
@@ -1122,7 +1189,7 @@
         if (isHidlGralloc) {
             // Queue up another rcCloseColorBuffer if applicable.
             // invariant: have ashmem.
-            if (cb->ashmemSize > 0 && cb->mappedPid == getpid()) {
+            if (cb->bufferSize > 0 && cb->mappedPid == getpid()) {
                 int32_t* openCountPtr = getOpenCountPtr(cb);
                 if (*openCountPtr == -1) {
                     D("%s: revenge of the rcCloseColorBuffer!", __func__);
@@ -1138,16 +1205,16 @@
     // unmap ashmem region if it was previously mapped in this process
     // (through register_buffer)
     //
-    if (cb->ashmemSize > 0 && cb->mappedPid == getpid()) {
+    if (cb->bufferSize > 0 && cb->mappedPid == getpid()) {
         const bool should_unmap = put_ashmem_region(rcEnc, cb);
         if (!should_unmap) goto done;
 
-        int err = munmap((void *)cb->ashmemBase, cb->ashmemSize);
+        int err = munmap(cb->getBufferPtr(), cb->bufferSize);
         if (err) {
             ERR("gralloc_unregister_buffer(%p): unmap failed", cb);
             return -EINVAL;
         }
-        cb->ashmemBase = 0;
+        cb->bufferSize = 0;
         cb->mappedPid = 0;
         D("%s: Unregister buffer previous mapped to pid %d", __FUNCTION__, getpid());
     }
@@ -1167,9 +1234,12 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_old_t *cb = (cb_handle_old_t *)handle;
+    if (!gr) {
+        return -EINVAL;
+    }
 
-    if (!gr || !cb_handle_old_t::validate(cb)) {
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
         ALOGE("gralloc_lock bad handle\n");
         return -EINVAL;
     }
@@ -1229,11 +1299,11 @@
     if (cb->canBePosted() || sw_read || sw_write ||
             hw_cam_write || hw_cam_read ||
             hw_vid_enc_read) {
-        if (cb->ashmemBasePid != getpid() || !cb->ashmemBase) {
+        if (cb->ashmemBasePid != getpid() || !cb->getBufferPtr()) {
             return -EACCES;
         }
 
-        cpu_addr = (void *)(cb->ashmemBase + getAshmemColorOffset(cb));
+        cpu_addr = (void *)((char*)cb->getBufferPtr() + getAshmemColorOffset(cb));
     }
 
     if (cb->hostHandle) {
@@ -1255,7 +1325,7 @@
         }
 
         // camera delivers bits to the buffer directly and does not require
-        // an explicit read, it also writes in YUV_420 (interleaved)
+        // an explicit read.
         if (sw_read & !(usage & GRALLOC_USAGE_HW_CAMERA_MASK)) {
             D("gralloc_lock read back color buffer %d %d ashmem base %p sz %d\n",
               cb->width, cb->height, cb->ashmemBase, cb->ashmemSize);
@@ -1285,13 +1355,8 @@
                         D("convert rgb888 to yv12 here");
                         rgb888_to_yv12((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
                     } else if (cb->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-                        if (rcEnc->hasYUV420toNV21()) {
-                            D("convert rgb888 to nv21 here");
-                            rgb888_to_nv21((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
-                        } else {
-                            D("convert rgb888 to yuv420p here");
-                            rgb888_to_yuv420p((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
-                        }
+                        D("convert rgb888 to yuv420p here");
+                        rgb888_to_yuv420p((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
                     }
                     delete [] tmpBuf;
                 }
@@ -1302,7 +1367,7 @@
         }
 
         if (has_DMA_support(rcEnc)) {
-            gralloc_dmaregion_register_ashmem(rcEnc, cb->ashmemSize);
+            gralloc_dmaregion_register_ashmem(rcEnc, cb->bufferSize);
         }
         hostCon->unlock();
     }
@@ -1338,10 +1403,13 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_old_t *cb = (cb_handle_old_t *)handle;
+    if (!gr) {
+        return -EINVAL;
+    }
 
-    if (!gr || !cb_handle_old_t::validate(cb)) {
-        ALOGD("%s: invalid gr or cb handle. -EINVAL", __FUNCTION__);
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
+        ALOGD("%s: invalid cb handle. -EINVAL", __FUNCTION__);
         return -EINVAL;
     }
 
@@ -1355,14 +1423,13 @@
         DEFINE_AND_VALIDATE_HOST_CONNECTION;
         hostCon->lock();
 
-        void *cpu_addr = (void *)(cb->ashmemBase + getAshmemColorOffset(cb));
+        char *cpu_addr = (char*)cb->getBufferPtr() + getAshmemColorOffset(cb);
 
-        char* rgb_addr = (char *)cpu_addr;
         if (cb->lockedWidth < cb->width || cb->lockedHeight < cb->height) {
-            updateHostColorBuffer(cb, true, rgb_addr);
+            updateHostColorBuffer(cb, true, cpu_addr);
         }
         else {
-            updateHostColorBuffer(cb, false, rgb_addr);
+            updateHostColorBuffer(cb, false, cpu_addr);
         }
 
         hostCon->unlock();
@@ -1391,8 +1458,12 @@
     }
 
     private_module_t *gr = (private_module_t *)module;
-    cb_handle_old_t *cb = (cb_handle_old_t *)handle;
-    if (!gr || !cb_handle_old_t::validate(cb)) {
+    if (!gr) {
+        return -EINVAL;
+    }
+
+    cb_handle_old_t *cb = cb_handle_old_t::from_unconst(handle);
+    if (!cb) {
         ALOGE("%s: bad colorbuffer handle. -EINVAL", __FUNCTION__);
         return -EINVAL;
     }
@@ -1445,34 +1516,14 @@
             uOffset = vOffset + cSize;
             cStep = 1;
             break;
-        case HAL_PIXEL_FORMAT_YCbCr_420_888: {
-            DEFINE_AND_VALIDATE_HOST_CONNECTION
-            if (rcEnc->hasYUV420toNV21()) {
-                yStride = cb->width;
-                cStride = cb->width;
-                yOffset = 0;
-                vOffset = yStride * cb->height;
-                uOffset = vOffset + 1;
-                cStep = 2;
-            } else {
-                if (usage & GRALLOC_USAGE_HW_CAMERA_MASK) {
-                    yStride = cb->width;
-                    cStride = cb->width;
-                    yOffset = 0;
-                    vOffset = yStride * cb->height;
-                    uOffset = vOffset + 1;
-                    cStep = 2;
-                } else {
-                    yStride = cb->width;
-                    cStride = yStride / 2;
-                    yOffset = 0;
-                    uOffset = cb->height * yStride;
-                    vOffset = uOffset + cStride * cb->height / 2;
-                    cStep = 1;
-                }
-            }
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            yStride = cb->width;
+            cStride = yStride / 2;
+            yOffset = 0;
+            uOffset = cb->height * yStride;
+            vOffset = uOffset + cStride * cb->height / 2;
+            cStep = 1;
             break;
-        }
         default:
             ALOGE("gralloc_lock_ycbcr unexpected internal format %x",
                     cb->format);
diff --git a/system/hwc2/EmuHWC2.cpp b/system/hwc2/EmuHWC2.cpp
index 921d848..edf6397 100644
--- a/system/hwc2/EmuHWC2.cpp
+++ b/system/hwc2/EmuHWC2.cpp
@@ -31,6 +31,7 @@
 #include "../egl/goldfish_sync.h"
 
 #include "ThreadInfo.h"
+#include "gralloc_cb.h"
 
 #if defined(LOG_NNDEBUG) && LOG_NNDEBUG == 0
 #define ALOGVV ALOGV
@@ -219,6 +220,23 @@
                     displayHook<decltype(&Display::getClientTargetSupport),
                     &Display::getClientTargetSupport, uint32_t, uint32_t,
                                                       int32_t, int32_t>);
+        // 2.3 required functions
+        case FunctionDescriptor::GetDisplayIdentificationData:
+            return asFP<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>(
+                    displayHook<decltype(&Display::getDisplayIdentificationData),
+                    &Display::getDisplayIdentificationData, uint8_t*, uint32_t*, uint8_t*>);
+        case FunctionDescriptor::GetDisplayCapabilities:
+            return asFP<HWC2_PFN_GET_DISPLAY_CAPABILITIES>(
+                    displayHook<decltype(&Display::getDisplayCapabilities),
+                    &Display::getDisplayCapabilities, uint32_t*, uint32_t*>);
+        case FunctionDescriptor::GetDisplayBrightnessSupport:
+            return asFP<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>(
+                    displayHook<decltype(&Display::getDisplayBrightnessSupport),
+                    &Display::getDisplayBrightnessSupport, bool*>);
+        case FunctionDescriptor::SetDisplayBrightness:
+            return asFP<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
+                    displayHook<decltype(&Display::setDisplayBrightness),
+                    &Display::setDisplayBrightness, float>);
         // Layer functions
         case FunctionDescriptor::SetCursorPosition:
             return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
@@ -374,8 +392,7 @@
     if (mHandle != nullptr) {
         mGralloc->unregisterBuffer(mGralloc, mHandle);
         mAllocDev->free(mAllocDev, mHandle);
-        ALOGI("free targetCb %u",
-            cb_handle_t::from_raw_pointer(mHandle)->hostHandle);
+        ALOGI("free targetCb %u", cb_handle_t::from(mHandle)->hostHandle);
     }
 }
 
@@ -390,9 +407,9 @@
                                &mHandle, &stride);
         assert(ret == 0 && "Fail to allocate target ColorBuffer");
         mGralloc->registerBuffer(mGralloc, mHandle);
-        ALOGI("targetCb %u", cb_handle_t::from_raw_pointer(mHandle)->hostHandle);
+        ALOGI("targetCb %u", cb_handle_t::from(mHandle)->hostHandle);
     }
-    return cb_handle_t::from_raw_pointer(mHandle)->hostHandle;
+    return cb_handle_t::from(mHandle)->hostHandle;
 }
 
 // Display functions
@@ -796,7 +813,7 @@
                           __FUNCTION__, (uint32_t)layer->getId());
                 }
                 const cb_handle_t *cb =
-                    cb_handle_t::from_raw_pointer(layer->getLayerBuffer().getBuffer());
+                    cb_handle_t::from(layer->getLayerBuffer().getBuffer());
                 if (cb != nullptr) {
                     l->cbHandle = cb->hostHandle;
                 }
@@ -906,7 +923,7 @@
         int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
     ALOGVV("%s", __FUNCTION__);
 
-    const cb_handle_t *cb = cb_handle_t::from_raw_pointer(target);
+    const cb_handle_t *cb = cb_handle_t::from(target);
     ALOGV("%s: display(%u) buffer handle %p cb %d, acquireFence %d", __FUNCTION__,
           (uint32_t)mId, target, cb->hostHandle, acquireFence);
     std::unique_lock<std::mutex> lock(mStateMutex);
@@ -1130,6 +1147,136 @@
     return Error::None;
 }
 
+// thess EDIDs are carefully generated according to the EDID spec version 1.3, more info
+// can be found from the following file:
+//   frameworks/native/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+// approved pnp ids can be found here: https://uefi.org/pnp_id_list
+// pnp id: GGL, name: EMU_display_0, last byte is checksum
+// display id is local:8141603649153536
+static const std::vector<uint8_t> sEDID0 {
+    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
+    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+    0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x30, 0x00, 0x4b
+};
+
+// pnp id: GGL, name: EMU_display_1
+// display id is local:8140900251843329
+static const std::vector<uint8_t> sEDID1 {
+    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
+    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+    0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x31, 0x00, 0x3b
+};
+
+// pnp id: GGL, name: EMU_display_2
+// display id is local:8140940453066754
+static const std::vector<uint8_t> sEDID2 {
+    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27,
+    0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+    0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+    0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x32, 0x00, 0x49
+};
+
+Error EmuHWC2::Display::getDisplayIdentificationData(uint8_t* outPort,
+        uint32_t* outDataSize, uint8_t* outData) {
+    ALOGVV("%s DisplayId %u", __FUNCTION__, (uint32_t)mId);
+    if (outPort == nullptr || outDataSize == nullptr)
+        return Error::BadParameter;
+
+    uint32_t len = std::min(*outDataSize, (uint32_t)(sEDID0.size()));
+    if (outData != nullptr && len < (uint32_t)(sEDID0.size())) {
+        ALOGW("%s DisplayId %u, small buffer size: %u is specified",
+                __FUNCTION__, (uint32_t)mId, len);
+    }
+    *outDataSize = (int32_t)(sEDID0.size());
+    switch (mId) {
+        case 0:
+            *outPort = 0;
+            if (outData)
+                memcpy(outData, sEDID0.data(), len);
+            break;
+
+        case 1:
+            *outPort = 1;
+            if (outData)
+                memcpy(outData, sEDID1.data(), len);
+            break;
+
+        case 2:
+            *outPort = 2;
+            if (outData)
+                memcpy(outData, sEDID2.data(), len);
+            break;
+
+        default:
+            *outPort = (uint8_t)mId;
+            if (outData) {
+                memcpy(outData, sEDID2.data(), len);
+                uint32_t size = sEDID0.size();
+                // change the name to EMU_display_<mID>
+                // note the 3rd char from back is the number, _0, _1, _2, etc.
+                if (len >= size - 2)
+                    outData[size-3] = '0' + (uint8_t)mId;
+                if (len >= size) {
+                    // update the last byte, which is checksum byte
+                    uint8_t checksum = -(uint8_t)std::accumulate(
+                            outData, outData + size - 1, static_cast<uint8_t>(0));
+                    outData[size - 1] = checksum;
+                }
+            }
+            break;
+    }
+
+    return Error::None;
+}
+
+Error EmuHWC2::Display::getDisplayCapabilities(uint32_t* outNumCapabilities,
+        uint32_t* outCapabilities) {
+    if (outNumCapabilities == nullptr) {
+        return Error::None;
+    }
+
+    bool brightness_support = true;
+    bool doze_support = true;
+
+    uint32_t count = 1  + static_cast<uint32_t>(doze_support) + (brightness_support ? 1 : 0);
+    int index = 0;
+    if (outCapabilities != nullptr && (*outNumCapabilities >= count)) {
+        outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+        if (doze_support) {
+            outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_DOZE;
+        }
+        if (brightness_support) {
+            outCapabilities[index++] = HWC2_DISPLAY_CAPABILITY_BRIGHTNESS;
+       }
+    }
+
+    *outNumCapabilities = count;
+    return Error::None;
+}
+
+Error EmuHWC2::Display::getDisplayBrightnessSupport(bool *out_support) {
+    *out_support = false;
+    return Error::None;
+}
+
+Error EmuHWC2::Display::setDisplayBrightness(float brightness) {
+    ALOGW("TODO: setDisplayBrightness() is not implemented yet: brightness=%f", brightness);
+    return Error::None;
+}
 
 int EmuHWC2::Display::populatePrimaryConfigs() {
     ALOGVV("%s DisplayId %u", __FUNCTION__, (uint32_t)mId);
@@ -1524,6 +1671,7 @@
 EmuHWC2::Display* EmuHWC2::getDisplay(hwc2_display_t id) {
     auto display = mDisplays.find(id);
     if (display == mDisplays.end()) {
+        ALOGE("Failed to get display for id=%d", (uint32_t)id);
         return nullptr;
     }
     return display->second.get();
diff --git a/system/hwc2/EmuHWC2.h b/system/hwc2/EmuHWC2.h
index d4615a7..ff056ca 100644
--- a/system/hwc2/EmuHWC2.h
+++ b/system/hwc2/EmuHWC2.h
@@ -27,13 +27,14 @@
 #include <atomic>
 #include <map>
 #include <mutex>
+#include <numeric>
 #include <sstream>
 #include <vector>
 #include <unordered_set>
 #include <unordered_map>
 #include <set>
+#include <cutils/native_handle.h>
 
-#include "gralloc_cb.h"
 #include "MiniFence.h"
 #include "HostConnection.h"
 
@@ -257,6 +258,13 @@
         HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
         HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
                  int32_t format, int32_t dataspace);
+        // 2.3 required functions
+        HWC2::Error getDisplayIdentificationData(uint8_t* outPort,
+                 uint32_t* outDataSize, uint8_t* outData);
+        HWC2::Error getDisplayCapabilities(uint32_t* outNumCapabilities,
+                 uint32_t* outCapabilities);
+        HWC2::Error getDisplayBrightnessSupport(bool *out_support);
+        HWC2::Error setDisplayBrightness(float brightness);
 
         // Read configs from PRIMARY Display
         int populatePrimaryConfigs();
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.cpp b/system/vulkan_enc/AndroidHardwareBuffer.cpp
index e2f2ad1..0a71d6d 100644
--- a/system/vulkan_enc/AndroidHardwareBuffer.cpp
+++ b/system/vulkan_enc/AndroidHardwareBuffer.cpp
@@ -111,9 +111,12 @@
 
     const native_handle_t *handle =
        AHardwareBuffer_getNativeHandle(buffer);
-    const cb_handle_t* cb_handle = cb_handle_t::from_native_handle(handle);
-    uint32_t colorBufferHandle = cb_handle->hostHandle;
+    const cb_handle_t* cb_handle = cb_handle_t::from(handle);
+    if (!cb_handle) {
+        return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+    }
 
+    uint32_t colorBufferHandle = cb_handle->hostHandle;
     if (!colorBufferHandle) {
         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
     }
@@ -128,7 +131,7 @@
     }
 
     pProperties->memoryTypeBits = memoryTypeBits;
-    pProperties->allocationSize = cb_handle->allocationSize();
+    pProperties->allocationSize = cb_handle->allocatedSize();
 
     return VK_SUCCESS;
 }
@@ -164,9 +167,12 @@
 
     const native_handle_t *handle =
        AHardwareBuffer_getNativeHandle(info->buffer);
-    const cb_handle_t* cb_handle = cb_handle_t::from_native_handle(handle);
-    uint32_t colorBufferHandle = cb_handle->hostHandle;
+    const cb_handle_t* cb_handle = cb_handle_t::from(handle);
+    if (!cb_handle) {
+        return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+    }
 
+    uint32_t colorBufferHandle = cb_handle->hostHandle;
     if (!colorBufferHandle) {
         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
     }
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 98bf049..363d3b9 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -1836,7 +1836,7 @@
             ALOGD("%s: Import AHardwareBulffer", __func__);
             const native_handle_t *handle =
                 AHardwareBuffer_getNativeHandle(ahw);
-            const cb_handle_t* cb_handle = cb_handle_t::from_native_handle(handle);
+            const cb_handle_t* cb_handle = cb_handle_t::from(handle);
             importCbInfo.colorBuffer = cb_handle->hostHandle;
             vk_append_struct(&structChainIter, &importCbInfo);
         }
@@ -3463,9 +3463,7 @@
             return;
         }
 
-        const cb_handle_t* cb_handle =
-            cb_handle_t::from_raw_pointer(nativeInfo->handle);
-
+        const cb_handle_t* cb_handle = cb_handle_t::from(nativeInfo->handle);
         if (!cb_handle) return;
 
         VkNativeBufferANDROID* nativeInfoOut =
diff --git a/system/vulkan_enc/vk_format_info.h b/system/vulkan_enc/vk_format_info.h
index 8c0b7dc..c517cb1 100644
--- a/system/vulkan_enc/vk_format_info.h
+++ b/system/vulkan_enc/vk_format_info.h
@@ -27,6 +27,7 @@
 #define VK_FORMAT_INFO_H
 
 #include <stdbool.h>
+#include <system/graphics.h>
 #include <vulkan/vulkan.h>
 #include <vndk/hardware_buffer.h>
 
diff --git a/system/vulkan_enc/vulkan_enc_unittests.cpp b/system/vulkan_enc/vulkan_enc_unittests.cpp
index 920550a..744ea31 100644
--- a/system/vulkan_enc/vulkan_enc_unittests.cpp
+++ b/system/vulkan_enc/vulkan_enc_unittests.cpp
@@ -95,6 +95,9 @@
     p.waitAny(handle, -1);
 
     EXPECT_GE(x, 1);
+
+    // Prevent use after scope after test finish
+    p.waitAll(handle);
 }
 
 // Tests waitAll primitive; each worker increments the atomic int once,