Make VirtGpu* interfaces

... so that upcoming end2end tests can set up a mock impl that
interacts with the host within-process.

Bug: b/292257025
Test: m && cvd start
Change-Id: I9d1fbaf3c2e50831a03405ad4f37b477b224abd9
diff --git a/guest/OpenglSystemCommon/AddressSpaceStream.cpp b/guest/OpenglSystemCommon/AddressSpaceStream.cpp
index cb0d58a..cc55303 100644
--- a/guest/OpenglSystemCommon/AddressSpaceStream.cpp
+++ b/guest/OpenglSystemCommon/AddressSpaceStream.cpp
@@ -160,7 +160,7 @@
 bool virtgpu_address_space_ping(address_space_handle_t fd, struct address_space_ping* info) {
     int ret;
     struct VirtGpuExecBuffer exec = {};
-    VirtGpuDevice& instance = VirtGpuDevice::getInstance();
+    VirtGpuDevice* instance = VirtGpuDevice::getInstance();
     struct gfxstreamContextPing ping = {};
 
     ping.hdr.opCode = GFXSTREAM_CONTEXT_PING;
@@ -169,7 +169,7 @@
     exec.command = static_cast<void*>(&ping);
     exec.command_size = sizeof(ping);
 
-    ret = instance.execBuffer(exec, nullptr);
+    ret = instance->execBuffer(exec, nullptr);
     if (ret)
         return false;
 
@@ -186,15 +186,15 @@
     char* blobAddr, *bufferPtr;
     int ret;
 
-    VirtGpuDevice& instance = VirtGpuDevice::getInstance();
-    VirtGpuCaps caps = instance.getCaps();
+    VirtGpuDevice* instance = VirtGpuDevice::getInstance();
+    VirtGpuCaps caps = instance->getCaps();
 
     blobCreate.blobId = 0;
     blobCreate.blobMem = kBlobMemHost3d;
     blobCreate.flags = kBlobFlagMappable;
     blobCreate.size = ALIGN(caps.gfxstreamCapset.ringSize + caps.gfxstreamCapset.bufferSize,
                             caps.gfxstreamCapset.blobAlignment);
-    blob = instance.createBlob(blobCreate);
+    blob = instance->createBlob(blobCreate);
     if (!blob)
         return nullptr;
 
@@ -205,7 +205,7 @@
     exec.command = static_cast<void*>(&contextCreate);
     exec.command_size = sizeof(contextCreate);
 
-    ret = instance.execBuffer(exec, blob);
+    ret = instance->execBuffer(exec, blob);
     if (ret)
         return nullptr;
 
diff --git a/guest/OpenglSystemCommon/HostConnection.cpp b/guest/OpenglSystemCommon/HostConnection.cpp
index 2901d74..023f99c 100644
--- a/guest/OpenglSystemCommon/HostConnection.cpp
+++ b/guest/OpenglSystemCommon/HostConnection.cpp
@@ -330,9 +330,8 @@
             break;
         }
         case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
