Merge "reland: virtio-gpu-asg transport"
diff --git a/shared/GoldfishAddressSpace/Android.bp b/shared/GoldfishAddressSpace/Android.bp
index 6dcdb56..4e8d31d 100644
--- a/shared/GoldfishAddressSpace/Android.bp
+++ b/shared/GoldfishAddressSpace/Android.bp
@@ -6,11 +6,13 @@
     ],
     shared_libs: [
         "liblog",
+        "libdrm",
     ],
     export_include_dirs: [
         "include",
     ],
     cflags: [
         "-DLOG_TAG=\"goldfish-address-space\"",
+        "-DVIRTIO_GPU",
     ],
 }
diff --git a/shared/GoldfishAddressSpace/include/goldfish_address_space.h b/shared/GoldfishAddressSpace/include/goldfish_address_space.h
index 044e18a..ad5e3cb 100644
--- a/shared/GoldfishAddressSpace/include/goldfish_address_space.h
+++ b/shared/GoldfishAddressSpace/include/goldfish_address_space.h
@@ -49,6 +49,7 @@
     Media = 1,
     HostMemoryAllocator = 5,
     SharedSlotsHostMemoryAllocator = 6,
+    VirtioGpuGraphics = 10,
 };
 
 class GoldfishAddressSpaceBlockProvider {
@@ -135,7 +136,7 @@
 // require different lifetime expectations versus GoldfishAddressSpaceBlock).
 
 // We also expose the ping info struct that is shared between host and guest.
-struct goldfish_address_space_ping {
+struct address_space_ping {
     uint64_t offset;
     uint64_t size;
     uint64_t metadata;
@@ -164,6 +165,97 @@
 void goldfish_address_space_unmap(void* ptr, uint64_t size);
 
 bool goldfish_address_space_set_subdevice_type(address_space_handle_t, GoldfishAddressSpaceSubdeviceType type, address_space_handle_t*);
-bool goldfish_address_space_ping(address_space_handle_t, struct goldfish_address_space_ping*);
+bool goldfish_address_space_ping(address_space_handle_t, struct address_space_ping*);
+
+// virtio-gpu version
+
+struct address_space_virtgpu_hostmem_info {
+    uint32_t id;
+    uint32_t bo;
+    void* ptr;
+};
+
+struct address_space_virtgpu_info {
+    int fd;
+    uint32_t resp_bo;
+    uint32_t resp_resid;
+    void* resp_mapped_ptr;
+};
+
+address_space_handle_t virtgpu_address_space_open();
+void virtgpu_address_space_close(address_space_handle_t);
+
+// Ping with no response
+bool virtgpu_address_space_ping(address_space_handle_t, struct address_space_ping*);
+
+bool virtgpu_address_space_create_context_with_subdevice(
+    address_space_handle_t,
+    uint32_t subdevice_type,
+    struct address_space_virtgpu_info* info_out);
+
+bool virtgpu_address_space_allocate_hostmem(
+    address_space_handle_t fd,
+    size_t size,
+    uint64_t hostmem_id,
+    struct address_space_virtgpu_hostmem_info* hostmem_info_out);
+
+// Ping with response
+bool virtgpu_address_space_ping_with_response(
+    struct address_space_virtgpu_info* info,
+    struct address_space_ping* ping);
+
+// typedef/struct to abstract over goldfish vs virtio-gpu implementations
+typedef address_space_handle_t (*address_space_open_t)(void);
+typedef void (*address_space_close_t)(address_space_handle_t);
+
+typedef bool (*address_space_allocate_t)(
+    address_space_handle_t, size_t size, uint64_t* phys_addr, uint64_t* offset);
+typedef bool (*address_space_free_t)(
+    address_space_handle_t, uint64_t offset);
+
+typedef bool (*address_space_claim_shared_t)(
+    address_space_handle_t, uint64_t offset, uint64_t size);
+typedef bool (*address_space_unclaim_shared_t)(
+    address_space_handle_t, uint64_t offset);
+
+// pgoff is the offset into the page to return in the result
+typedef void* (*address_space_map_t)(
+    address_space_handle_t, uint64_t offset, uint64_t size, uint64_t pgoff);
+typedef void (*address_space_unmap_t)(void* ptr, uint64_t size);
+
+typedef bool (*address_space_set_subdevice_type_t)(
+    address_space_handle_t, GoldfishAddressSpaceSubdeviceType type, address_space_handle_t*);
+typedef bool (*address_space_ping_t)(
+    address_space_handle_t, struct address_space_ping*);
+
+// Specific to virtio-gpu
+typedef bool (*address_space_create_context_with_subdevice_t)(
+    address_space_handle_t,
+    uint32_t subdevice_type,
+    struct address_space_virtgpu_info* info_out);
+
+typedef bool (*address_space_allocate_hostmem_t)(
+    address_space_handle_t fd,
+    size_t size,
+    uint64_t hostmem_id,
+    struct address_space_virtgpu_hostmem_info* hostmem_info_out);
+
+typedef bool (*address_space_ping_with_response_t)(
+    struct address_space_virtgpu_info* info,
+    struct address_space_ping* ping);
+
+struct address_space_ops {
+    address_space_open_t open;
+    address_space_close_t close;
+    address_space_claim_shared_t claim_shared;
+    address_space_unclaim_shared_t unclaim_shared;
+    address_space_map_t map;
+    address_space_unmap_t unmap;
+    address_space_set_subdevice_type_t set_subdevice_type;
+    address_space_ping_t ping;
+    address_space_create_context_with_subdevice_t create_context_with_subdevice;
+    address_space_allocate_hostmem_t allocate_hostmem;
+    address_space_ping_with_response_t ping_with_response;
+};
 
 #endif  // #ifndef ANDROID_INCLUDE_HARDWARE_GOLDFISH_ADDRESS_SPACE_H
diff --git a/shared/GoldfishAddressSpace/include/goldfish_address_space_android.impl b/shared/GoldfishAddressSpace/include/goldfish_address_space_android.impl
index 8ff7e78..a8a70af 100644
--- a/shared/GoldfishAddressSpace/include/goldfish_address_space_android.impl
+++ b/shared/GoldfishAddressSpace/include/goldfish_address_space_android.impl
@@ -25,9 +25,15 @@
 #include <errno.h>
 #include <memory>
 
+#ifdef VIRTIO_GPU
+#include <drm/virtgpu_drm.h>
+#include <xf86drm.h>
+#endif
+
 #include <log/log.h>
 
 #include "goldfish_address_space.h"
+#include "virtio_gpu_next.h"
 
 namespace {
 
@@ -46,7 +52,7 @@
 #define GOLDFISH_ADDRESS_SPACE_IOCTL_OP(OP, T)		_IOWR(GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC, OP, T)
 #define GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(10, struct goldfish_address_space_allocate_block)
 #define GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(11, __u64)
-#define GOLDFISH_ADDRESS_SPACE_IOCTL_PING		GOLDFISH_ADDRESS_SPACE_IOCTL_OP(12, struct goldfish_address_space_ping)
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_PING		GOLDFISH_ADDRESS_SPACE_IOCTL_OP(12, struct address_space_ping)
 #define GOLDFISH_ADDRESS_SPACE_IOCTL_CLAIM_SHARED		GOLDFISH_ADDRESS_SPACE_IOCTL_OP(13, struct goldfish_address_space_claim_shared)
 #define GOLDFISH_ADDRESS_SPACE_IOCTL_UNCLAIM_SHARED		GOLDFISH_ADDRESS_SPACE_IOCTL_OP(14, __u64)
 
@@ -70,14 +76,14 @@
     return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK, &offset);
 }
 
-long ioctl_ping(int fd, struct goldfish_address_space_ping *request)
+long ioctl_ping(int fd, struct address_space_ping *request)
 {
     return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_PING, request);
 }
 
 long set_address_space_subdevice_type(int fd, uint64_t type)
 {
-    struct goldfish_address_space_ping request;
+    struct address_space_ping request;
     ::memset(&request, 0, sizeof(request));
     request.version = sizeof(request);
     request.metadata = type;
@@ -359,7 +365,7 @@
         return -ENODEV;
     }
 
-    struct goldfish_address_space_ping request;
+    struct address_space_ping request;
     if (m_useSharedSlots) {
         // shared memory slots are supported
         ::memset(&request, 0, sizeof(request));
@@ -415,7 +421,7 @@
     }
 
     if (block->guestPtr()) {
-        struct goldfish_address_space_ping request;
+        struct address_space_ping request;
         ::memset(&request, 0, sizeof(request));
         request.version = sizeof(request);
         request.offset = block->offset();
@@ -517,7 +523,7 @@
 bool goldfish_address_space_set_subdevice_type(
     address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
     address_space_handle_t* handle_out) {
-    struct goldfish_address_space_ping request;
+    struct address_space_ping request;
     request.metadata = (uint64_t)type;
     *handle_out = handle;
     return goldfish_address_space_ping(handle, &request);
@@ -525,7 +531,7 @@
 
 bool goldfish_address_space_ping(
     address_space_handle_t handle,
-    struct goldfish_address_space_ping* ping) {
+    struct address_space_ping* ping) {
     long res = ioctl_ping(handle, ping);
 
     if (res) {
@@ -535,3 +541,240 @@
 
     return true;
 }
+
+// virtio-gpu version
+address_space_handle_t virtgpu_address_space_open() {
+return drmOpenRender(128);
+}
+
+void virtgpu_address_space_close(address_space_handle_t fd) {
+close(fd);
+}
+
+// kVirtioGpuAddressSpaceContextCreateWithSubdevice | subdeviceType
+const uint32_t kVirtioGpuAddressSpaceContextCreateWithSubdevice = 0x1001;
+
+// kVirtioGpuAddressSpacePing | offset_lo | offset_hi | size_lo | size_hi | metadata_lo | metadata_hi | version | wait_fd | wait_flags | direction
+// no output
+const uint32_t kVirtioGpuAddressSpacePing = 0x1002;
+
+// kVirtioGpuAddressSpacePingWithResponse | resp_resid | offset_lo | offset_hi | metadata_lo | metadata_hi | version | wait_fd | wait_flags | direction
+// out: same as input then | out: error
+const uint32_t kVirtioGpuAddressSpacePingWithResponse = 0x1003;
+
+// Ping with no response
+bool virtgpu_address_space_ping(address_space_handle_t fd, struct address_space_ping* info) {
+
+    uint32_t words[] = {
+        kVirtioGpuAddressSpacePing,
+        (uint32_t)(info->offset), (uint32_t)(info->offset >> 32),
+        (uint32_t)(info->size), (uint32_t)(info->size >> 32),
+        (uint32_t)(info->metadata), (uint32_t)(info->metadata >> 32),
+        (uint32_t)(info->version), (uint32_t)(info->wait_fd),
+        (uint32_t)(info->wait_flags), (uint32_t)(info->direction),
+    };
+
+    drm_virtgpu_execbuffer execbuffer = {
+        .flags = 0,
+        .size = sizeof(words),
+        .command = (uint64_t)(uintptr_t)(words),
+        .bo_handles = 0,
+        .num_bo_handles = 0,
+        .fence_fd = -1,
+    };
+
+    int queue_work_err = drmIoctl(fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &execbuffer);
+
+    if (queue_work_err) {
+        ALOGE("%s: failed with %d executing command buffer (%s)\n",  __func__,
+                queue_work_err, strerror(errno));
+        return false;
+    }
+
+    return true;
+}
+
+bool virtgpu_address_space_create_context_with_subdevice(
+    address_space_handle_t fd,
+    uint32_t subdevice_type,
+    struct address_space_virtgpu_info* info_out) {
+
+    // response page
+    drm_virtgpu_resource_create create = {
+        .target     = PIPE_BUFFER,
+        .format     = VIRGL_FORMAT_R8_UNORM,
+        .bind       = VIRGL_BIND_CUSTOM,
+        .width      = 4096,
+        .height     = 1U,
+        .depth      = 1U,
+        .array_size = 0U,
+        .size       = 4096,
+        .stride     = 4096,
+    };
+
+    int ret = drmIoctl(fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE, &create);
+    if (ret) {
+        ALOGE("%s: failed with %d allocating command buffer (%s)\n",
+                __func__, ret, strerror(errno));
+        return false;
+    }
+
+    drm_virtgpu_map map = {
+        .handle = create.bo_handle,
+    };
+
+    ret = drmIoctl(fd, DRM_IOCTL_VIRTGPU_MAP, &map);
+    if (ret) {
+        ALOGE("%s: failed with %d mapping command response buffer (%s)\n",
+            __func__, ret, strerror(errno));
+        return false;
+    }
+
+    void* ptr = static_cast<unsigned char*>(
+            mmap64(nullptr, 4096, PROT_WRITE, MAP_SHARED, fd, map.offset));
+
+    if (ptr == MAP_FAILED) {
+        ALOGE("%s: failed with %d mmap'ing command response buffer (%s)\n",
+                __func__, errno, strerror(errno));
+        return false;
+    }
+
+    info_out->fd = fd;
+    info_out->resp_bo = create.bo_handle;
+    info_out->resp_resid = create.res_handle;
+    info_out->resp_mapped_ptr = ptr;
+
+    ALOGD("%s: resp bo: %u resid %u mapped %p\n", __func__,
+            create.bo_handle, create.res_handle, ptr);
+
+    // Context creation command
+    uint32_t words[] = {
+        kVirtioGpuAddressSpaceContextCreateWithSubdevice,
+        subdevice_type,
+    };
+
+    drm_virtgpu_execbuffer execbuffer = {
+        .flags = 0,
+        .size = sizeof(words),
+        .command = (uint64_t)(uintptr_t)(words),
+        .bo_handles = 0,
+        .num_bo_handles = 0,
+        .fence_fd = -1,
+    };
+
+    int queue_work_err = drmIoctl(fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &execbuffer);
+
+    if (queue_work_err) {
+        ALOGE("%s: failed with %d executing command buffer (%s)\n",  __func__,
+                queue_work_err, strerror(errno));
+        return false;
+    }
+
+    return true;
+}
+
+bool virtgpu_address_space_allocate_hostmem(
+    address_space_handle_t fd,
+    size_t size,
+    uint64_t hostmem_id,
+    struct address_space_virtgpu_hostmem_info* hostmem_info_out) {
+
+    struct drm_virtgpu_resource_create_blob drm_rc_blob = { 0 };
+    drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_HOST;
+    drm_rc_blob.blob_flags = VIRTGPU_BLOB_FLAG_MAPPABLE;
+    drm_rc_blob.blob_id = hostmem_id;
+    drm_rc_blob.size = size;
+
+    int res = drmIoctl(
+            fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &drm_rc_blob);
+
+    if (res) {
+        ALOGE("%s: Failed to resource create v2: sterror: %s errno: %d\n", __func__,
+                strerror(errno), errno);
+        abort();
+    }
+
+    struct drm_virtgpu_map map_info = {
+        .handle = drm_rc_blob.bo_handle,
+    };
+
+    res = drmIoctl(fd, DRM_IOCTL_VIRTGPU_MAP, &map_info);
+    if (res) {
+        ALOGE("%s: Failed to virtgpu map: sterror: %s errno: %d\n", __func__,
+                strerror(errno), errno);
+        abort();
+    }
+
+    void* directMappedAddr = mmap64(0, size, PROT_WRITE, MAP_SHARED, fd, map_info.offset);
+
+    if (!directMappedAddr) {
+        ALOGE("%s: mmap of virtio gpu resource failed\n", __func__);
+        abort();
+    }
+
+    hostmem_info_out->id = hostmem_id;
+    hostmem_info_out->bo = drm_rc_blob.bo_handle;
+    hostmem_info_out->ptr = directMappedAddr;
+    return true;
+}
+
+uint64_t buildu64(uint32_t lo, uint32_t hi) {
+    uint64_t res = (uint64_t)lo;
+    uint64_t hi64 = (uint64_t)hi;
+    return res | (hi64 << 32);
+}
+
+// Ping with response
+bool virtgpu_address_space_ping_with_response(
+    struct address_space_virtgpu_info* info,
+    struct address_space_ping* ping) {
+
+    uint32_t words[] = {
+        kVirtioGpuAddressSpacePingWithResponse,
+        info->resp_resid,
+        (uint32_t)(ping->offset), (uint32_t)(ping->offset >> 32),
+        (uint32_t)(ping->size), (uint32_t)(ping->size >> 32),
+        (uint32_t)(ping->metadata), (uint32_t)(ping->metadata >> 32),
+        (uint32_t)(ping->version), (uint32_t)(ping->wait_fd),
+        (uint32_t)(ping->wait_flags), (uint32_t)(ping->direction),
+    };
+
+    drm_virtgpu_execbuffer execbuffer = {
+        .flags = 0,
+        .size = sizeof(words),
+        .command = (uint64_t)(uintptr_t)(words),
+        .bo_handles = (uint64_t)(uintptr_t)(&info->resp_bo),
+        .num_bo_handles = 1,
+        .fence_fd = -1,
+    };
+
+    int queue_work_err = drmIoctl(info->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &execbuffer);
+
+    if (queue_work_err) {
+        ALOGE("%s: failed with %d executing command buffer (%s)\n",  __func__,
+                queue_work_err, strerror(errno));
+        return false;
+    }
+
+    struct drm_virtgpu_3d_wait waitcmd;
+    memset(&waitcmd, 0, sizeof(waitcmd));
+    waitcmd.handle = info->resp_bo;
+
+    int ret = drmIoctl(info->fd, DRM_IOCTL_VIRTGPU_WAIT, &waitcmd);
+    if (ret) {
+        ALOGE("%s: DRM_IOCTL_VIRTGPU_WAIT failed with %d (%s)\n", __func__, errno, strerror(errno));
+        return false;
+    }
+
+    uint32_t* respWords = (uint32_t*)info->resp_mapped_ptr;
+   
+    ping->offset = buildu64(respWords[0], respWords[1]);
+    ping->size = buildu64(respWords[2], respWords[3]);
+    ping->metadata = buildu64(respWords[4], respWords[5]);
+    ping->version = respWords[6];
+    ping->wait_fd = respWords[7];
+    ping->wait_flags = respWords[8];
+    ping->direction = respWords[9];
+
+    return true;
+}
diff --git a/shared/GoldfishAddressSpace/include/goldfish_address_space_host.impl b/shared/GoldfishAddressSpace/include/goldfish_address_space_host.impl
index 8995c6b..d1fa4a3 100644
--- a/shared/GoldfishAddressSpace/include/goldfish_address_space_host.impl
+++ b/shared/GoldfishAddressSpace/include/goldfish_address_space_host.impl
@@ -377,7 +377,7 @@
 bool goldfish_address_space_set_subdevice_type(
     address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
     address_space_handle_t* handle_out) {
-    struct goldfish_address_space_ping request;
+    struct address_space_ping request;
     request.metadata = (uint64_t)type;
     *handle_out = handle;
     return goldfish_address_space_ping(handle, &request);
@@ -385,7 +385,7 @@
 
 bool goldfish_address_space_ping(
     address_space_handle_t handle,
-    struct goldfish_address_space_ping* ping) {
+    struct address_space_ping* ping) {
 
     AddressSpaceDevicePingInfo* asHostPingInfo =
         reinterpret_cast<AddressSpaceDevicePingInfo*>(ping);
diff --git a/shared/GoldfishAddressSpace/include/virtio_gpu_next.h b/shared/GoldfishAddressSpace/include/virtio_gpu_next.h
new file mode 100644
index 0000000..610dc51
--- /dev/null
+++ b/shared/GoldfishAddressSpace/include/virtio_gpu_next.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2020 The Android Open Source Project
+// Copyright (C) 2020 Google Inc.
+//
+// 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
+
+#ifndef HOST_BUILD
+#include "drm.h"
+#endif
+
+#define PIPE_BUFFER             0
+#define VIRGL_FORMAT_R8_UNORM   64
+#define VIRGL_BIND_CUSTOM       (1 << 17)
+
+#define DRM_VIRTGPU_RESOURCE_CREATE_BLOB 0x0a
+
+#define VIRTGPU_PARAM_RESOURCE_BLOB 3 /* DRM_VIRTGPU_RESOURCE_CREATE_BLOB */
+#define VIRTGPU_PARAM_HOST_VISIBLE 4
+
+struct drm_virtgpu_resource_create_blob {
+#define VIRTGPU_BLOB_MEM_GUEST              0x0001
+#define VIRTGPU_BLOB_MEM_HOST               0x0002
+#define VIRTGPU_BLOB_MEM_HOST_GUEST         0x0003
+
+#define VIRTGPU_BLOB_FLAG_MAPPABLE          0x0001
+#define VIRTGPU_BLOB_FLAG_SHAREABLE         0x0002
+#define VIRTGPU_BLOB_FLAG_CROSS_DEVICE      0x0004
+	/* zero is invalid blob_mem */
+    uint32_t blob_mem;
+    uint32_t blob_flags;
+    uint32_t bo_handle;
+    uint32_t res_handle;
+    uint64_t size;
+
+	/*
+	 * for 3D contexts with VIRTGPU_BLOB_MEM_HOSTGUEST and
+	 * VIRTGPU_BLOB_MEM_HOST otherwise, must be zero.
+	 */
+	uint32_t pad;
+    uint32_t cmd_size;
+    uint64_t cmd;
+    uint64_t blob_id;
+};
+
+
+#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB              \
+        DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE_BLOB,   \
+                        struct drm_virtgpu_resource_create_blob)
diff --git a/system/OpenglSystemCommon/AddressSpaceStream.cpp b/system/OpenglSystemCommon/AddressSpaceStream.cpp
index 3f066f3..df34adc 100644
--- a/system/OpenglSystemCommon/AddressSpaceStream.cpp
+++ b/system/OpenglSystemCommon/AddressSpaceStream.cpp
@@ -42,7 +42,7 @@
         return nullptr;
     }
 
-    struct goldfish_address_space_ping request;
+    struct address_space_ping request;
     request.metadata = ASG_GET_RING;
     if (!goldfish_address_space_ping(child_device_handle, &request)) {
         ALOGE("AddressSpaceStream::create failed (get ring)\n");
@@ -123,21 +123,156 @@
     context.ring_config->host_consumed_pos = 0;
     context.ring_config->guest_write_pos = 0;
 
+    struct address_space_ops ops = {
+        .open = goldfish_address_space_open,
+        .close = goldfish_address_space_close,
+        .claim_shared = goldfish_address_space_claim_shared,
+        .unclaim_shared = goldfish_address_space_unclaim_shared,
+        .map = goldfish_address_space_map,
+        .unmap = goldfish_address_space_unmap,
+        .set_subdevice_type = goldfish_address_space_set_subdevice_type,
+        .ping = goldfish_address_space_ping,
+    };
+
     AddressSpaceStream* res =
         new AddressSpaceStream(
             child_device_handle, version, context,
-            ringOffset, bufferOffset);
+            ringOffset, bufferOffset, false /* not virtio */, ops);
 
     return res;
 }
 
+#ifdef HOST_BUILD
+AddressSpaceStream* createVirtioGpuAddressSpaceStream(size_t ignored_bufSize) {
+    // Ignore incoming ignored_bufSize
+    (void)ignored_bufSize;
+    return nullptr;
+}
+#else
+AddressSpaceStream* createVirtioGpuAddressSpaceStream(size_t ignored_bufSize) {
+    // Ignore incoming ignored_bufSize
+    (void)ignored_bufSize;
+
+    auto handle = virtgpu_address_space_open();
+
+    if (handle <= 0) {
+        ALOGE("AddressSpaceStream::create failed (open device)\n");
+        return nullptr;
+    }
+
+    struct address_space_virtgpu_info virtgpu_info;
+
+    ALOGD("%s: create subdevice and get resp\n", __func__);
+    if (!virtgpu_address_space_create_context_with_subdevice(
+            handle, GoldfishAddressSpaceSubdeviceType::VirtioGpuGraphics,
+            &virtgpu_info)) {
+        ALOGE("AddressSpaceStream::create failed (create subdevice)\n");
+        virtgpu_address_space_close(handle);
+        return nullptr;
+    }
+    ALOGD("%s: create subdevice and get resp (done)\n", __func__);
+
+    struct address_space_ping request;
+    uint32_t ringSize = 0;
+    uint32_t bufferSize = 0;
+
+    request.metadata = ASG_GET_RING;
+    if (!virtgpu_address_space_ping_with_response(
+        &virtgpu_info, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get ring version)\n");
+        virtgpu_address_space_close(handle);
+        return nullptr;
+    }
+    ringSize = request.size;
+
+    request.metadata = ASG_GET_BUFFER;
+    if (!virtgpu_address_space_ping_with_response(
+        &virtgpu_info, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get ring version)\n");
+        virtgpu_address_space_close(handle);
+        return nullptr;
+    }
+    bufferSize = request.size;
+
+    request.metadata = ASG_SET_VERSION;
+    request.size = 1; // version 1
+
+    if (!virtgpu_address_space_ping_with_response(
+        &virtgpu_info, &request)) {
+        ALOGE("AddressSpaceStream::create failed (set version)\n");
+        virtgpu_address_space_close(handle);
+        return nullptr;
+    }
+
+    ALOGD("%s: ping returned. context ring and buffer sizes %u %u\n", __func__,
+            ringSize, bufferSize);
+
+    uint64_t hostmem_id = request.metadata;
+    uint32_t version = request.size;
+    size_t hostmem_alloc_size =
+        (size_t)(ringSize + bufferSize);
+
+    ALOGD("%s: hostmem size: %zu\n", __func__, hostmem_alloc_size);
+
+    struct address_space_virtgpu_hostmem_info hostmem_info;
+    if (!virtgpu_address_space_allocate_hostmem(
+            handle,
+            hostmem_alloc_size,
+            hostmem_id,
+            &hostmem_info)) {
+        ALOGE("AddressSpaceStream::create failed (alloc hostmem)\n");
+        virtgpu_address_space_close(handle);
+        return nullptr;
+    }
+
+    request.metadata = ASG_GET_CONFIG;
+    if (!virtgpu_address_space_ping_with_response(
+        &virtgpu_info, &request)) {
+        ALOGE("AddressSpaceStream::create failed (get config)\n");
+        virtgpu_address_space_close(handle);
+        return nullptr;
+    }
+
+    char* ringPtr = (char*)hostmem_info.ptr;
+    char* bufferPtr = ((char*)hostmem_info.ptr) + sizeof(struct asg_ring_storage);
+
+    struct asg_context context =
+        asg_context_create(
+            (char*)ringPtr, (char*)bufferPtr, bufferSize);
+
+    context.ring_config->transfer_mode = 1;
+    context.ring_config->host_consumed_pos = 0;
+    context.ring_config->guest_write_pos = 0;
+
+    struct address_space_ops ops = {
+        .open = virtgpu_address_space_open,
+        .close = virtgpu_address_space_close,
+        .ping = virtgpu_address_space_ping,
+        .allocate_hostmem = virtgpu_address_space_allocate_hostmem,
+        .ping_with_response = virtgpu_address_space_ping_with_response,
+    };
+
+    AddressSpaceStream* res =
+        new AddressSpaceStream(
+            handle, version, context,
+            0, 0, true /* is virtio */, ops);
+
+    return res;
+}
+#endif
+
+
 AddressSpaceStream::AddressSpaceStream(
     address_space_handle_t handle,
     uint32_t version,
     struct asg_context context,
     uint64_t ringOffset,
-    uint64_t writeBufferOffset) :
+    uint64_t writeBufferOffset,
+    bool virtioMode,
+    struct address_space_ops ops) :
     IOStream(context.ring_config->flush_interval),
+    m_virtioMode(virtioMode),
+    m_ops(ops),
     m_tmpBuf(0),
     m_tmpBufSize(0),
     m_tmpBufXferSize(0),
@@ -163,11 +298,13 @@
 }
 
 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_virtioMode) {
+        m_ops.unmap(m_context.to_host, sizeof(struct asg_ring_storage));
+        m_ops.unmap(m_context.buffer, m_writeBufferSize);
+        m_ops.unclaim_shared(m_handle, m_ringOffset);
+        m_ops.unclaim_shared(m_handle, m_writeBufferOffset);
+    }
+    m_ops.close(m_handle);
     if (m_readBuf) free(m_readBuf);
     if (m_tmpBuf) free(m_tmpBuf);
 }
