AddressSpaceStream

bug: 140112486
Change-Id: Ida19e194b7160975fb6b4bdaaf4982291456e05c
diff --git a/BUILD.gn b/BUILD.gn
index 0f4d394..09463d1 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -36,6 +36,7 @@
     "shared/OpenglCodecCommon/goldfish_address_space.h",
     "shared/OpenglCodecCommon/goldfish_dma.cpp",
     "shared/OpenglCodecCommon/goldfish_dma.h",
+    "system/OpenglSystemCommon/AddressSpaceStream.cpp",
     "system/OpenglSystemCommon/HostConnection.cpp",
     "system/OpenglSystemCommon/HostConnection.h",
     "system/OpenglSystemCommon/ProcessPipe.cpp",
diff --git a/system/OpenglSystemCommon/AddressSpaceStream.cpp b/system/OpenglSystemCommon/AddressSpaceStream.cpp
new file mode 100644
index 0000000..00d654c
--- /dev/null
+++ b/system/OpenglSystemCommon/AddressSpaceStream.cpp
@@ -0,0 +1,545 @@
+/*
+* Copyright (C) 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.
+*/
+#include "AddressSpaceStream.h"
+
+#if PLATFORM_SDK_VERSION < 26
+#include <cutils/log.h>
+#else
+#include <log/log.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+static const uint32_t kDeviceId = 0;
+
+static const size_t kReadSize = 512 * 1024;
+static const size_t kWriteOffset = kReadSize;
+
+AddressSpaceStream* createAddressSpaceStream(size_t ignored_bufSize) {
+    // Ignore incoming ignored_bufSize
+    (void)ignored_bufSize;
+
+    auto handle = goldfish_address_space_open();
+
+    struct goldfish_address_space_ping request;
+    request.metadata = kDeviceId;
+
+    if (!goldfish_address_space_ping(handle, &request)) {
+        ALOGE("AddressSpaceStream::create failed (initial device create)\n");
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    request.metadata = ASG_GET_RING;
+    if (!goldfish_address_space_ping(handle, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get ring)\n");
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    uint64_t ringOffset = request.metadata;
+
+    request.metadata = ASG_GET_BUFFER;
+    if (!goldfish_address_space_ping(handle, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get buffer)\n");
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    uint64_t bufferOffset = request.metadata;
+    uint64_t bufferSize = request.size;
+
+    if (!goldfish_address_space_claim_shared(
+        handle, ringOffset, sizeof(asg_ring_storage))) {
+        ALOGE("AddressSpaceStream::create failed (claim ring storage)\n");
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    if (!goldfish_address_space_claim_shared(
+        handle, bufferOffset, bufferSize)) {
+        ALOGE("AddressSpaceStream::create failed (claim buffer storage)\n");
+        goldfish_address_space_unclaim_shared(handle, ringOffset);
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    char* ringPtr = (char*)goldfish_address_space_map(
+        handle, ringOffset, sizeof(struct asg_ring_storage));
+
+    if (!ringPtr) {
+        ALOGE("AddressSpaceStream::create failed (map ring storage)\n");
+        goldfish_address_space_unclaim_shared(handle, bufferOffset);
+        goldfish_address_space_unclaim_shared(handle, ringOffset);
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    char* bufferPtr = (char*)goldfish_address_space_map(
+        handle, bufferOffset, bufferSize);
+
+    if (!bufferPtr) {
+        ALOGE("AddressSpaceStream::create failed (map buffer storage)\n");
+        goldfish_address_space_unmap(ringPtr, sizeof(struct asg_ring_storage));
+        goldfish_address_space_unclaim_shared(handle, bufferOffset);
+        goldfish_address_space_unclaim_shared(handle, ringOffset);
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    struct asg_context context =
+        asg_context_create(
+            ringPtr, bufferPtr, bufferSize);
+
+    request.metadata = ASG_SET_VERSION;
+    request.size = 1; // version 1
+
+    if (!goldfish_address_space_ping(handle, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get buffer)\n");
+        goldfish_address_space_unmap(bufferPtr, bufferSize);
+        goldfish_address_space_unmap(ringPtr, sizeof(struct asg_ring_storage));
+        goldfish_address_space_unclaim_shared(handle, bufferOffset);
+        goldfish_address_space_unclaim_shared(handle, ringOffset);
+        goldfish_address_space_close(handle);
+        return nullptr;
+    }
+
+    uint32_t version = request.size;
+
+    context.ring_config->transfer_mode = 1;
+    context.ring_config->host_consumed_pos = 0;
+    context.ring_config->guest_write_pos = 0;
+
+    AddressSpaceStream* res =
+        new AddressSpaceStream(
+            handle, version, context,
+            ringOffset, bufferOffset);
+
+    return res;
+}
+
+AddressSpaceStream::AddressSpaceStream(
+    address_space_handle_t handle,
+    uint32_t version,
+    struct asg_context context,
+    uint64_t ringOffset,
+    uint64_t writeBufferOffset) :
+    IOStream(context.ring_config->flush_interval),
+    m_tmpBuf(0),
+    m_tmpBufSize(0),
+    m_tmpBufXferSize(0),
+    m_usingTmpBuf(0),
+    m_readBuf(0),
+    m_read(0),
+    m_readLeft(0),
+    m_handle(handle),
+    m_version(version),
+    m_context(context),
+    m_ringOffset(ringOffset),
+    m_writeBufferOffset(writeBufferOffset),
+    m_writeBufferSize(context.ring_config->buffer_size),
+    m_writeBufferMask(m_writeBufferSize - 1),
+    m_buf((unsigned char*)context.buffer),
+    m_writeStart(m_buf),
+    m_writeStep(context.ring_config->flush_interval) {
+    // We'll use this in the future, but at the moment,
+    // it's a potential compile Werror.
+    (void)m_version;
+}
+
+AddressSpaceStream::~AddressSpaceStream() {
+    goldfish_address_space_unmap(m_context.to_host, sizeof(struct asg_ring_storage));
+    goldfish_address_space_unmap(m_context.buffer, m_writeBufferSize);
+    goldfish_address_space_unclaim_shared(m_handle, m_ringOffset);
+    goldfish_address_space_unclaim_shared(m_handle, m_writeBufferOffset);
+    goldfish_address_space_close(m_handle);
+    if (m_readBuf) free(m_readBuf);
+    if (m_tmpBuf) free(m_tmpBuf);
+}
+
+size_t AddressSpaceStream::idealAllocSize(size_t len) {
+    if (len > m_writeStep) return len;
+    return m_writeStep;
+}
+
+void *AddressSpaceStream::allocBuffer(size_t minSize) {
+    if (!m_readBuf) {
+        m_readBuf = (unsigned char*)malloc(kReadSize);
+    }
+
+    size_t allocSize =
+        (m_writeStep < minSize ? minSize : m_writeStep);
+
+    if (m_writeStep < allocSize) {
+        ALOGD("%s: oops. wanted %zu have %zu\n", __func__,
+                (size_t)allocSize, (size_t)m_writeStep);
+        if (!m_tmpBuf) {
+            m_tmpBufSize = allocSize * 2;
+            m_tmpBuf = (unsigned char*)malloc(m_tmpBufSize);
+        }
+
+        if (m_tmpBufSize < allocSize) {
+            m_tmpBufSize = allocSize * 2;
+            m_tmpBuf = (unsigned char*)realloc(m_tmpBuf, m_tmpBufSize);
+        }
+
+        if (!m_usingTmpBuf) {
+            ensureType1Finished();
+        }
+
+        m_usingTmpBuf = true;
+        m_tmpBufXferSize = allocSize;
+        return m_tmpBuf;
+    } else {
+        if (m_usingTmpBuf) {
+            writeFully(m_tmpBuf, m_tmpBufXferSize);
+            m_usingTmpBuf = false;
+            m_tmpBufXferSize = 0;
+        }
+
+        return m_writeStart;
+    }
+};
+
+int AddressSpaceStream::commitBuffer(size_t size)
+{
+    if (size == 0) return 0;
+
+    if (m_usingTmpBuf) {
+        writeFully(m_tmpBuf, m_tmpBufXferSize);
+        m_tmpBufXferSize = 0;
+        m_usingTmpBuf = false;
+        return 0;
+    } else {
+        int res = type1Write(m_writeStart - m_buf, size);
+        advanceWrite();
+        return res;
+    }
+}
+
+const unsigned char *AddressSpaceStream::readFully(void *ptr, size_t totalReadSize)
+{
+    ensureConsumerFinishing();
+
+    unsigned char* userReadBuf = static_cast<unsigned char*>(ptr);
+
+    if (!userReadBuf) {
+        if (totalReadSize > 0) {
+            ALOGE("AddressSpaceStream::commitBufferAndReadFully failed, userReadBuf=NULL, totalReadSize %zu, lethal"
+                    " error, exiting.", totalReadSize);
+            abort();
+        }
+        return nullptr;
+    }
+
+    // Advance buffered read if not yet consumed.
+    size_t remaining = totalReadSize;
+    size_t bufferedReadSize =
+        m_readLeft < remaining ? m_readLeft : remaining;
+
+    if (bufferedReadSize) {
+        memcpy(userReadBuf,
+               m_readBuf + (m_read - m_readLeft),
+               bufferedReadSize);
+        remaining -= bufferedReadSize;
+        m_readLeft -= bufferedReadSize;
+    }
+
+    if (!remaining) return userReadBuf;
+
+    // Read up to kReadSize bytes if all buffered read has been consumed.
+    size_t maxRead = m_readLeft ? 0 : kReadSize;
+    ssize_t actual = 0;
+
+    if (maxRead) {
+        actual = speculativeRead(m_readBuf, maxRead);
+
+        // Updated buffered read size.
+        if (actual > 0) {
+            m_read = m_readLeft = actual;
+        }
+
+        if (actual == 0) {
+            ALOGD("%s: end of pipe", __FUNCTION__);
+            return NULL;
+        }
+    }
+
+    // Consume buffered read and read more if necessary.
+    while (remaining) {
+        bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
+        if (bufferedReadSize) {
+            memcpy(userReadBuf + (totalReadSize - remaining),
+                   m_readBuf + (m_read - m_readLeft),
+                   bufferedReadSize);
+            remaining -= bufferedReadSize;
+            m_readLeft -= bufferedReadSize;
+            continue;
+        }
+
+        actual = speculativeRead(m_readBuf, kReadSize);
+
+        if (actual == 0) {
+            ALOGD("%s: Failed reading from pipe: %d", __FUNCTION__,  errno);
+            return NULL;
+        }
+
+        if (actual > 0) {
+            m_read = m_readLeft = actual;
+            continue;
+        }
+    }
+
+    return userReadBuf;
+}
+
+const unsigned char *AddressSpaceStream::read(void *buf, size_t *inout_len) {
+    unsigned char* dst = (unsigned char*)buf;
+    size_t wanted = *inout_len;
+    ssize_t actual = speculativeRead(dst, wanted);
+
+    if (actual >= 0) {
+        *inout_len = actual;
+    } else {
+        return nullptr;
+    }
+
+    return (const unsigned char*)dst;
+}
+
+int AddressSpaceStream::writeFully(const void *buf, size_t size)
+{
+    ensureType1Finished();
+    m_context.ring_config->transfer_size = size;
+    m_context.ring_config->transfer_mode = 3;
+
+    size_t sent = 0;
+    size_t quarterRingSize = m_writeBufferSize / 4;
+    size_t chunkSize = size < quarterRingSize ? size : quarterRingSize;
+    const uint8_t* bufferBytes = (const uint8_t*)buf;
+
+    while (sent < size) {
+        size_t remaining = size - sent;
+        size_t sendThisTime = remaining < chunkSize ? remaining : chunkSize;
+
+        long sentChunks =
+            ring_buffer_view_write(
+                m_context.to_host_large_xfer.ring,
+                &m_context.to_host_large_xfer.view,
+                bufferBytes + sent, sendThisTime, 1);
+
+        if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
+            notifyAvailable();
+        }
+
+        if (sentChunks == 0) {
+            ring_buffer_yield();
+        }
+
+        sent += sentChunks * sendThisTime;
+
+        if (isInError()) {
+            return -1;
+        }
+    }
+
+    ensureType3Finished();
+    m_context.ring_config->transfer_mode = 1;
+    return 0;
+}
+
+const unsigned char *AddressSpaceStream::commitBufferAndReadFully(
+    size_t writeSize, void *userReadBufPtr, size_t totalReadSize) {
+
+    if (m_usingTmpBuf) {
+        writeFully(m_tmpBuf, m_tmpBufXferSize);
+        m_usingTmpBuf = false;
+        m_tmpBufXferSize = 0;
+    }
+
+    commitBuffer(writeSize);
+    return readFully(userReadBufPtr, totalReadSize);
+}
+
+bool AddressSpaceStream::isInError() const {
+    return 1 == m_context.ring_config->in_error;
+}
+
+ssize_t AddressSpaceStream::speculativeRead(unsigned char* readBuffer, size_t trySize) {
+    flush();
+    ensureConsumerFinishing();
+
+    size_t actuallyRead = 0;
+    while (!actuallyRead) {
+        uint32_t readAvail =
+            ring_buffer_available_read(
+                m_context.from_host_large_xfer.ring,
+                &m_context.from_host_large_xfer.view);
+
+        if (!readAvail) {
+            ring_buffer_yield();
+            continue;
+        }
+
+        uint32_t toRead = readAvail > trySize ?  trySize : readAvail;
+
+        long stepsRead = ring_buffer_view_read(
+            m_context.from_host_large_xfer.ring,
+            &m_context.from_host_large_xfer.view,
+            readBuffer, toRead, 1);
+
+        actuallyRead += stepsRead * toRead;
+
+        if (isInError()) {
+            return -1;
+        }
+    }
+
+    return actuallyRead;
+}
+
+void AddressSpaceStream::notifyAvailable() {
+    struct goldfish_address_space_ping request;
+    request.metadata = ASG_NOTIFY_AVAILABLE;
+    goldfish_address_space_ping(m_handle, &request);
+}
+
+uint32_t AddressSpaceStream::getRelativeBufferPos(uint32_t pos) {
+    return pos & m_writeBufferMask;
+}
+
+uint32_t AddressSpaceStream::getAvailableForWrite() {
+    uint32_t host_consumed_view;
+    __atomic_load(&m_context.ring_config->host_consumed_pos,
+                  &host_consumed_view,
+                  __ATOMIC_SEQ_CST);
+    uint32_t availableForWrite =
+        getRelativeBufferPos(
+            host_consumed_view -
+            m_context.ring_config->guest_write_pos - 1);
+    return availableForWrite;
+}
+
+void AddressSpaceStream::advanceWrite() {
+    uint32_t avail = getAvailableForWrite();
+
+    while (avail < m_context.ring_config->flush_interval) {
+        ensureConsumerFinishing();
+        avail = getAvailableForWrite();
+    }
+
+    __atomic_add_fetch(
+        &m_context.ring_config->guest_write_pos,
+        m_context.ring_config->flush_interval,
+        __ATOMIC_SEQ_CST);
+
+    unsigned char* newBuffer =
+        m_buf +
+        getRelativeBufferPos(
+            m_context.ring_config->guest_write_pos);
+
+    m_writeStart = newBuffer;
+}
+
+void AddressSpaceStream::ensureConsumerFinishing() {
+    uint32_t currAvailRead =
+        ring_buffer_available_read(m_context.to_host, 0);
+
+    while (currAvailRead) {
+        ring_buffer_yield();
+        uint32_t nextAvailRead = ring_buffer_available_read(m_context.to_host, 0);
+
+        if (nextAvailRead != currAvailRead) {
+            break;
+        }
+
+        if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
+            notifyAvailable();
+            break;
+        }
+    }
+}
+
+void AddressSpaceStream::ensureType1Finished() {
+    ensureConsumerFinishing();
+
+    uint32_t currAvailRead =
+        ring_buffer_available_read(m_context.to_host, 0);
+
+    while (currAvailRead) {
+        ring_buffer_yield();
+        currAvailRead = ring_buffer_available_read(m_context.to_host, 0);
+        if (isInError()) {
+            return;
+        }
+    }
+}
+
+void AddressSpaceStream::ensureType3Finished() {
+    uint32_t availReadLarge =
+        ring_buffer_available_read(
+            m_context.to_host_large_xfer.ring,
+            &m_context.to_host_large_xfer.view);
+    while (availReadLarge) {
+        ring_buffer_yield();
+        availReadLarge =
+            ring_buffer_available_read(
+                m_context.to_host_large_xfer.ring,
+                &m_context.to_host_large_xfer.view);
+        if (isInError()) {
+            return;
+        }
+    }
+}
+
+int AddressSpaceStream::type1Write(uint32_t bufferOffset, size_t size) {
+    size_t sent = 0;
+    size_t sizeForRing = sizeof(struct asg_type1_xfer);
+
+    struct asg_type1_xfer xfer = {
+        bufferOffset,
+        (uint32_t)size,
+    };
+
+    uint8_t* writeBufferBytes = (uint8_t*)(&xfer);
+
+    while (sent < sizeForRing) {
+
+        long sentChunks = ring_buffer_write(
+            m_context.to_host,
+            writeBufferBytes + sent,
+            sizeForRing - sent, 1);
+
+        if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
+            notifyAvailable();
+        }
+
+        if (sentChunks == 0) {
+            ring_buffer_yield();
+        }
+
+        sent += sentChunks * (sizeForRing - sent);
+
+        if (isInError()) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
diff --git a/system/OpenglSystemCommon/AddressSpaceStream.h b/system/OpenglSystemCommon/AddressSpaceStream.h
new file mode 100644
index 0000000..9a06991
--- /dev/null
+++ b/system/OpenglSystemCommon/AddressSpaceStream.h
@@ -0,0 +1,81 @@
+/*
+* Copyright (C) 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 __ADDRESS_SPACE_STREAM_H
+#define __ADDRESS_SPACE_STREAM_H
+
+#include "IOStream.h"
+
+#include "address_space_graphics_types.h"
+#include "goldfish_address_space.h"
+
+class AddressSpaceStream;
+
+AddressSpaceStream* createAddressSpaceStream(size_t bufSize);
+
+class AddressSpaceStream : public IOStream {
+public:
+    explicit AddressSpaceStream(
+        address_space_handle_t handle,
+        uint32_t version,
+        struct asg_context context,
+        uint64_t ringOffset,
+        uint64_t writeBufferOffset);
+    ~AddressSpaceStream();
+
+    virtual size_t idealAllocSize(size_t len);
+    virtual void *allocBuffer(size_t minSize);
+    virtual int commitBuffer(size_t size);
+    virtual const unsigned char *readFully( void *buf, size_t len);
+    virtual const unsigned char *read( void *buf, size_t *inout_len);
+    virtual int writeFully(const void *buf, size_t len);
+    virtual const unsigned char *commitBufferAndReadFully(size_t size, void *buf, size_t len);
+
+private:
+    bool isInError() const;
+    ssize_t speculativeRead(unsigned char* readBuffer, size_t trySize);
+    void notifyAvailable();
+    uint32_t getRelativeBufferPos(uint32_t pos);
+    uint32_t getAvailableForWrite();
+    void advanceWrite();
+    void ensureConsumerFinishing();
+    void ensureType1Finished();
+    void ensureType3Finished();
+    int type1Write(uint32_t offset, size_t size);
+
+    unsigned char* m_tmpBuf;
+    size_t m_tmpBufSize;
+    size_t m_tmpBufXferSize;
+    bool m_usingTmpBuf;
+
+    unsigned char* m_readBuf;
+    size_t m_read;
+    size_t m_readLeft;
+
+    address_space_handle_t m_handle;
+    uint32_t m_version;
+    struct asg_context m_context;
+
+    uint64_t m_ringOffset;
+    uint64_t m_writeBufferOffset;
+
+    uint32_t m_writeBufferSize;
+    uint32_t m_writeBufferMask;
+    unsigned char* m_buf;
+    unsigned char* m_writeStart;
+    uint32_t m_writeStep;
+};
+
+#endif
diff --git a/system/OpenglSystemCommon/Android.mk b/system/OpenglSystemCommon/Android.mk
index e8af35b..98dc5d3 100644
--- a/system/OpenglSystemCommon/Android.mk
+++ b/system/OpenglSystemCommon/Android.mk
@@ -11,6 +11,7 @@
     FormatConversions.cpp \
     HostConnection.cpp \
     QemuPipeStream.cpp \
+    AddressSpaceStream.cpp \
     ProcessPipe.cpp    \
 
 LOCAL_CFLAGS += -Wno-unused-variable -Wno-unused-parameter
diff --git a/system/OpenglSystemCommon/CMakeLists.txt b/system/OpenglSystemCommon/CMakeLists.txt
index 25d2b6c..fb8fc56 100644
--- a/system/OpenglSystemCommon/CMakeLists.txt
+++ b/system/OpenglSystemCommon/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}/system/OpenglSystemCommon/Android.mk" "e8484748e692aa93eff0414a8e15ca19c75c3e333427c74a392d774872e56050")
-set(OpenglSystemCommon_src FormatConversions.cpp HostConnection.cpp QemuPipeStream.cpp ProcessPipe.cpp ThreadInfo_host.cpp)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/Android.mk" "0fe7f681af374ebed00868184abdad57ad606f31f12c91a2485d98feb282b62d")
+set(OpenglSystemCommon_src FormatConversions.cpp HostConnection.cpp QemuPipeStream.cpp AddressSpaceStream.cpp ProcessPipe.cpp ThreadInfo_host.cpp)
 android_add_shared_library(OpenglSystemCommon)
 target_include_directories(OpenglSystemCommon PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(OpenglSystemCommon 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")
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index 2cd1d38..6e604df 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -44,6 +44,7 @@
 
 #ifdef GOLDFISH_VULKAN
 #include "VkEncoder.h"
+#include "AddressSpaceStream.h"
 #else
 namespace goldfish_vk {
 struct VkEncoder {
@@ -51,6 +52,11 @@
     int placeholder;
 };
 } // namespace goldfish_vk
+using AddressSpaceStream = QemuPipeStream;
+AddressSpaceStream* createAddressSpaceStream(size_t bufSize) {
+    ALOGE("%s: FATAL: Trying to create ASG stream in unsupported build\n", __func__);
+    abort();
+}
 #endif
 
 using goldfish_vk::VkEncoder;
@@ -162,11 +168,22 @@
     if (!con) return con;
 
     const enum HostConnectionType connType = getConnectionTypeFromProperty();
+    // const enum HostConnectionType connType = HOST_CONNECTION_VIRTIO_GPU;
 
     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_ADDRESS_SPACE: {
+            AddressSpaceStream *stream = createAddressSpaceStream(STREAM_BUFFER_SIZE);
+            if (!stream) {
+                ALOGE("Failed to create AddressSpaceStream for host connection!!!\n");
+                delete con;
+                return NULL;
+            }
+            con->m_connectionType = HOST_CONNECTION_ADDRESS_SPACE;
+            con->m_stream = stream;
+            con->m_grallocHelper = &m_goldfishGralloc;
+            con->m_processPipe = &m_goldfishProcessPipe;
+            break;
+        }
         case HOST_CONNECTION_QEMU_PIPE: {
             QemuPipeStream *stream = new QemuPipeStream(STREAM_BUFFER_SIZE);
             if (!stream) {
@@ -233,6 +250,9 @@
             con->m_processPipe = stream->getProcessPipe();
             break;
         }
+#else
+        default:
+            break;
 #endif
     }
 
@@ -244,6 +264,8 @@
 
     ALOGD("HostConnection::get() New Host Connection established %p, tid %d\n",
           con, getCurrentThreadId());
+
+    // ALOGD("Address space echo latency check done\n");
     return con;
 }
 
diff --git a/system/OpenglSystemCommon/address_space_graphics_types.h b/system/OpenglSystemCommon/address_space_graphics_types.h
new file mode 100644
index 0000000..1ebad34
--- /dev/null
+++ b/system/OpenglSystemCommon/address_space_graphics_types.h
@@ -0,0 +1,354 @@
+// Copyright 2019 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/base/ring_buffer.h"
+
+#include <functional>
+
+// This file defines common types for address space graphics and provides
+// documentation.
+
+// Address space graphics======================================================
+//
+// Basic idea
+//
+// Address space graphics (ASG) is a subdevice of the address space device that
+// provides a way to run graphics commands and data with fewer VM exits by
+// leveraging shared memory ring buffers.
+//
+// Each GL/Vk thread in the guest is associated with a context (asg_context).
+// asg_context consists of pointers into the shared memory that view it as a
+// collection of ring buffers and a common write buffer.
+//
+// Consumer concept
+//
+// ASG does not assume a particular rendering backend (though we will use
+// RenderThread's). This is for ease of coding/testing and flexibility; the
+// implementation is not coupled to emugl/libOpenglRender.
+//
+// Instead, there is the concept of a "Consumer" of ASG that will do something
+// with the data arriving from the shared memory region, and possibly reply
+// back to the guest. We register functions to construct and deconstruct
+// Consumers as part of emulator init (setConsumer).
+//
+// Guest workflow
+//
+// 1. Open address space device
+//
+// 2. Create the graphics context as the subdevice
+//
+// 3. ping(ASG_GET_RING) to get the offset/size of the ring buffer admin. info
+//
+// 4. ping(ASG_GET_BUFFER) to get the offset/size of the shared transfer buffer.
+//
+// 5. ioctl(CLAIM_SHARED) and mmap on those two offset/size pairs to get a
+// guest-side mapping.
+//
+// 6. call asg_context_create on the ring and buffer pointers to create the asg_context.
+//
+// 7. Now the guest and host share asg_context pts and can communicate.
+//
+// 8. But usually the guest will sometimes need to ping(ASG_NOTIFY_AVAILABLE)
+// so that the host side (which is usually a separate thread that we don't want
+// to spin too much) wakes up and processes data.
+
+namespace android {
+namespace base {
+
+class Stream;
+
+} // namespace base
+} // namespace android
+
+#define ADDRESS_SPACE_GRAPHICS_DEVICE_ID 0
+#define ADDRESS_SPACE_GRAPHICS_PAGE_SIZE 4096
+#define ADDRESS_SPACE_GRAPHICS_BLOCK_SIZE (16ULL * 1048576ULL)
+
+// AddressSpaceGraphicsContext shares memory with
+// the guest via the following layout:
+extern "C" {
+
+struct asg_ring_storage { // directly shared with guest
+    char to_host[ADDRESS_SPACE_GRAPHICS_PAGE_SIZE];
+    char to_host_large_xfer[ADDRESS_SPACE_GRAPHICS_PAGE_SIZE];
+    char from_host_large_xfer[ADDRESS_SPACE_GRAPHICS_PAGE_SIZE];
+};
+
+// Set by the address space graphics device to notify the guest that the host
+// has slept or is able to consume something, or we are exiting, or there is an
+// error.
+enum asg_host_state {
+    // The host renderthread is asleep and needs to be woken up.
+    ASG_HOST_STATE_NEED_NOTIFY = 0,
+
+    // The host renderthread is active and can consume new data
+    // without notification.
+    ASG_HOST_STATE_CAN_CONSUME = 1,
+
+    // Normal exit
+    ASG_HOST_STATE_EXIT = 2,
+
+    // Error: Something weird happened and we need to exit.
+    ASG_HOST_STATE_ERROR = 3,
+};
+
+struct asg_ring_config;
+
+// Each context has a pair of ring buffers for communication
+// to and from the host. There is another ring buffer for large xfers
+// to the host (all xfers from the host are already considered "large").
+//
+// Each context also comes with _one_ auxiliary buffer to hold both its own
+// commands and to perform private DMA transfers.
+struct asg_context { // ptrs into RingStorage
+    struct ring_buffer* to_host;
+    char* buffer;
+    asg_host_state* host_state;
+    asg_ring_config* ring_config;
+    struct ring_buffer_with_view to_host_large_xfer;
+    struct ring_buffer_with_view from_host_large_xfer;
+};
+
+// Helper function that will be common between guest and host:
+// Given ring storage and a write buffer, returns asg_context that
+// is the correct view into it.
+static struct asg_context asg_context_create(
+    char* ring_storage,
+    char* buffer,
+    uint32_t buffer_size) {
+
+    struct asg_context res;
+
+    res.to_host =
+        reinterpret_cast<struct ring_buffer*>(
+            ring_storage +
+            offsetof(struct asg_ring_storage, to_host));
+    res.to_host_large_xfer.ring =
+        reinterpret_cast<struct ring_buffer*>(
+            ring_storage +
+            offsetof(struct asg_ring_storage, to_host_large_xfer));
+    res.from_host_large_xfer.ring =
+        reinterpret_cast<struct ring_buffer*>(
+            ring_storage +
+            offsetof(struct asg_ring_storage, from_host_large_xfer));
+
+    ring_buffer_init(res.to_host);
+
+    res.buffer = buffer;
+    res.host_state =
+        reinterpret_cast<asg_host_state*>(
+            &res.to_host->state);
+    res.ring_config =
+        reinterpret_cast<asg_ring_config*>(
+            res.to_host->config);
+
+    ring_buffer_view_init(
+        res.to_host_large_xfer.ring,
+        &res.to_host_large_xfer.view,
+        (uint8_t*)res.buffer, buffer_size);
+
+    ring_buffer_view_init(
+        res.from_host_large_xfer.ring,
+        &res.from_host_large_xfer.view,
+        (uint8_t*)res.buffer, buffer_size);
+
+    return res;
+}
+
+// During operation, the guest sends commands and data over the auxiliary
+// buffer while using the |to_host| ring to communicate what parts of the auxiliary
+// buffer is outstanding traffic needing to be consumed by the host.
+// After a transfer completes to the host, the host may write back data.
+// The guest then reads the results on the same auxiliary buffer
+// while being notified of which parts to read via the |from_host| ring.
+//
+// The size of the auxiliary buffer and flush interval is defined by
+// the following config.ini android_hw setting:
+//
+// 1) android_hw->hw_gltransport_asg_writeBufferSize
+// 2) android_hw->hw_gltransport_asg_writeStepSize
+//
+// 1) the size for the auxiliary buffer
+// 2) the step size over which commands are flushed to the host
+//
+// When transferring commands, command data is built up in writeStepSize
+// chunks and flushed to the host when either writeStepSize is reached or
+// the guest flushes explicitly.
+//
+// Command vs. Data Modes
+//
+// For command data larger than writeStepSize or when transferring data, we
+// fall back to using a different mode where the entire auxiliary buffer is
+// used to perform the transfer, |asg_writeBufferSize| steps at a time. The
+// host is also notified of the total transport size.
+//
+// When writing back to the guest, it is assumed that the write buffer will
+// be completely empty as the guest has already flushed and the host has
+// already consumed all commands/data, and is writing back. In this case,
+// the full auxiliary buffer is used at the same time for writing back to
+// the guest.
+//
+// Larger / Shared transfers
+//
+// Each of |to_host| and |from_host| can contain elements of type 1, 2, or 3:
+// Type 1: 8 bytes: 4 bytes offset, 4 bytes size. Relative to write buffer.
+struct __attribute__((__packed__)) asg_type1_xfer {
+    uint32_t offset;
+    uint32_t size;
+};
+// Type 2: 16 bytes: 16 bytes offset into address space PCI space, 8 bytes
+// size.
+struct __attribute__((__packed__)) asg_type2_xfer {
+    uint64_t physAddr;
+    uint64_t size;
+};
+// Type 3: There is a large transfer of known size and the entire write buffer
+// will be used to send it over.
+//
+// For type 1 transfers, we get the corresponding host virtual address by
+// adding the offset to the beginning of the write buffer.  For type 2
+// transfers, we need to calculate the guest physical address and then call
+// addressspacecontrolops.gethostptr, which is slower since it goes through
+// a data structure map of existing mappings.
+//
+// The rings never contain a mix of type 1 and 2 elements. For to_host,
+// the guest initiates changes between type 1 and 2.
+//
+// The config fields:
+//
+struct asg_ring_config {
+    // config[0]: size of the auxiliary buffer
+    uint32_t buffer_size;
+
+    // config[1]: flush interval for the auxiliary buffer
+    uint32_t flush_interval;
+
+    // the position of the interval in the auxiliary buffer
+    // that the host has read so far
+    uint32_t host_consumed_pos;
+
+    // the start of the places the guest might write to next
+    uint32_t guest_write_pos;
+
+    // 1 if transfers are of type 1, 2 if transfers of type 2,
+    // 3 if the overall transfer size is known and we are sending something large.
+    uint32_t transfer_mode;
+
+    // the size of the transfer, used if transfer size is known.
+    // Set before setting config[2] to 3.
+    uint32_t transfer_size;
+
+    // error state
+    uint32_t in_error;
+};
+
+// State/config changes may only occur if the ring is empty, or the state
+// is transitioning to Error. That way, the host and guest have a chance to
+// synchronize on the same state.
+//
+// Thus far we've established how commands and data are transferred
+// to and from the host. Next, let's discuss how AddressSpaceGraphicsContext
+// talks to the code that actually does something with the commands
+// and sends data back.
+
+} // extern "C"
+
+namespace android {
+namespace emulation {
+namespace asg {
+
+// Consumer Concept
+//
+// AddressSpaceGraphicsContext's are each associated with a consumer that
+// takes data off the auxiliary buffer and to_host, while sending back data
+// over the auxiliary buffer / from_host.
+//
+// will read the commands and write back data.
+//
+// The consumer type is fixed at startup. The interface is as follows:
+
+// Called by the consumer, implemented in AddressSpaceGraphicsContext:
+//
+// Called when the consumer doesn't find anything to
+// read in to_host. Will make the consumer sleep
+// until another Ping(NotifyAvailable).
+using OnUnavailableReadCallback =
+    std::function<int()>;
+
+// Unpacks a type 2 transfer into host pointer and size.
+using GetPtrCallback =
+    std::function<char*(uint64_t)>;
+
+struct ConsumerCallbacks {
+    OnUnavailableReadCallback onUnavailableRead;
+    GetPtrCallback getPtr;
+};
+
+using ConsumerCreateCallback =
+    std::function<void* (struct asg_context, ConsumerCallbacks)>;
+using ConsumerDestroyCallback =
+    std::function<void(void*)>;
+using ConsumerSaveCallback =
+    std::function<void(void*, base::Stream*)>;
+using ConsumerLoadCallback =
+    std::function<void(void*, base::Stream*)>;
+
+struct ConsumerInterface {
+    ConsumerCreateCallback create;
+    ConsumerDestroyCallback destroy;
+    ConsumerSaveCallback save;
+    ConsumerLoadCallback load;
+};
+
+} // namespace asg
+} // namespace emulation
+} // namespace android
+
+// The interface for the guest:
+
+extern "C" {
+// Handled outside in address_space_device.cpp:
+//
+// Ping(device id): Create the device. On the host, the two rings and
+// auxiliary buffer are allocated. The two rings are allocated up front.
+// Both the auxiliary buffers and the rings are allocated from blocks of
+// rings and auxiliary buffers. New blocks are created if we run out either
+// way.
+enum asg_command {
+    // Ping(get_ring): Returns, in the fields:
+    // metadata: offset to give to claimShared and mmap() in the guest
+    // size: size to give to claimShared and mmap() in the guest
+    ASG_GET_RING = 0,
+
+    // Ping(get_buffer): Returns, in the fields:
+    // metadata: offset to give to claimShared and mmap() in the guest
+    // size: size to give to claimShared and mmap() in the guest
+    ASG_GET_BUFFER = 1,
+
+    // Ping(set_version): Run after the guest reads and negotiates its
+    // version of the device with the host. The host now knows the guest's
+    // version and can proceed with a protocol that works for both.
+    // size (in): the version of the guest
+    // size (out): the version of the host
+    // After this command runs, the consumer is
+    // implicitly created.
+    ASG_SET_VERSION = 2,
+
+    // Ping(notiy_available): Wakes up the consumer from sleep so it
+    // can read data via toHost
+    ASG_NOTIFY_AVAILABLE = 3,
+};
+
+} // extern "C"