-            VirtGpuDevice& instance =
-                VirtGpuDevice::getInstance((enum VirtGpuCapset)kCapsetGfxStreamVulkan);
-            auto deviceHandle = instance.getDeviceHandle();
+            auto device = VirtGpuDevice::getInstance((enum VirtGpuCapset)kCapsetGfxStreamVulkan);
+            auto deviceHandle = device->getDeviceHandle();
             auto stream = createVirtioGpuAddressSpaceStream(getGlobalHealthMonitor());
             if (!stream) {
                 ALOGE("Failed to create virtgpu AddressSpaceStream\n");
diff --git a/guest/magma/magma.cpp b/guest/magma/magma.cpp
index 43c2ac4..2e17320 100644
--- a/guest/magma/magma.cpp
+++ b/guest/magma/magma.cpp
@@ -156,10 +156,10 @@
 
     // TODO(fxbug.dev/122604): Evaluate deferred guest resource creation.
     auto blob = VirtGpuDevice::getInstance(VirtGpuCapset::kCapsetGfxStreamVulkan)
-                    .createBlob({.size = info.size,
-                                 .flags = kBlobFlagMappable | kBlobFlagShareable,
-                                 .blobMem = kBlobMemHost3d,
-                                 .blobId = info.id});
+                    ->createBlob({.size = info.size,
+                                  .flags = kBlobFlagMappable | kBlobFlagShareable,
+                                  .blobMem = kBlobMemHost3d,
+                                  .blobId = info.id});
     if (!blob) {
         return MAGMA_STATUS_INTERNAL_ERROR;
     }
@@ -212,10 +212,10 @@
 
     ALOGI("opening blob id %lu size %lu\n", result_buffer_mapping_id, result_buffer_size);
     auto blob = VirtGpuDevice::getInstance(VirtGpuCapset::kCapsetGfxStreamVulkan)
-                    .createBlob({.size = result_buffer_size,
-                                 .flags = kBlobFlagMappable | kBlobFlagShareable,
-                                 .blobMem = kBlobMemHost3d,
-                                 .blobId = result_buffer_mapping_id});
+                    ->createBlob({.size = result_buffer_size,
+                                  .flags = kBlobFlagMappable | kBlobFlagShareable,
+                                  .blobMem = kBlobMemHost3d,
+                                  .blobId = result_buffer_mapping_id});
     if (!blob) {
         ALOGE("VirtGpuDevice::createBlob failed\n");
         return MAGMA_STATUS_INTERNAL_ERROR;
@@ -242,10 +242,10 @@
     status = context->magma_buffer_get_handle_enc_(self, buffer, &mapping_id);
     if (status != MAGMA_STATUS_OK) return status;
     auto blob = VirtGpuDevice::getInstance(VirtGpuCapset::kCapsetGfxStreamVulkan)
-                    .createBlob({.size = info.size,
-                                 .flags = kBlobFlagMappable | kBlobFlagShareable,
-                                 .blobMem = kBlobMemHost3d,
-                                 .blobId = mapping_id});
+                    ->createBlob({.size = info.size,
+                                  .flags = kBlobFlagMappable | kBlobFlagShareable,
+                                  .blobMem = kBlobMemHost3d,
+                                  .blobId = mapping_id});
     if (!blob) {
         return MAGMA_STATUS_INTERNAL_ERROR;
     }
@@ -389,7 +389,7 @@
 
         s_context = new MagmaClientContext(stream);
         auto render_node_fd =
-            VirtGpuDevice::getInstance(VirtGpuCapset::kCapsetGfxStreamVulkan).getDeviceHandle();
+            VirtGpuDevice::getInstance(VirtGpuCapset::kCapsetGfxStreamVulkan)->getDeviceHandle();
         s_context->render_node_fd_ = SafeCast<int>(render_node_fd);
 
         ALOGE("Created new context\n");
diff --git a/guest/platform/Android.bp b/guest/platform/Android.bp
index db93afb..d73dc34 100644
--- a/guest/platform/Android.bp
+++ b/guest/platform/Android.bp
@@ -21,11 +21,13 @@
 
 cc_library_static {
     name: "libplatform",
+    host_supported: true,
     vendor: true,
     srcs: [
-        "linux/VirtGpuBlob.cpp",
-        "linux/VirtGpuBlobMapping.cpp",
-        "linux/VirtGpuDevice.cpp"
+        "VirtGpu.cpp",
+        "linux/LinuxVirtGpuBlob.cpp",
+        "linux/LinuxVirtGpuBlobMapping.cpp",
+        "linux/LinuxVirtGpuDevice.cpp"
     ],
     shared_libs: [
         "libcutils",
@@ -49,3 +51,36 @@
         "include",
     ],
 }
+
+cc_library_static {
+    name: "libplatform_stub",
+    host_supported: true,
+    vendor: true,
+    srcs: [
+        "VirtGpu.cpp",
+        "stub/StubVirtGpuBlob.cpp",
+        "stub/StubVirtGpuBlobMapping.cpp",
+        "stub/StubVirtGpuDevice.cpp",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libdrm",
+        "liblog",
+        "libutils",
+    ],
+    export_shared_lib_headers: [
+        "libdrm",
+    ],
+    export_include_dirs: [
+        "include"
+    ],
+    cflags: [
+        "-DLOG_TAG=\"platform\"",
+        "-Wno-missing-field-initializers",
+        "-fvisibility=default",
+        "-fstrict-aliasing",
+    ],
+    local_include_dirs: [
+        "include",
+    ],
+}
\ No newline at end of file
diff --git a/guest/platform/CMakeLists.txt b/guest/platform/CMakeLists.txt
index e777321..0869d07 100644
--- a/guest/platform/CMakeLists.txt
+++ b/guest/platform/CMakeLists.txt
@@ -2,8 +2,8 @@
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
 android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/../../../hardware/google/gfxstream/guest/platform/Android.mk" "b2e96eaf4c7c9823b6d1846beb672c82f82465e1122b699cc91192837f93782b")
-set(platform_host_src stub/VirtGpuBlob.cpp stub/VirtGpuBlobMapping.cpp stub/VirtGpuDevice.cpp)
-android_add_library(TARGET platform_host LICENSE Apache-2.0 SRC stub/VirtGpuBlob.cpp stub/VirtGpuBlobMapping.cpp stub/VirtGpuDevice.cpp)
+set(platform_host_src stub/StubVirtGpuBlob.cpp stub/StubVirtGpuBlobMapping.cpp stub/StubVirtGpuDevice.cpp)
+android_add_library(TARGET platform_host LICENSE Apache-2.0 SRC stub/StubVirtGpuBlob.cpp stub/StubVirtGpuBlobMapping.cpp stub/StubVirtGpuDevice.cpp)
 target_include_directories(platform_host PRIVATE ${GOLDFISH_DEVICE_ROOT}/../../../hardware/google/gfxstream/guest/platform/include ${GOLDFISH_DEVICE_ROOT}/./../../../hardware/google/gfxstream/guest/iostream/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./../../../hardware/google/gfxstream/guest/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(platform_host PRIVATE "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGFXSTREAM" "-DENABLE_ANDROID_HEALTH_MONITOR")
 target_compile_options(platform_host PRIVATE "-fvisibility=default" "-Wno-unused-parameter")
diff --git a/guest/platform/linux/VirtGpuBlobMapping.cpp b/guest/platform/VirtGpu.cpp
similarity index 62%
copy from guest/platform/linux/VirtGpuBlobMapping.cpp
copy to guest/platform/VirtGpu.cpp
index e8251b8..e263f7c 100644
--- a/guest/platform/linux/VirtGpuBlobMapping.cpp
+++ b/guest/platform/VirtGpu.cpp
@@ -14,18 +14,21 @@
  * limitations under the License.
  */
 
-#include <sys/mman.h>
+ #include "VirtGpu.h"
 
-#include "VirtGpu.h"
+namespace {
 
-VirtGpuBlobMapping::VirtGpuBlobMapping(VirtGpuBlobPtr blob, uint8_t* ptr, uint64_t size)
-    : mBlob(blob), mPtr(ptr), mSize(size) {}
+static VirtGpuDevice* sDevice = nullptr;
 
-VirtGpuBlobMapping::~VirtGpuBlobMapping(void) {
-    munmap(mPtr, mSize);
+}  // namespace
+
+VirtGpuDevice* VirtGpuDevice::getInstance(enum VirtGpuCapset capset) {
+    if (!sDevice) {
+        sDevice = platform_internal::getPlatformVirtGpuDeviceInstance(capset);
+    }
+    return sDevice;
 }
 
-uint8_t* VirtGpuBlobMapping::asRawPtr(void) {
-    return mPtr;
+void VirtGpuDevice::setInstanceForTesting(VirtGpuDevice* device) {
+    sDevice = device;
 }
-
diff --git a/guest/platform/include/VirtGpu.h b/guest/platform/include/VirtGpu.h
index 4d4435e..4c9cb87 100644
--- a/guest/platform/include/VirtGpu.h
+++ b/guest/platform/include/VirtGpu.h
@@ -114,66 +114,49 @@
 using VirtGpuBlobPtr = std::shared_ptr<VirtGpuBlob>;
 using VirtGpuBlobMappingPtr = std::shared_ptr<VirtGpuBlobMapping>;
 
-class VirtGpuBlob : public std::enable_shared_from_this<VirtGpuBlob> {
+class VirtGpuBlob {
   public:
-    VirtGpuBlob(int64_t deviceHandle, uint32_t blobHandle, uint32_t resourceHandle, uint64_t size);
-    ~VirtGpuBlob();
+    virtual ~VirtGpuBlob() {}
 
-    uint32_t getResourceHandle(void);
-    uint32_t getBlobHandle(void);
-    int wait(void);
+    virtual uint32_t getResourceHandle(void) = 0;
+    virtual uint32_t getBlobHandle(void) = 0;
+    virtual int wait(void) = 0;
 
-    VirtGpuBlobMappingPtr createMapping(void);
-    int exportBlob(struct VirtGpuExternalHandle& handle);
-
-  private:
-    // Not owned.  Really should use a ScopedFD for this, but doesn't matter since we have a
-    // singleton deviceimplemenentation anyways.
-    int64_t mDeviceHandle;
-
-    uint32_t mBlobHandle;
-    uint32_t mResourceHandle;
-    uint64_t mSize;
+    virtual VirtGpuBlobMappingPtr createMapping(void) = 0;
+    virtual int exportBlob(struct VirtGpuExternalHandle& handle) = 0;
 };
 
 class VirtGpuBlobMapping {
   public:
-    VirtGpuBlobMapping(VirtGpuBlobPtr blob, uint8_t* ptr, uint64_t size);
-    ~VirtGpuBlobMapping(void);
+    virtual ~VirtGpuBlobMapping(void) {}
 
-    uint8_t* asRawPtr(void);
-
-  private:
-    VirtGpuBlobPtr mBlob;
-    uint8_t* mPtr;
-    uint64_t mSize;
+    virtual uint8_t* asRawPtr(void) = 0;
 };
 
 class VirtGpuDevice {
   public:
-    static VirtGpuDevice& getInstance(enum VirtGpuCapset capset = kCapsetNone);
-    int64_t getDeviceHandle(void);
+    static VirtGpuDevice* getInstance(enum VirtGpuCapset capset = kCapsetNone);
+    static void setInstanceForTesting(VirtGpuDevice* device);
 
-    struct VirtGpuCaps getCaps(void);
+    virtual ~VirtGpuDevice() {}
 
-    VirtGpuBlobPtr createBlob(const struct VirtGpuCreateBlob& blobCreate);
-    VirtGpuBlobPtr createPipeBlob(uint32_t size);
-    VirtGpuBlobPtr importBlob(const struct VirtGpuExternalHandle& handle);
+    virtual int64_t getDeviceHandle(void) = 0;
 
-    int execBuffer(struct VirtGpuExecBuffer& execbuffer, VirtGpuBlobPtr blob);
+    virtual struct VirtGpuCaps getCaps(void) = 0;
 
-  private:
-    VirtGpuDevice(enum VirtGpuCapset capset);
-    ~VirtGpuDevice();
-    VirtGpuDevice(VirtGpuDevice const&);
-    void operator=(VirtGpuDevice const&);
+    virtual VirtGpuBlobPtr createBlob(const struct VirtGpuCreateBlob& blobCreate) = 0;
+    virtual VirtGpuBlobPtr createPipeBlob(uint32_t size) = 0;
+    virtual VirtGpuBlobPtr importBlob(const struct VirtGpuExternalHandle& handle) = 0;
 
-    static VirtGpuDevice mInstance;
-    int64_t mDeviceHandle;
-
-    struct VirtGpuCaps mCaps;
+    virtual int execBuffer(struct VirtGpuExecBuffer& execbuffer, VirtGpuBlobPtr blob) = 0;
 };
 
+namespace platform_internal {
+
+VirtGpuDevice* getPlatformVirtGpuDeviceInstance(enum VirtGpuCapset capset = kCapsetNone);
+
+}  // namespace platform_internal
+
 // HACK: We can use android::base::EnumFlags, but we'll have to do more guest
 // refactorings to figure out our end goal.  We can either depend more on base or
 // try to transition to something else (b:202552093) [atleast for guests].
diff --git a/guest/platform/linux/LinuxVirtGpu.h b/guest/platform/linux/LinuxVirtGpu.h
new file mode 100644
index 0000000..c15a941
--- /dev/null
+++ b/guest/platform/linux/LinuxVirtGpu.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 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 "VirtGpu.h"
+
+class LinuxVirtGpuBlob : public std::enable_shared_from_this<LinuxVirtGpuBlob>, public VirtGpuBlob {
+  public:
+    LinuxVirtGpuBlob(int64_t deviceHandle, uint32_t blobHandle, uint32_t resourceHandle, uint64_t size);
+    ~LinuxVirtGpuBlob();
+
+    uint32_t getResourceHandle(void) override;
+    uint32_t getBlobHandle(void) override;
+    int wait(void) override;
+
+    VirtGpuBlobMappingPtr createMapping(void) override;
+    int exportBlob(struct VirtGpuExternalHandle& handle) override;
+
+  private:
+    // Not owned.  Really should use a ScopedFD for this, but doesn't matter since we have a
+    // singleton deviceimplemenentation anyways.
+    int64_t mDeviceHandle;
+
+    uint32_t mBlobHandle;
+    uint32_t mResourceHandle;
+    uint64_t mSize;
+};
+
+class LinuxVirtGpuBlobMapping : public VirtGpuBlobMapping {
+  public:
+    LinuxVirtGpuBlobMapping(VirtGpuBlobPtr blob, uint8_t* ptr, uint64_t size);
+    ~LinuxVirtGpuBlobMapping(void);
+
+    uint8_t* asRawPtr(void) override;
+
+  private:
+    VirtGpuBlobPtr mBlob;
+    uint8_t* mPtr;
+    uint64_t mSize;
+};
+
+class LinuxVirtGpuDevice : public VirtGpuDevice {
+  public:
+    LinuxVirtGpuDevice(enum VirtGpuCapset capset);
+    virtual ~LinuxVirtGpuDevice();
+
+    virtual int64_t getDeviceHandle(void);
+
+    virtual struct VirtGpuCaps getCaps(void);
+
+    virtual VirtGpuBlobPtr createBlob(const struct VirtGpuCreateBlob& blobCreate);
+    virtual VirtGpuBlobPtr createPipeBlob(uint32_t size);
+    virtual VirtGpuBlobPtr importBlob(const struct VirtGpuExternalHandle& handle);
+
+    virtual int execBuffer(struct VirtGpuExecBuffer& execbuffer, VirtGpuBlobPtr blob);
+
+  private:
+    int64_t mDeviceHandle;
+
+    struct VirtGpuCaps mCaps;
+};
diff --git a/guest/platform/linux/VirtGpuBlob.cpp b/guest/platform/linux/LinuxVirtGpuBlob.cpp
similarity index 83%
rename from guest/platform/linux/VirtGpuBlob.cpp
rename to guest/platform/linux/LinuxVirtGpuBlob.cpp
index 63d508e..59a244a 100644
--- a/guest/platform/linux/VirtGpuBlob.cpp
+++ b/guest/platform/linux/LinuxVirtGpuBlob.cpp
@@ -23,17 +23,17 @@
 
 #include <cutils/log.h>
 
-#include "VirtGpu.h"
+#include "LinuxVirtGpu.h"
 #include "virtgpu_drm.h"
 
-VirtGpuBlob::VirtGpuBlob(int64_t deviceHandle, uint32_t blobHandle, uint32_t resourceHandle,
+LinuxVirtGpuBlob::LinuxVirtGpuBlob(int64_t deviceHandle, uint32_t blobHandle, uint32_t resourceHandle,
                          uint64_t size)
     : mDeviceHandle(deviceHandle),
       mBlobHandle(blobHandle),
       mResourceHandle(resourceHandle),
       mSize(size) {}
 
-VirtGpuBlob::~VirtGpuBlob(void) {
+LinuxVirtGpuBlob::~LinuxVirtGpuBlob(void) {
     struct drm_gem_close gem_close {
         .handle = mBlobHandle, .pad = 0,
     };
@@ -45,15 +45,15 @@
     }
 }
 
-uint32_t VirtGpuBlob::getBlobHandle(void) {
+uint32_t LinuxVirtGpuBlob::getBlobHandle(void) {
     return mBlobHandle;
 }
 
-uint32_t VirtGpuBlob::getResourceHandle(void) {
+uint32_t LinuxVirtGpuBlob::getResourceHandle(void) {
     return mResourceHandle;
 }
 
-VirtGpuBlobMappingPtr VirtGpuBlob::createMapping(void) {
+VirtGpuBlobMappingPtr LinuxVirtGpuBlob::createMapping(void) {
     int ret;
     struct drm_virtgpu_map map {
         .handle = mBlobHandle, .pad = 0,
@@ -73,10 +73,10 @@
         return nullptr;
     }
 
-    return std::make_shared<VirtGpuBlobMapping>(shared_from_this(), ptr, mSize);
+    return std::make_shared<LinuxVirtGpuBlobMapping>(shared_from_this(), ptr, mSize);
 }
 
-int VirtGpuBlob::exportBlob(struct VirtGpuExternalHandle& handle) {
+int LinuxVirtGpuBlob::exportBlob(struct VirtGpuExternalHandle& handle) {
     int ret, fd;
 
     ret = drmPrimeHandleToFD(mDeviceHandle, mBlobHandle, DRM_CLOEXEC | DRM_RDWR, &fd);
@@ -90,7 +90,7 @@
     return 0;
 }
 
-int VirtGpuBlob::wait() {
+int LinuxVirtGpuBlob::wait() {
     int ret;
     struct drm_virtgpu_3d_wait wait_3d = {0};
 
diff --git a/guest/platform/linux/VirtGpuBlobMapping.cpp b/guest/platform/linux/LinuxVirtGpuBlobMapping.cpp
similarity index 75%
rename from guest/platform/linux/VirtGpuBlobMapping.cpp
rename to guest/platform/linux/LinuxVirtGpuBlobMapping.cpp
index e8251b8..c8035f0 100644
--- a/guest/platform/linux/VirtGpuBlobMapping.cpp
+++ b/guest/platform/linux/LinuxVirtGpuBlobMapping.cpp
@@ -16,16 +16,15 @@
 
 #include <sys/mman.h>
 
-#include "VirtGpu.h"
+#include "LinuxVirtGpu.h"
 
-VirtGpuBlobMapping::VirtGpuBlobMapping(VirtGpuBlobPtr blob, uint8_t* ptr, uint64_t size)
+LinuxVirtGpuBlobMapping::LinuxVirtGpuBlobMapping(VirtGpuBlobPtr blob, uint8_t* ptr, uint64_t size)
     : mBlob(blob), mPtr(ptr), mSize(size) {}
 
-VirtGpuBlobMapping::~VirtGpuBlobMapping(void) {
+LinuxVirtGpuBlobMapping::~LinuxVirtGpuBlobMapping(void) {
     munmap(mPtr, mSize);
 }
 
-uint8_t* VirtGpuBlobMapping::asRawPtr(void) {
+uint8_t* LinuxVirtGpuBlobMapping::asRawPtr(void) {
     return mPtr;
 }
-
diff --git a/guest/platform/linux/VirtGpuDevice.cpp b/guest/platform/linux/LinuxVirtGpuDevice.cpp
similarity index 84%
rename from guest/platform/linux/VirtGpuDevice.cpp
rename to guest/platform/linux/LinuxVirtGpuDevice.cpp
index 1f4b194..bd2a249 100644
--- a/guest/platform/linux/VirtGpuDevice.cpp
+++ b/guest/platform/linux/LinuxVirtGpuDevice.cpp
@@ -23,7 +23,7 @@
 
 #include <cutils/log.h>
 
-#include "VirtGpu.h"
+#include "LinuxVirtGpu.h"
 #include "virtgpu_drm.h"
 #include "virtgpu_gfxstream_protocol.h"
 
@@ -35,12 +35,7 @@
 #define VIRGL_BIND_CUSTOM (1 << 17)
 #define PIPE_BUFFER 0
 
-VirtGpuDevice& VirtGpuDevice::getInstance(enum VirtGpuCapset capset) {
-    static VirtGpuDevice mInstance(capset);
-    return mInstance;
-}
-
-VirtGpuDevice::VirtGpuDevice(enum VirtGpuCapset capset) {
+LinuxVirtGpuDevice::LinuxVirtGpuDevice(enum VirtGpuCapset capset) {
     struct VirtGpuParam params[] = {
         PARAM(VIRTGPU_PARAM_3D_FEATURES),          PARAM(VIRTGPU_PARAM_CAPSET_QUERY_FIX),
         PARAM(VIRTGPU_PARAM_RESOURCE_BLOB),        PARAM(VIRTGPU_PARAM_HOST_VISIBLE),
@@ -111,13 +106,17 @@
     }
 }
 
-struct VirtGpuCaps VirtGpuDevice::getCaps(void) { return mCaps; }
+LinuxVirtGpuDevice::~LinuxVirtGpuDevice() {
+    close(mDeviceHandle);
+}
 
-int64_t VirtGpuDevice::getDeviceHandle(void) {
+struct VirtGpuCaps LinuxVirtGpuDevice::getCaps(void) { return mCaps; }
+
+int64_t LinuxVirtGpuDevice::getDeviceHandle(void) {
     return mDeviceHandle;
 }
 
-VirtGpuBlobPtr VirtGpuDevice::createPipeBlob(uint32_t size) {
+VirtGpuBlobPtr LinuxVirtGpuDevice::createPipeBlob(uint32_t size) {
     drm_virtgpu_resource_create create = {
             .target = PIPE_BUFFER,
             .format = VIRGL_FORMAT_R8_UNORM,
@@ -136,11 +135,11 @@
         return nullptr;
     }
 
-    return std::make_shared<VirtGpuBlob>(mDeviceHandle, create.bo_handle, create.res_handle,
+    return std::make_shared<LinuxVirtGpuBlob>(mDeviceHandle, create.bo_handle, create.res_handle,
                                          static_cast<uint64_t>(size));
 }
 
-VirtGpuBlobPtr VirtGpuDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) {
+VirtGpuBlobPtr LinuxVirtGpuDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) {
     int ret;
     struct drm_virtgpu_resource_create_blob create = {0};
 
@@ -155,11 +154,11 @@
         return nullptr;
     }
 
-    return std::make_shared<VirtGpuBlob>(mDeviceHandle, create.bo_handle, create.res_handle,
+    return std::make_shared<LinuxVirtGpuBlob>(mDeviceHandle, create.bo_handle, create.res_handle,
                                          blobCreate.size);
 }
 
-VirtGpuBlobPtr VirtGpuDevice::importBlob(const struct VirtGpuExternalHandle& handle) {
+VirtGpuBlobPtr LinuxVirtGpuDevice::importBlob(const struct VirtGpuExternalHandle& handle) {
     struct drm_virtgpu_resource_info info = {0};
     uint32_t blobHandle;
     int ret;
@@ -178,11 +177,11 @@
         return nullptr;
     }
 
-    return std::make_shared<VirtGpuBlob>(mDeviceHandle, blobHandle, info.res_handle,
+    return std::make_shared<LinuxVirtGpuBlob>(mDeviceHandle, blobHandle, info.res_handle,
                                          static_cast<uint64_t>(info.size));
 }
 
-int VirtGpuDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer, VirtGpuBlobPtr blob) {
+int LinuxVirtGpuDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer, VirtGpuBlobPtr blob) {
     int ret;
     struct drm_virtgpu_execbuffer exec = {0};
     uint32_t blobHandle;
@@ -213,6 +212,11 @@
     return 0;
 }
 
-VirtGpuDevice::~VirtGpuDevice() {
-    close(mDeviceHandle);
+namespace platform_internal {
+
+VirtGpuDevice* getPlatformVirtGpuDeviceInstance(enum VirtGpuCapset capset) {
+    static LinuxVirtGpuDevice sInstance(capset);
+    return &sInstance;
 }
+
+}  // namespace platform_internal
diff --git a/guest/platform/linux/meson.build b/guest/platform/linux/meson.build
index 07bae4e..a645caf 100644
--- a/guest/platform/linux/meson.build
+++ b/guest/platform/linux/meson.build
@@ -2,9 +2,10 @@
 # SPDX-License-Identifier: MIT
 
 files_lib_platform = files(
-  'VirtGpuDevice.cpp',
-  'VirtGpuBlobMapping.cpp',
-  'VirtGpuBlob.cpp',
+  '../VirtGpu.cpp',
+  'LinuxVirtGpuDevice.cpp',
+  'LinuxVirtGpuBlobMapping.cpp',
+  'LinuxVirtGpuBlob.cpp',
 )
 
 lib_platform = static_library(
diff --git a/guest/platform/stub/StubVirtGpu.h b/guest/platform/stub/StubVirtGpu.h
new file mode 100644
index 0000000..4e70a9f
--- /dev/null
+++ b/guest/platform/stub/StubVirtGpu.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 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 "VirtGpu.h"
+
+class StubVirtGpuBlob : public std::enable_shared_from_this<StubVirtGpuBlob>, public VirtGpuBlob {
+  public:
+    StubVirtGpuBlob(int64_t deviceHandle, uint32_t blobHandle, uint32_t resourceHandle, uint64_t size);
+    ~StubVirtGpuBlob();
+
+    uint32_t getResourceHandle(void) override;
+    uint32_t getBlobHandle(void) override;
+    int wait(void) override;
+
+    VirtGpuBlobMappingPtr createMapping(void) override;
+    int exportBlob(struct VirtGpuExternalHandle& handle) override;
+
+  private:
+    // Not owned.  Really should use a ScopedFD for this, but doesn't matter since we have a
+    // singleton deviceimplemenentation anyways.
+    int64_t mDeviceHandle;
+
+    uint32_t mBlobHandle;
+    uint32_t mResourceHandle;
+    uint64_t mSize;
+};
+
+class StubVirtGpuBlobMapping : public VirtGpuBlobMapping {
+  public:
+    StubVirtGpuBlobMapping(VirtGpuBlobPtr blob, uint8_t* ptr, uint64_t size);
+    ~StubVirtGpuBlobMapping(void);
+
+    uint8_t* asRawPtr(void) override;
+
+  private:
+    VirtGpuBlobPtr mBlob;
+    uint8_t* mPtr;
+    uint64_t mSize;
+};
+
+class StubVirtGpuDevice : public VirtGpuDevice {
+  public:
+    StubVirtGpuDevice(enum VirtGpuCapset capset);
+    virtual ~StubVirtGpuDevice();
+
+    virtual int64_t getDeviceHandle(void);
+
+    virtual struct VirtGpuCaps getCaps(void);
+
+    virtual VirtGpuBlobPtr createBlob(const struct VirtGpuCreateBlob& blobCreate);
+    virtual VirtGpuBlobPtr createPipeBlob(uint32_t size);
+    virtual VirtGpuBlobPtr importBlob(const struct VirtGpuExternalHandle& handle);
+
+    virtual int execBuffer(struct VirtGpuExecBuffer& execbuffer, VirtGpuBlobPtr blob);
+
+  private:
+    int64_t mDeviceHandle;
+
+    struct VirtGpuCaps mCaps;
+};
\ No newline at end of file
diff --git a/guest/platform/stub/VirtGpuBlob.cpp b/guest/platform/stub/StubVirtGpuBlob.cpp
similarity index 71%
rename from guest/platform/stub/VirtGpuBlob.cpp
rename to guest/platform/stub/StubVirtGpuBlob.cpp
index d07fa18..fd37644 100644
--- a/guest/platform/stub/VirtGpuBlob.cpp
+++ b/guest/platform/stub/StubVirtGpuBlob.cpp
@@ -14,31 +14,31 @@
  * limitations under the License.
  */
 
-#include "VirtGpu.h"
+#include "StubVirtGpu.h"
 
-VirtGpuBlob::VirtGpuBlob(int64_t deviceHandle, uint32_t blobHandle, uint32_t resourceHandle,
+StubVirtGpuBlob::StubVirtGpuBlob(int64_t deviceHandle, uint32_t blobHandle, uint32_t resourceHandle,
                          uint64_t size)
     : mDeviceHandle(deviceHandle),
       mBlobHandle(blobHandle),
       mResourceHandle(resourceHandle),
       mSize(size) {}
 
-VirtGpuBlob::~VirtGpuBlob(void) {
+StubVirtGpuBlob::~StubVirtGpuBlob(void) {
     // Unimplemented stub
 }
 
-uint32_t VirtGpuBlob::getBlobHandle(void) {
+uint32_t StubVirtGpuBlob::getBlobHandle(void) {
     return 0;
 }
 
-uint32_t VirtGpuBlob::getResourceHandle(void) {
+uint32_t StubVirtGpuBlob::getResourceHandle(void) {
     return 0;
 }
 
-VirtGpuBlobMappingPtr VirtGpuBlob::createMapping(void) {
+VirtGpuBlobMappingPtr StubVirtGpuBlob::createMapping(void) {
     return nullptr;
 }
 
-int VirtGpuBlob::wait() {
+int StubVirtGpuBlob::wait() {
     return -1;
 }
diff --git a/guest/platform/stub/VirtGpuBlobMapping.cpp b/guest/platform/stub/StubVirtGpuBlobMapping.cpp
similarity index 77%
rename from guest/platform/stub/VirtGpuBlobMapping.cpp
rename to guest/platform/stub/StubVirtGpuBlobMapping.cpp
index b14b658..f7e845b 100644
--- a/guest/platform/stub/VirtGpuBlobMapping.cpp
+++ b/guest/platform/stub/StubVirtGpuBlobMapping.cpp
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-#include "VirtGpu.h"
+#include "StubVirtGpu.h"
 
-VirtGpuBlobMapping::VirtGpuBlobMapping(VirtGpuBlobPtr blob, uint8_t* ptr, uint64_t size)
+StubVirtGpuBlobMapping::StubVirtGpuBlobMapping(VirtGpuBlobPtr blob, uint8_t* ptr, uint64_t size)
     : mBlob(blob), mPtr(ptr), mSize(size) {}
 
-VirtGpuBlobMapping::~VirtGpuBlobMapping(void) {
+StubVirtGpuBlobMapping::~StubVirtGpuBlobMapping(void) {
     // Unimplemented for now
    (void) mPtr;
    (void) mSize;
    (void) mBlob;
 }
 
-uint8_t* VirtGpuBlobMapping::asRawPtr(void) {
+uint8_t* StubVirtGpuBlobMapping::asRawPtr(void) {
     return nullptr;
 }
diff --git a/guest/platform/stub/StubVirtGpuDevice.cpp b/guest/platform/stub/StubVirtGpuDevice.cpp
new file mode 100644
index 0000000..c4930b7
--- /dev/null
+++ b/guest/platform/stub/StubVirtGpuDevice.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 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 "StubVirtGpu.h"
+
+StubVirtGpuDevice::StubVirtGpuDevice(enum VirtGpuCapset) {
+    // Unimplemented stub
+}
+
+struct VirtGpuCaps StubVirtGpuDevice::getCaps(void) { return mCaps; }
+
+int64_t StubVirtGpuDevice::getDeviceHandle(void) {
+    return mDeviceHandle;
+}
+
+VirtGpuBlobPtr StubVirtGpuDevice::createPipeBlob(uint32_t) {
+    return nullptr;
+}
+
+VirtGpuBlobPtr StubVirtGpuDevice::createBlob(const struct VirtGpuCreateBlob&) {
+    return nullptr;
+}
+
+VirtGpuBlobPtr StubVirtGpuDevice::importBlob(const struct VirtGpuExternalHandle&) {
+    return nullptr;
+}
+
+int StubVirtGpuDevice::execBuffer(struct VirtGpuExecBuffer&, VirtGpuBlobPtr) {
+    return -1;
+}
+
+StubVirtGpuDevice::~StubVirtGpuDevice() {
+    // Unimplemented stub
+}
+
+namespace platform_internal {
+
+VirtGpuDevice* getPlatformVirtGpuDeviceInstance(enum VirtGpuCapset capset) {
+    static StubVirtGpuDevice sInstance(capset);
+    return &sInstance;
+}
+
+}  // namespace platform_internal
\ No newline at end of file
diff --git a/guest/platform/stub/VirtGpuDevice.cpp b/guest/platform/stub/VirtGpuDevice.cpp
deleted file mode 100644
index bf8c11f..0000000
--- a/guest/platform/stub/VirtGpuDevice.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2022 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 "VirtGpu.h"
-
-VirtGpuDevice& VirtGpuDevice::getInstance(enum VirtGpuCapset capset) {
-    static VirtGpuDevice mInstance(capset);
-    return mInstance;
-}
-
-VirtGpuDevice::VirtGpuDevice(enum VirtGpuCapset capset) {
-    // Unimplemented stub
-}
-
-struct VirtGpuCaps VirtGpuDevice::getCaps(void) { return mCaps; }
-
-int64_t VirtGpuDevice::getDeviceHandle(void) {
-    return mDeviceHandle;
-}
-
-VirtGpuBlobPtr VirtGpuDevice::createPipeBlob(uint32_t size) {
-    return nullptr;
-}
-
-VirtGpuBlobPtr VirtGpuDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) {
-    return nullptr;
-}
-
-VirtGpuBlobPtr VirtGpuDevice::importBlob(const struct VirtGpuExternalHandle& handle) {
-    return nullptr;
-}
-
-int VirtGpuDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer, VirtGpuBlobPtr blob) {
-    return -1;
-}
-
-VirtGpuDevice::~VirtGpuDevice() {
-    // Unimplemented stub
-}
diff --git a/guest/vulkan_enc/ResourceTracker.cpp b/guest/vulkan_enc/ResourceTracker.cpp
index 843cf18..63ff963 100644
--- a/guest/vulkan_enc/ResourceTracker.cpp
+++ b/guest/vulkan_enc/ResourceTracker.cpp
@@ -912,8 +912,8 @@
     }
 
     void setupCaps(void) {
-        VirtGpuDevice& instance = VirtGpuDevice::getInstance((enum VirtGpuCapset)3);
-        mCaps = instance.getCaps();
+        VirtGpuDevice* instance = VirtGpuDevice::getInstance((enum VirtGpuCapset)3);
+        mCaps = instance->getCaps();
 
         // Delete once goldfish Linux drivers are gone
         if (mCaps.gfxstreamCapset.protocolVersion == 0) {
@@ -2947,13 +2947,13 @@
             }
             {
                 AutoLock<RecursiveLock> lock(mLock);
-                VirtGpuDevice& instance = VirtGpuDevice::getInstance((enum VirtGpuCapset)3);
+                VirtGpuDevice* instance = VirtGpuDevice::getInstance((enum VirtGpuCapset)3);
                 createBlob.blobMem = kBlobMemHost3d;
                 createBlob.flags = kBlobFlagMappable;
                 createBlob.blobId = hvaSizeId[2];
                 createBlob.size = hostAllocationInfo.allocationSize;
 
-                auto blob = instance.createBlob(createBlob);
+                auto blob = instance->createBlob(createBlob);
                 if (!blob) {
                     ALOGE("Failed to create coherent memory: failed to create blob.");
                     res = VK_ERROR_OUT_OF_DEVICE_MEMORY;
@@ -3040,7 +3040,7 @@
         if (mCaps.params[kParamCreateGuestHandle]) {
             struct VirtGpuCreateBlob createBlob = {0};
             struct VirtGpuExecBuffer exec = {};
-            VirtGpuDevice& instance = VirtGpuDevice::getInstance();
+            VirtGpuDevice* instance = VirtGpuDevice::getInstance();
             struct gfxstreamPlaceholderCommandVk placeholderCmd = {};
 
             createBlobInfo.blobId = ++mBlobId;
@@ -3053,7 +3053,7 @@
             createBlob.blobId = createBlobInfo.blobId;
             createBlob.size = hostAllocationInfo.allocationSize;
 
-            guestBlob = instance.createBlob(createBlob);
+            guestBlob = instance->createBlob(createBlob);
             if (!guestBlob) {
                 ALOGE("Failed to allocate coherent memory: failed to create blob.");
                 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
@@ -3064,7 +3064,7 @@
             exec.command_size = sizeof(placeholderCmd);
             exec.flags = kRingIdx;
             exec.ring_idx = 1;
-            if (instance.execBuffer(exec, guestBlob)) {
+            if (instance->execBuffer(exec, guestBlob)) {
                 ALOGE("Failed to allocate coherent memory: failed to execbuffer for wait.");
                 return VK_ERROR_OUT_OF_HOST_MEMORY;
             }
@@ -3947,7 +3947,7 @@
         if (info.blobId && !info.coherentMemory && !mCaps.params[kParamCreateGuestHandle]) {
             VkEncoder* enc = (VkEncoder*)context;
             VirtGpuBlobMappingPtr mapping;
-            VirtGpuDevice& instance = VirtGpuDevice::getInstance();
+            VirtGpuDevice* instance = VirtGpuDevice::getInstance();
 
             uint64_t offset;
             uint8_t* ptr;
@@ -3961,7 +3961,7 @@
             createBlob.blobId = info.blobId;
             createBlob.size = info.coherentMemorySize;
 
-            auto blob = instance.createBlob(createBlob);
+            auto blob = instance->createBlob(createBlob);
             if (!blob) return VK_ERROR_OUT_OF_DEVICE_MEMORY;
 
             mapping = blob->createMapping();
@@ -4613,7 +4613,7 @@
     VkResult createFence(VkDevice device, uint64_t hostFenceHandle, int64_t& osHandle) {
         struct VirtGpuExecBuffer exec = { };
         struct gfxstreamCreateExportSyncVK exportSync = { };
-        VirtGpuDevice& instance = VirtGpuDevice::getInstance();
+        VirtGpuDevice* instance = VirtGpuDevice::getInstance();
 
         uint64_t hostDeviceHandle = get_host_u64_VkDevice(device);
 
@@ -4626,7 +4626,7 @@
         exec.command = static_cast<void*>(&exportSync);
         exec.command_size = sizeof(exportSync);
         exec.flags = kFenceOut | kRingIdx;
-        if (instance.execBuffer(exec, nullptr))
+        if (instance->execBuffer(exec, nullptr))
             return VK_ERROR_OUT_OF_HOST_MEMORY;
 
         osHandle = exec.handle.osHandle;
@@ -7153,7 +7153,7 @@
         if (mFeatureInfo->hasVirtioGpuNativeSync) {
             struct VirtGpuExecBuffer exec = { };
             struct gfxstreamCreateQSRIExportVK exportQSRI = { };
-            VirtGpuDevice& instance = VirtGpuDevice::getInstance();
+            VirtGpuDevice* instance = VirtGpuDevice::getInstance();
 
             uint64_t hostImageHandle = get_host_u64_VkImage(image);
 
@@ -7164,7 +7164,7 @@
             exec.command = static_cast<void*>(&exportQSRI);
             exec.command_size = sizeof(exportQSRI);
             exec.flags = kFenceOut | kRingIdx;
-            if (instance.execBuffer(exec, nullptr))
+            if (instance->execBuffer(exec, nullptr))
                 return VK_ERROR_OUT_OF_HOST_MEMORY;
 
             *fd = exec.handle.osHandle;