@@ -433,9 +570,9 @@
 }
 
 void AddressSpaceStream::notifyAvailable() {
-    struct goldfish_address_space_ping request;
+    struct address_space_ping request;
     request.metadata = ASG_NOTIFY_AVAILABLE;
-    goldfish_address_space_ping(m_handle, &request);
+    m_ops.ping(m_handle, &request);
     ++m_notifs;
 }
 
diff --git a/system/OpenglSystemCommon/AddressSpaceStream.h b/system/OpenglSystemCommon/AddressSpaceStream.h
index a4db5aa..3d60695 100644
--- a/system/OpenglSystemCommon/AddressSpaceStream.h
+++ b/system/OpenglSystemCommon/AddressSpaceStream.h
@@ -24,6 +24,7 @@
 class AddressSpaceStream;
 
 AddressSpaceStream* createAddressSpaceStream(size_t bufSize);
+AddressSpaceStream* createVirtioGpuAddressSpaceStream(size_t bufSize);
 
 class AddressSpaceStream : public IOStream {
 public:
@@ -32,7 +33,9 @@
         uint32_t version,
         struct asg_context context,
         uint64_t ringOffset,
-        uint64_t writeBufferOffset);
+        uint64_t writeBufferOffset,
+        bool virtioMode,
+        struct address_space_ops ops);
     ~AddressSpaceStream();
 
     virtual size_t idealAllocSize(size_t len);
@@ -43,6 +46,11 @@
     virtual int writeFully(const void *buf, size_t len);
     virtual const unsigned char *commitBufferAndReadFully(size_t size, void *buf, size_t len);
 
+    int getRendernodeFd() const {
+        if (!m_virtioMode) return -1;
+        return m_handle;
+    }
+
 private:
     bool isInError() const;
     ssize_t speculativeRead(unsigned char* readBuffer, size_t trySize);
@@ -54,6 +62,9 @@
     void ensureType3Finished();
     int type1Write(uint32_t offset, size_t size);
 
+    bool m_virtioMode;
+    struct address_space_ops m_ops;
+
     unsigned char* m_tmpBuf;
     size_t m_tmpBufSize;
     size_t m_tmpBufXferSize;
diff --git a/system/OpenglSystemCommon/EmulatorFeatureInfo.h b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
index f1505fe..7545e5a 100644
--- a/system/OpenglSystemCommon/EmulatorFeatureInfo.h
+++ b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
@@ -154,6 +154,7 @@
     HOST_CONNECTION_VIRTIO_GPU = 2,
     HOST_CONNECTION_ADDRESS_SPACE = 3,
     HOST_CONNECTION_VIRTIO_GPU_PIPE = 4,
+    HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE = 5,
 };
 
 enum GrallocType {
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index 72ea1f0..8ab05ea 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -58,6 +58,10 @@
     ALOGE("%s: FATAL: Trying to create ASG stream in unsupported build\n", __func__);
     abort();
 }
+AddressSpaceStream* createVirtioGpuAddressSpaceStream(size_t bufSize) {
+    ALOGE("%s: FATAL: Trying to create virtgpu ASG stream in unsupported build\n", __func__);
+    abort();
+}
 #endif
 
 using goldfish_vk::VkEncoder;
@@ -112,6 +116,7 @@
     if (!strcmp("virtio-gpu", transportValue)) return HOST_CONNECTION_VIRTIO_GPU;
     if (!strcmp("asg", transportValue)) return HOST_CONNECTION_ADDRESS_SPACE;
     if (!strcmp("virtio-gpu-pipe", transportValue)) return HOST_CONNECTION_VIRTIO_GPU_PIPE;
+    if (!strcmp("virtio-gpu-asg", transportValue)) return HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
 
     return HOST_CONNECTION_QEMU_PIPE;
 #endif
@@ -491,7 +496,7 @@
             con->m_grallocType = getGrallocTypeFromProperty();
             con->m_stream = stream;
             con->m_rendernodeFdOwned = false;
-            con->m_rendernodeFdOwned = stream->getRendernodeFd();
+            con->m_rendernodeFd = stream->getRendernodeFd();
             switch (con->m_grallocType) {
                 case GRALLOC_TYPE_RANCHU:
                     con->m_grallocHelper = &m_goldfishGralloc;
@@ -509,6 +514,37 @@
             con->m_processPipe = &m_goldfishProcessPipe;
             break;
         }
+#ifndef HOST_BUILD
+        case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
+            AddressSpaceStream *stream = createVirtioGpuAddressSpaceStream(STREAM_BUFFER_SIZE);
+            if (!stream) {
+                ALOGE("Failed to create virtgpu AddressSpaceStream for host connection!!!\n");
+                delete con;
+                return NULL;
+            }
+            con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
+            con->m_grallocType = getGrallocTypeFromProperty();
+            con->m_stream = stream;
+            con->m_rendernodeFdOwned = false;
+            con->m_rendernodeFd = stream->getRendernodeFd();
+            switch (con->m_grallocType) {
+                case GRALLOC_TYPE_RANCHU:
+                    con->m_grallocHelper = &m_goldfishGralloc;
+                    break;
+                case GRALLOC_TYPE_MINIGBM: {
+                    MinigbmGralloc* m = new MinigbmGralloc;
+                    m->setFd(stream->getRendernodeFd());
+                    con->m_grallocHelper = m;
+                    break;
+                }
+                default:
+                    ALOGE("Fatal: Unknown gralloc type 0x%x\n", con->m_grallocType);
+                    abort();
+            }
+            con->m_processPipe = &m_goldfishProcessPipe;
+            break;
+        }
+#endif // !HOST_BUILD
 #else
         default:
             break;
diff --git a/system/OpenglSystemCommon/ProcessPipe.cpp b/system/OpenglSystemCommon/ProcessPipe.cpp
index 84764f4..0d74789 100644
--- a/system/OpenglSystemCommon/ProcessPipe.cpp
+++ b/system/OpenglSystemCommon/ProcessPipe.cpp
@@ -166,7 +166,8 @@
         case HOST_CONNECTION_VIRTIO_GPU:
             sQemuPipeInit();
             break;
-        case HOST_CONNECTION_VIRTIO_GPU_PIPE: {
+        case HOST_CONNECTION_VIRTIO_GPU_PIPE:
+        case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
             sVirtioGpuPipeStream = new VirtioGpuPipeStream(4096);
             sProcUID = sVirtioGpuPipeStream->initProcessPipe();
             break;
diff --git a/system/OpenglSystemCommon/address_space_graphics_types.h b/system/OpenglSystemCommon/address_space_graphics_types.h
index 1ebad34..5f0e9b6 100644
--- a/system/OpenglSystemCommon/address_space_graphics_types.h
+++ b/system/OpenglSystemCommon/address_space_graphics_types.h
@@ -342,6 +342,7 @@
     // 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
+    // metadata (out): hostmem id
     // After this command runs, the consumer is
     // implicitly created.
     ASG_SET_VERSION = 2,
@@ -349,6 +350,9 @@
     // Ping(notiy_available): Wakes up the consumer from sleep so it
     // can read data via toHost
     ASG_NOTIFY_AVAILABLE = 3,
+
+    // Retrieve the host config
+    ASG_GET_CONFIG = 4,
 };
 
 } // extern "C"
diff --git a/system/codecs/omx/common/Android.mk b/system/codecs/omx/common/Android.mk
index 9e233e7..4daf0b7 100644
--- a/system/codecs/omx/common/Android.mk
+++ b/system/codecs/omx/common/Android.mk
@@ -33,6 +33,15 @@
 $(call emugl-import,libGoldfishAddressSpace$(GOLDFISH_OPENGL_LIB_SUFFIX))
 else
 $(call emugl-export,STATIC_LIBRARIES,libGoldfishAddressSpace)
+
+ifeq (true,$(BUILD_EMULATOR_VULKAN))
+
+LOCAL_CFLAGS += -DVIRTIO_GPU
+LOCAL_C_INCLUDES += external/libdrm external/minigbm/cros_gralloc
+LOCAL_SHARED_LIBRARIES += libdrm
+
+endif
+
 endif
 
 $(call emugl-end-module)
diff --git a/system/codecs/omx/common/goldfish_media_utils.cpp b/system/codecs/omx/common/goldfish_media_utils.cpp
index a2057ab..4f4ead0 100644
--- a/system/codecs/omx/common/goldfish_media_utils.cpp
+++ b/system/codecs/omx/common/goldfish_media_utils.cpp
@@ -123,7 +123,7 @@
         mStartPtr = goldfish_address_space_map(mHandle, mOffset, mSize);
         ALOGI("guest address is %p", mStartPtr);
 
-        struct goldfish_address_space_ping pingInfo;
+        struct address_space_ping pingInfo;
         pingInfo.metadata = GoldfishAddressSpaceSubdeviceType::Media;
         pingInfo.offset = mOffset;
         if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
@@ -185,7 +185,7 @@
 
 bool GoldfishMediaTransportImpl::sendOperation(MediaCodecType type,
                                                MediaOperation op, unsigned int offSetToStartAddr) {
-    struct goldfish_address_space_ping pingInfo;
+    struct address_space_ping pingInfo;
     pingInfo.metadata = makeMetadata(type, op, offSetToStartAddr);
     pingInfo.offset = mOffset; // + (offSetToStartAddr);
     if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
diff --git a/system/gralloc/Android.mk b/system/gralloc/Android.mk
index 8a12378..38ae394 100644
--- a/system/gralloc/Android.mk
+++ b/system/gralloc/Android.mk
@@ -19,6 +19,13 @@
 
 ifneq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
 LOCAL_SHARED_LIBRARIES += libdl
+
+ifeq (true,$(BUILD_EMULATOR_VULKAN))
+LOCAL_CFLAGS += -DVIRTIO_GPU
+LOCAL_C_INCLUDES += external/libdrm external/minigbm/cros_gralloc
+LOCAL_SHARED_LIBRARIES += libdrm
+endif
+
 endif
 
 $$(call emugl-end-module)
diff --git a/system/gralloc/CMakeLists.txt b/system/gralloc/CMakeLists.txt
index b972006..21bcde2 100644
--- a/system/gralloc/CMakeLists.txt
+++ b/system/gralloc/CMakeLists.txt
@@ -1,7 +1,7 @@
 # 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/gralloc/Android.mk" "09618d9293855148fb310e67065028da8c7f6dcf936b02b5695292c82ed4724e")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/gralloc/Android.mk" "c6313719aae414d05f6f4e8c6eb9039dd5cb120ae0a63818e25bfbe0cebcc702")
 set(gralloc.goldfish_src gralloc_old.cpp)
 android_add_library(TARGET gralloc.goldfish SHARED LICENSE Apache-2.0 SRC gralloc_old.cpp)
 target_include_directories(gralloc.goldfish PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/shared/gralloc_cb/include ${GOLDFISH_DEVICE_ROOT}/shared/GoldfishAddressSpace/include ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/shared/qemupipe/include-types ${GOLDFISH_DEVICE_ROOT}/shared/qemupipe/include ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
@@ -11,7 +11,7 @@
 # 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/gralloc/Android.mk" "09618d9293855148fb310e67065028da8c7f6dcf936b02b5695292c82ed4724e")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/gralloc/Android.mk" "c6313719aae414d05f6f4e8c6eb9039dd5cb120ae0a63818e25bfbe0cebcc702")
 set(gralloc.ranchu_src gralloc_old.cpp)
 android_add_library(TARGET gralloc.ranchu SHARED LICENSE Apache-2.0 SRC gralloc_old.cpp)
 target_include_directories(gralloc.ranchu PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/shared/gralloc_cb/include ${GOLDFISH_DEVICE_ROOT}/shared/GoldfishAddressSpace/include ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/shared/qemupipe/include-types ${GOLDFISH_DEVICE_ROOT}/shared/qemupipe/include ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
diff --git a/system/hals/Android.mk b/system/hals/Android.mk
index 3cdb4bf..1641d23 100644
--- a/system/hals/Android.mk
+++ b/system/hals/Android.mk
@@ -45,6 +45,10 @@
     device/generic/goldfish-opengl/host/include/libOpenglRender \
     device/generic/goldfish-opengl/system/renderControl_enc \
 
+LOCAL_CFLAGS += -DVIRTIO_GPU
+LOCAL_C_INCLUDES += external/libdrm external/minigbm/cros_gralloc
+LOCAL_SHARED_LIBRARIES += libdrm
+
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
@@ -78,5 +82,9 @@
     device/generic/goldfish-opengl/host/include/libOpenglRender \
     device/generic/goldfish-opengl/system/renderControl_enc \
 
+LOCAL_CFLAGS += -DVIRTIO_GPU
+LOCAL_C_INCLUDES += external/libdrm external/minigbm/cros_gralloc
+LOCAL_SHARED_LIBRARIES += libdrm
+
 include $(BUILD_SHARED_LIBRARY)