Merge "gfxstream: add CONFIG_AEMU statements around register/unregister Vulkan instance" into main
diff --git a/Android.bp b/Android.bp
index afd1c29..928c7ab 100644
--- a/Android.bp
+++ b/Android.bp
@@ -164,6 +164,8 @@
         "-DVK_GFXSTREAM_STRUCTURE_TYPE_EXT",
         "-DGFXSTREAM_ENABLE_HOST_GLES=1",
         "-Wall",
+        "-Wextra",
+        "-Wshadow",
         "-Wthread-safety",
         "-Wno-unused-function",
         "-Wno-unused-parameter",
diff --git a/host/RendererImpl.cpp b/host/RendererImpl.cpp
index e02789c..14bbbff 100644
--- a/host/RendererImpl.cpp
+++ b/host/RendererImpl.cpp
@@ -190,7 +190,7 @@
     for (const auto& c : mStoppedChannels) {
         c->renderThread()->waitForFinished();
         {
-            android::base::AutoLock lock(*graphicsDriverLock());
+            android::base::AutoLock driverLock(*graphicsDriverLock());
             c->renderThread()->sendExitSignal();
             c->renderThread()->wait();
         }
@@ -231,7 +231,7 @@
     for (const auto& c : channels) {
         c->renderThread()->waitForFinished();
         {
-            android::base::AutoLock lock(*graphicsDriverLock());
+            android::base::AutoLock driverLock(*graphicsDriverLock());
             c->renderThread()->sendExitSignal();
             c->renderThread()->wait();
         }
@@ -309,7 +309,7 @@
 
     thread->waitForFinished();
     {
-        android::base::AutoLock lock(*graphicsDriverLock());
+        android::base::AutoLock driverLock(*graphicsDriverLock());
         thread->sendExitSignal();
         thread->wait();
     }
diff --git a/host/gl/glestranslator/GLES_CM/GLEScmImp.cpp b/host/gl/glestranslator/GLES_CM/GLEScmImp.cpp
index 9163128..5d2ef00 100644
--- a/host/gl/glestranslator/GLES_CM/GLEScmImp.cpp
+++ b/host/gl/glestranslator/GLES_CM/GLEScmImp.cpp
@@ -1213,10 +1213,12 @@
     case GL_COMPRESSED_TEXTURE_FORMATS:
         {
             int nparams = getCompressedFormats(1, NULL);
-            if (nparams>0) {
-                int * iparams = new int[nparams];
+            if (nparams > 0) {
+                int* iparams = new int[nparams];
                 getCompressedFormats(1, iparams);
-                for (int i=0; i<nparams; i++) params[i] = (GLfloat)iparams[i];
+                for (int paramIndex = 0; paramIndex < nparams; paramIndex++) {
+                    params[paramIndex] = (GLfloat)iparams[paramIndex];
+                }
                 delete [] iparams;
             }
         }
@@ -2691,10 +2693,10 @@
     if (fbName) {
         auto fbObj = ctx->getFBOData(fbName);
         if (fbObj) {
-            GLenum target;
-            GLuint name = fbObj->getAttachment(attachment, &target, NULL);
+            GLenum attachmentTarget;
+            GLuint name = fbObj->getAttachment(attachment, &attachmentTarget, NULL);
             if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES) {
-                *params = target;
+                *params = attachmentTarget;
                 return;
             }
             else if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES) {
diff --git a/host/gl/glestranslator/GLES_V2/GLESv2Imp.cpp b/host/gl/glestranslator/GLES_V2/GLESv2Imp.cpp
index 049eaeb..5e495c5 100644
--- a/host/gl/glestranslator/GLES_V2/GLESv2Imp.cpp
+++ b/host/gl/glestranslator/GLES_V2/GLESv2Imp.cpp
@@ -2187,12 +2187,12 @@
         {
             int nparams = getCompressedFormats(2, NULL);
             if (nparams > 0) {
-                int* iparams = new int[nparams];
-                getCompressedFormats(2, iparams);
-                for (int i = 0; i < nparams; i++) {
-                    params[i] = (T)iparams[i];
+                int* compressedFormats = new int[nparams];
+                getCompressedFormats(2, compressedFormats);
+                for (int paramIndex = 0; paramIndex < nparams; paramIndex++) {
+                    params[paramIndex] = (T)compressedFormats[paramIndex];
                 }
-                delete [] iparams;
+                delete[] compressedFormats;
             }
         }
         break;
@@ -2549,18 +2549,17 @@
     if (fbName) {
         auto fbObj = ctx->getFBOData(fbName);
         if (fbObj != NULL) {
-            GLenum target;
-            GLuint name = fbObj->getAttachment(attachment, &target, NULL);
+            GLenum attachmentTarget;
+            GLuint name = fbObj->getAttachment(attachment, &attachmentTarget, NULL);
             if (!name) {
                 SET_ERROR_IF(pname != GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE &&
                         pname != GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, GL_INVALID_ENUM);
             }
             if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) {
-                if (target == GL_TEXTURE_2D) {
+                if (attachmentTarget == GL_TEXTURE_2D) {
                     *params = GL_TEXTURE;
                     return;
-                }
-                else if (target == GL_RENDERBUFFER) {
+                } else if (attachmentTarget == GL_RENDERBUFFER) {
                     *params = GL_RENDERBUFFER;
                     return;
                 } else {
diff --git a/host/gl/glestranslator/GLcommon/TextureData.cpp b/host/gl/glestranslator/GLcommon/TextureData.cpp
index fda7b23..63bc7a5 100644
--- a/host/gl/glestranslator/GLcommon/TextureData.cpp
+++ b/host/gl/glestranslator/GLcommon/TextureData.cpp
@@ -53,8 +53,8 @@
     });
 }
 
-void TextureData::onSave(android::base::Stream* stream, unsigned int globalName) const {
-    ObjectData::onSave(stream, globalName);
+void TextureData::onSave(android::base::Stream* stream, unsigned int overrideGlobalName) const {
+    ObjectData::onSave(stream, overrideGlobalName);
     // The current TextureData structure is wrong when dealing with mipmaps.
     stream->putBe32(target);
     stream->putBe32(width);
@@ -73,7 +73,7 @@
     stream->write(crop_rect, sizeof(crop_rect));
     stream->putBe32(texStorageLevels);
     stream->putBe32(0); // deprecated mipmap level
-    stream->putBe32(globalName);
+    stream->putBe32(overrideGlobalName);
     saveCollection(stream, m_texParam,
                    [](android::base::Stream* stream,
                       const std::pair<const GLenum, GLint>& texParam) {
diff --git a/host/tests/CompositorVk_unittest.cpp b/host/tests/CompositorVk_unittest.cpp
index 25015e3..643dbef 100644
--- a/host/tests/CompositorVk_unittest.cpp
+++ b/host/tests/CompositorVk_unittest.cpp
@@ -292,7 +292,7 @@
         uint32_t physicalDeviceCount = 0;
         ASSERT_EQ(k_vk->vkEnumeratePhysicalDevices(m_vkInstance, &physicalDeviceCount, nullptr),
                   VK_SUCCESS);
-        ASSERT_GT(physicalDeviceCount, 0);
+        ASSERT_GT(physicalDeviceCount, (uint32_t)0);
         std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
         ASSERT_EQ(k_vk->vkEnumeratePhysicalDevices(m_vkInstance, &physicalDeviceCount,
                                                    physicalDevices.data()),
@@ -300,7 +300,7 @@
         for (const auto &device : physicalDevices) {
             uint32_t queueFamilyCount = 0;
             k_vk->vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
-            ASSERT_GT(queueFamilyCount, 0);
+            ASSERT_GT(queueFamilyCount, (uint32_t)0);
             std::vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyCount);
             k_vk->vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
                                                            queueFamilyProperties.data());
diff --git a/host/tests/FrameBuffer_unittest.cpp b/host/tests/FrameBuffer_unittest.cpp
index 001dfdb..e7db7bf 100644
--- a/host/tests/FrameBuffer_unittest.cpp
+++ b/host/tests/FrameBuffer_unittest.cpp
@@ -180,7 +180,7 @@
 TEST_F(FrameBufferTest, CreateColorBuffer) {
     HandleType handle =
         mFb->createColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     // FramBuffer::finalize handles color buffer destruction here
 }
 
@@ -188,7 +188,7 @@
 TEST_F(FrameBufferTest, CreateCloseColorBuffer) {
     HandleType handle =
         mFb->createColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     mFb->closeColorBuffer(handle);
 }
 
@@ -196,7 +196,7 @@
 TEST_F(FrameBufferTest, CreateOpenCloseColorBuffer) {
     HandleType handle =
         mFb->createColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     EXPECT_EQ(0, mFb->openColorBuffer(handle));
     mFb->closeColorBuffer(handle);
 }
@@ -206,7 +206,7 @@
 TEST_F(FrameBufferTest, CreateOpenUpdateCloseColorBuffer) {
     HandleType handle =
         mFb->createColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     EXPECT_EQ(0, mFb->openColorBuffer(handle));
 
     TestTexture forUpdate = createTestPatternRGBA8888(mWidth, mHeight);
@@ -225,7 +225,7 @@
 TEST_F(FrameBufferTest, CreateOpenUpdateCloseColorBuffer_ReadYUV420) {
     HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GL_RGBA,
                                                FRAMEWORK_FORMAT_YUV_420_888);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     EXPECT_EQ(0, mFb->openColorBuffer(handle));
 
     TestTexture forUpdate = createTestPatternRGBA8888(mWidth, mHeight);
@@ -252,7 +252,7 @@
 TEST_F(FrameBufferTest, CreateOpenUpdateCloseColorBuffer_ReadNV12) {
     HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GL_RGBA,
                                                FRAMEWORK_FORMAT_NV12);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     EXPECT_EQ(0, mFb->openColorBuffer(handle));
 
     TestTexture forUpdate = createTestPatternRGBA8888(mWidth, mHeight);
@@ -282,7 +282,7 @@
     mHeight = 8;
     HandleType handle_nv12 = mFb->createColorBuffer(mWidth, mHeight, GL_RGBA,
                                                     FRAMEWORK_FORMAT_NV12);
-    EXPECT_NE(0, handle_nv12);
+    EXPECT_NE((HandleType)0, handle_nv12);
     EXPECT_EQ(0, mFb->openColorBuffer(handle_nv12));
 
     uint8_t forUpdate[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -306,7 +306,7 @@
     // yuv420
     HandleType handle_yuv420 = mFb->createColorBuffer(
             mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_YUV_420_888);
-    EXPECT_NE(0, handle_yuv420);
+    EXPECT_NE((HandleType)0, handle_yuv420);
     EXPECT_EQ(0, mFb->openColorBuffer(handle_yuv420));
 
     uint32_t textures[2] = {1, 2};
@@ -334,7 +334,7 @@
     mWidth = 20 * 16;
     HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GL_RGBA,
                                                FRAMEWORK_FORMAT_YV12);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     EXPECT_EQ(0, mFb->openColorBuffer(handle));
 
     TestTexture forUpdate = createTestPatternRGBA8888(mWidth, mHeight);
@@ -364,7 +364,7 @@
 TEST_F(FrameBufferTest, CreateOpenUpdateCloseColorBuffer_FormatChange) {
     HandleType handle =
         mFb->createColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     EXPECT_EQ(0, mFb->openColorBuffer(handle));
 
     TestTexture forUpdate = createTestPatternRGBA8888(mWidth, mHeight);
@@ -384,19 +384,19 @@
 // Tests obtaining EGL configs from FrameBuffer.
 TEST_F(FrameBufferTest, Configs) {
     const EmulatedEglConfigList* configs = mFb->getConfigs();
-    EXPECT_GE(configs->size(), 0);
+    EXPECT_GE(configs->size(), (size_t)0);
 }
 
 // Tests creating GL context from FrameBuffer.
 TEST_F(FrameBufferTest, CreateEmulatedEglContext) {
     HandleType handle = mFb->createEmulatedEglContext(0, 0, GLESApi_3_0);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
 }
 
 // Tests creating window surface from FrameBuffer.
 TEST_F(FrameBufferTest, CreateEmulatedEglWindowSurface) {
     HandleType handle = mFb->createEmulatedEglWindowSurface(0, mWidth, mHeight);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
 }
 
 // Tests eglMakeCurrent from FrameBuffer.
@@ -745,7 +745,7 @@
 TEST_F(FrameBufferTest, CreateColorBufferBGRA) {
     HandleType handle =
         mFb->createColorBuffer(mWidth, mHeight, GL_BGRA_EXT, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     // FramBuffer::finalize handles color buffer destruction here
 }
 
@@ -754,7 +754,7 @@
 TEST_F(FrameBufferTest, DISABLED_ReadColorBufferSwitchRedBlue) {
     HandleType handle =
         mFb->createColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     EXPECT_EQ(0, mFb->openColorBuffer(handle));
 
     TestTexture forUpdate = createTestPatternRGBA8888(mWidth, mHeight);
@@ -769,8 +769,8 @@
     // Switch them back, so we get the original image
     uint8_t* forReadBytes = forRead.data();
 
-    for (uint32_t row = 0; row < mHeight; ++row) {
-        for (uint32_t col = 0; col < mWidth; ++col) {
+    for (int row = 0; row < mHeight; ++row) {
+        for (int col = 0; col < mWidth; ++col) {
             uint8_t* pixel = forReadBytes + mWidth * 4 * row + col * 4;
             // In RGBA8:
             //    3 2 1 0
@@ -801,7 +801,7 @@
     EXPECT_EQ(0, mFb->createDisplay(&id));
     uint32_t handle =
         mFb->createColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE);
-    EXPECT_NE(0, handle);
+    EXPECT_NE((HandleType)0, handle);
     EXPECT_EQ(0, mFb->setDisplayColorBuffer(id, handle));
     uint32_t getHandle = 0;
     mFb->getDisplayColorBuffer(id, &getHandle);
@@ -816,7 +816,7 @@
 TEST_F(FrameBufferTest, SetMultiDisplayPosition) {
     uint32_t id = FrameBuffer::s_invalidIdMultiDisplay;
     mFb->createDisplay(&id);
-    EXPECT_NE(0, id);
+    EXPECT_NE((uint32_t)0, id);
     uint32_t w = mWidth / 2, h = mHeight / 2;
     EXPECT_EQ(0, mFb->setDisplayPose(id, -1, -1, w, h));
     int32_t x, y;
diff --git a/host/tests/GLSnapshotTestStateUtils.cpp b/host/tests/GLSnapshotTestStateUtils.cpp
index 46b0af3..a29cac9 100644
--- a/host/tests/GLSnapshotTestStateUtils.cpp
+++ b/host/tests/GLSnapshotTestStateUtils.cpp
@@ -25,23 +25,25 @@
 namespace gfxstream {
 namespace gl {
 
+static constexpr const GLenum kNoError = GL_NO_ERROR;
+
 GLuint createBuffer(const GLESv2Dispatch* gl, GlBufferData data) {
     // We bind to GL_ARRAY_BUFFER in order to set up buffer data,
     // so let's hold on to what the old binding was so we can restore it
     GLuint currentArrayBuffer;
     gl->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&currentArrayBuffer);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
 
     GLuint name;
     gl->glGenBuffers(1, &name);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
 
     gl->glBindBuffer(GL_ARRAY_BUFFER, name);
     gl->glBufferData(GL_ARRAY_BUFFER, data.size, data.bytes, data.usage);
 
     // Restore the old binding
     gl->glBindBuffer(GL_ARRAY_BUFFER, currentArrayBuffer);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return name;
 };
 
@@ -89,21 +91,21 @@
     GLuint auxFramebuffer;
     gl->glGenFramebuffers(1, &auxFramebuffer);
     gl->glBindFramebuffer(GL_FRAMEBUFFER, auxFramebuffer);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
 
     gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target,
                                texture, level);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     gl->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
                      out.data());  // TODO(benzene): flexible format/type?
                                    // seems like RGBA/UNSIGNED_BYTE is the only
                                    // guaranteed supported format+type
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
 
     // restore old framebuffer
     gl->glBindFramebuffer(GL_FRAMEBUFFER, oldFramebuffer);
     gl->glDeleteFramebuffers(1, &auxFramebuffer);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
 
     return out;
 }
diff --git a/host/tests/GLSnapshotTesting.cpp b/host/tests/GLSnapshotTesting.cpp
index 8ea3945..062c6ee 100644
--- a/host/tests/GLSnapshotTesting.cpp
+++ b/host/tests/GLSnapshotTesting.cpp
@@ -32,6 +32,8 @@
 namespace gfxstream {
 namespace gl {
 
+static constexpr const GLenum kNoError = GL_NO_ERROR;
+
 using android::base::StdioStream;
 using android::snapshot::TextureLoader;
 using android::snapshot::TextureSaver;
@@ -71,7 +73,7 @@
                                                 GLboolean expected) {
     GLboolean current;
     gl->glGetBooleanv(name, &current);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return compareValue<GLboolean>(expected, current,
                                    "GL global boolean mismatch for parameter " +
                                            describeGlEnum(name) + ":");
@@ -82,7 +84,7 @@
                                             GLint expected) {
     GLint current;
     gl->glGetIntegerv(name, &current);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return compareValue<GLint>(expected, current,
                                "GL global int mismatch for parameter " +
                                        describeGlEnum(name) + ":");
@@ -94,7 +96,7 @@
                                               GLint expected) {
     GLint current;
     gl->glGetIntegeri_v(name, index, &current);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return compareValue<GLint>(expected, current,
                                "GL global int_i mismatch for parameter " +
                                        describeGlEnum(name) + ":" + std::to_string(index));
@@ -106,7 +108,7 @@
                                               GLfloat expected) {
     GLfloat current;
     gl->glGetFloatv(name, &current);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return compareValue<GLfloat>(expected, current,
                                  "GL global float mismatch for parameter " +
                                          describeGlEnum(name) + ":");
@@ -123,7 +125,7 @@
     }
 
     int mismatches = 0;
-    for (int i = 0; i < expected.size(); i++) {
+    for (size_t i = 0; i < expected.size(); i++) {
         if (i >= actual.size()) {
             if (mismatches < 10) {
                 mismatches++;
@@ -181,7 +183,7 @@
     std::vector<GLboolean> current;
     current.resize(std::max(size, static_cast<GLuint>(expected.size())));
     gl->glGetBooleanv(name, &current[0]);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return compareVector<GLboolean>(
             expected, current,
             "GL global booleanv parameter " + describeGlEnum(name));
@@ -197,7 +199,7 @@
     std::vector<GLboolean> current;
     current.resize(std::max(size, static_cast<GLuint>(expected.size())));
     gl->glGetBooleani_v(name, index,  &current[0]);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return compareVector<GLboolean>(
             expected, current,
             "GL global booleanv_i parameter " + describeGlEnum(name) + ":" + std::to_string(index) );
@@ -210,7 +212,7 @@
     std::vector<GLint> current;
     current.resize(std::max(size, static_cast<GLuint>(expected.size())));
     gl->glGetIntegerv(name, &current[0]);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return compareVector<GLint>(
             expected, current,
             "GL global intv parameter " + describeGlEnum(name));
@@ -225,7 +227,7 @@
     std::vector<GLfloat> current;
     current.resize(std::max(size, static_cast<GLuint>(expected.size())));
     gl->glGetFloatv(name, &current[0]);
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     return compareVector<GLfloat>(
             expected, current,
             "GL global floatv parameter " + describeGlEnum(name));
@@ -321,12 +323,12 @@
     {
         SCOPED_TRACE("during pre-snapshot default state check");
         defaultStateCheck();
-        ASSERT_EQ(GL_NO_ERROR, gl->glGetError());
+        ASSERT_EQ(kNoError, gl->glGetError());
     }
     {
         SCOPED_TRACE("during pre-snapshot state change");
         stateChange();
-        ASSERT_EQ(GL_NO_ERROR, gl->glGetError());
+        ASSERT_EQ(kNoError, gl->glGetError());
     }
     {
         SCOPED_TRACE("during pre-snapshot changed state check");
@@ -334,14 +336,14 @@
     }
     SnapshotTest::doSnapshot([this] {
         SCOPED_TRACE("during post-reset default state check");
-        EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+        EXPECT_EQ(kNoError, gl->glGetError());
         defaultStateCheck();
     });
-    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+    EXPECT_EQ(kNoError, gl->glGetError());
     {
         SCOPED_TRACE("during post-snapshot changed state check");
         changedStateCheck();
-        EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
+        EXPECT_EQ(kNoError, gl->glGetError());
     }
 }
 
diff --git a/host/tests/Magma_unittest.cpp b/host/tests/Magma_unittest.cpp
index 027f283..210e64a 100644
--- a/host/tests/Magma_unittest.cpp
+++ b/host/tests/Magma_unittest.cpp
@@ -34,25 +34,25 @@
     gfxstream::magma::MonotonicMap<uint64_t, MapTester> m;
 
     auto k1 = m.create(42, "hello");
-    EXPECT_EQ(k1, 1);
+    EXPECT_EQ(k1, (uint64_t)1);
     auto v1 = m.get(k1);
     ASSERT_NE(v1, nullptr);
-    EXPECT_EQ(v1->x, 42 + 5);
+    EXPECT_EQ(v1->x, (uint64_t)(42 + 5));
 
     auto k2 = m.create(5, "foo");
-    EXPECT_EQ(k2, 2);
+    EXPECT_EQ(k2, (uint64_t)2);
     auto v2 = m.get(k2);
     ASSERT_NE(v2, nullptr);
-    EXPECT_EQ(v2->x, 5 + 3);
+    EXPECT_EQ(v2->x, (uint64_t)(5 + 3));
 
     EXPECT_TRUE(m.erase(k1));
     EXPECT_FALSE(m.erase(k1));
 
     auto k3 = m.create(8, "bar");
-    EXPECT_EQ(k3, 3);
+    EXPECT_EQ(k3, (uint64_t)3);
     auto v3 = m.get(k3);
     ASSERT_NE(v3, nullptr);
-    EXPECT_EQ(v3->x, 11);
+    EXPECT_EQ(v3->x, (uint64_t)11);
 
     auto v2b = m.get(k2);
     EXPECT_EQ(v2, v2b);
diff --git a/host/tests/SampleApplication.cpp b/host/tests/SampleApplication.cpp
index 82b9712..422518e 100644
--- a/host/tests/SampleApplication.cpp
+++ b/host/tests/SampleApplication.cpp
@@ -345,9 +345,9 @@
         app2sfQueue.dequeueBuffer(&appItem);
         if (appItem.sync) { appItem.sync->wait(EGL_FOREVER_KHR); }
 
-        hwc_rect_t displayFrame = {0, 0, mWidth, mHeight/2};
-        hwc_frect_t crop = {0.0, 0.0, (float)mWidth, (float)mHeight};
-        hwc_color_t color = {0, 0, 0, 0};
+        displayFrame = {0, 0, mWidth, mHeight/2};
+        crop = {0.0, 0.0, (float)mWidth, (float)mHeight};
+        color = {0, 0, 0, 0};
         autoComposeDevice.configureLayer(1,
                                          appItem.colorBuffer,
                                          HWC2_COMPOSITION_DEVICE,
diff --git a/host/vulkan/VkAndroidNativeBuffer.cpp b/host/vulkan/VkAndroidNativeBuffer.cpp
index 40a7b84..d7436e4 100644
--- a/host/vulkan/VkAndroidNativeBuffer.cpp
+++ b/host/vulkan/VkAndroidNativeBuffer.cpp
@@ -114,48 +114,51 @@
     return structType == VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID;
 }
 
-VkResult prepareAndroidNativeBufferImage(VkEmulation* emu, VulkanDispatch* vk, VkDevice device,
-                                         android::base::BumpPool& allocator,
-                                         const VkImageCreateInfo* pCreateInfo,
-                                         const VkNativeBufferANDROID* nativeBufferANDROID,
-                                         const VkAllocationCallbacks* pAllocator,
-                                         const VkPhysicalDeviceMemoryProperties* memProps,
-                                         AndroidNativeBufferInfo* out) {
+/*static*/
+std::unique_ptr<AndroidNativeBufferInfo> AndroidNativeBufferInfo::create(
+    VkEmulation* emu,
+    VulkanDispatch* vk, VkDevice device, android::base::BumpPool& allocator,
+    const VkImageCreateInfo* pCreateInfo, const VkNativeBufferANDROID* nativeBufferANDROID,
+    const VkAllocationCallbacks* pAllocator, const VkPhysicalDeviceMemoryProperties* memProps) {
     bool colorBufferExportedToGl = false;
     bool externalMemoryCompatible = false;
 
-    out->vk = vk;
-    out->device = device;
-    out->vkFormat = pCreateInfo->format;
-    out->extent = pCreateInfo->extent;
-    out->usage = pCreateInfo->usage;
+    std::unique_ptr<AndroidNativeBufferInfo> out(new AndroidNativeBufferInfo());
+
+    out->mDeviceDispatch = vk;
+    out->mDevice = device;
+    out->mVkFormat = pCreateInfo->format;
+    out->mExtent = pCreateInfo->extent;
+    out->mUsage = pCreateInfo->usage;
 
     for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i) {
-        out->queueFamilyIndices.push_back(pCreateInfo->pQueueFamilyIndices[i]);
+        out->mQueueFamilyIndices.push_back(pCreateInfo->pQueueFamilyIndices[i]);
     }
 
-    out->format = nativeBufferANDROID->format;
-    out->stride = nativeBufferANDROID->stride;
-    out->colorBufferHandle = *static_cast<const uint32_t*>(nativeBufferANDROID->handle);
+    out->mAhbFormat = nativeBufferANDROID->format;
+    out->mStride = nativeBufferANDROID->stride;
+    out->mColorBufferHandle = *static_cast<const uint32_t*>(nativeBufferANDROID->handle);
 
-    if (!emu->getColorBufferShareInfo(out->colorBufferHandle, &colorBufferExportedToGl,
+    if (!emu->getColorBufferShareInfo(out->mColorBufferHandle, &colorBufferExportedToGl,
                                       &externalMemoryCompatible)) {
-        VK_ANB_ERR("Failed to query if ColorBuffer:%d exported to GL.", out->colorBufferHandle);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        VK_ANB_ERR("Failed to query if ColorBuffer:%d exported to GL.", out->mColorBufferHandle);
+        return nullptr;
     }
 
     if (externalMemoryCompatible) {
-        emu->releaseColorBufferForGuestUse(out->colorBufferHandle);
-        out->externallyBacked = true;
+        emu->releaseColorBufferForGuestUse(out->mColorBufferHandle);
+        out->mExternallyBacked = true;
     }
 
-    out->useVulkanNativeImage = (emu && emu->isGuestVulkanOnly()) || colorBufferExportedToGl;
+    out->mUseVulkanNativeImage =
+        (emu && emu->isGuestVulkanOnly()) || colorBufferExportedToGl;
 
     VkDeviceSize bindOffset = 0;
-    if (out->externallyBacked) {
+    if (out->mExternallyBacked) {
         VkImageCreateInfo createImageCi;
         deepcopy_VkImageCreateInfo(&allocator, VK_STRUCTURE_TYPE_MAX_ENUM, pCreateInfo,
                                    &createImageCi);
+
         auto* nativeBufferAndroid = vk_find_struct<VkNativeBufferANDROID>(&createImageCi);
         if (!nativeBufferAndroid) {
             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
@@ -169,18 +172,18 @@
         if (importedColorBufferHandle == 0) {
             VK_ANB_ERR(
                 "Failed to prepare ANB image: attempted to import a non-existent ColorBuffer.");
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return nullptr;
         }
         const auto importedColorBufferInfoOpt = emu->getColorBufferInfo(importedColorBufferHandle);
         if (!importedColorBufferInfoOpt) {
             VK_ANB_ERR("Failed to prepare ANB image: ColorBuffer:%d info not found.",
                        importedColorBufferHandle);
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return nullptr;
         }
         const auto& importedColorBufferInfo = *importedColorBufferInfoOpt;
         if (pCreateInfo == nullptr) {
             VK_ANB_ERR("Failed to prepare ANB image: invalid pCreateInfo.");
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return nullptr;
         }
         if (pCreateInfo->extent.width > importedColorBufferInfo.width) {
             VK_ANB_ERR(
@@ -188,7 +191,7 @@
                 "importing ColorBuffer:%d which only has width:%d",
                 pCreateInfo->extent.width, importedColorBufferHandle,
                 importedColorBufferInfo.width);
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return nullptr;
         }
         if (pCreateInfo->extent.height > importedColorBufferInfo.height) {
             VK_ANB_ERR(
@@ -196,7 +199,7 @@
                 "importing ColorBuffer:%d which only has height:%d",
                 pCreateInfo->extent.height, importedColorBufferHandle,
                 importedColorBufferInfo.height);
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return nullptr;
         }
         const auto& importedColorBufferMemoryInfo = importedColorBufferInfo.memory;
 
@@ -209,30 +212,31 @@
             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
                 << "Unhandled VkExternalMemoryImageCreateInfo in the pNext chain.";
         }
+
         // Create the image with extension structure about external backing.
         VkExternalMemoryImageCreateInfo extImageCi = {
             VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
             0,
             static_cast<VkExternalMemoryHandleTypeFlags>(emu->getDefaultExternalMemoryHandleType()),
         };
-
 #if defined(__APPLE__)
         if (emu->supportsMoltenVk()) {
             // Change handle type requested to metal handle
             extImageCi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
         }
 #endif
-
         vk_insert_struct(createImageCi, extImageCi);
 
-        VkResult createResult = vk->vkCreateImage(device, &createImageCi, pAllocator, &out->image);
+        VkResult createResult =
+            vk->vkCreateImage(out->mDevice, &createImageCi, pAllocator, &out->mImage);
+        if (createResult != VK_SUCCESS) {
+            return nullptr;
+        }
 
-        if (createResult != VK_SUCCESS) return createResult;
+        vk->vkGetImageMemoryRequirements(out->mDevice, out->mImage, &out->mImageMemoryRequirements);
 
-        vk->vkGetImageMemoryRequirements(device, out->image, &out->memReqs);
-
-        if (out->memReqs.size < importedColorBufferMemoryInfo.size) {
-            out->memReqs.size = importedColorBufferMemoryInfo.size;
+        if (out->mImageMemoryRequirements.size < importedColorBufferMemoryInfo.size) {
+            out->mImageMemoryRequirements.size = importedColorBufferMemoryInfo.size;
         }
 
         VkMemoryDedicatedAllocateInfo dedicatedInfo = {
@@ -243,15 +247,16 @@
         };
         VkMemoryDedicatedAllocateInfo* dedicatedInfoPtr = nullptr;
         if (importedColorBufferMemoryInfo.dedicatedAllocation) {
-            dedicatedInfo.image = out->image;
+            dedicatedInfo.image = out->mImage;
             dedicatedInfoPtr = &dedicatedInfo;
         }
 
-        if (!emu->importExternalMemory(vk, device, &importedColorBufferMemoryInfo, dedicatedInfoPtr,
-                                       &out->imageMemory)) {
+        if (!emu->importExternalMemory(out->mDeviceDispatch, out->mDevice,
+                                  &importedColorBufferMemoryInfo, dedicatedInfoPtr,
+                                  &out->mImageMemory)) {
             VK_ANB_ERR("VK_ANDROID_native_buffer: Failed to import external memory%s",
                        importedColorBufferMemoryInfo.dedicatedAllocation ? " (dedicated)" : "");
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return nullptr;
         }
 
         bindOffset = importedColorBufferMemoryInfo.bindOffset;
@@ -261,17 +266,19 @@
         VkImageCreateInfo infoNoNative = *pCreateInfo;
         infoNoNative.pNext = nullptr;
         infoNoNative.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
-        VkResult createResult = vk->vkCreateImage(device, &infoNoNative, pAllocator, &out->image);
 
-        if (createResult != VK_SUCCESS) return createResult;
+        VkResult createResult = vk->vkCreateImage(device, &infoNoNative, pAllocator, &out->mImage);
+        if (createResult != VK_SUCCESS) {
+            return nullptr;
+        }
 
-        vk->vkGetImageMemoryRequirements(device, out->image, &out->memReqs);
+        vk->vkGetImageMemoryRequirements(device, out->mImage, &out->mImageMemoryRequirements);
 
         uint32_t imageMemoryTypeIndex = 0;
         bool imageMemoryTypeIndexFound = false;
 
         for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
-            bool supported = out->memReqs.memoryTypeBits & (1 << i);
+            bool supported = out->mImageMemoryRequirements.memoryTypeBits & (1 << i);
             if (supported) {
                 imageMemoryTypeIndex = i;
                 imageMemoryTypeIndexFound = true;
@@ -283,35 +290,31 @@
             VK_ANB_ERR(
                 "VK_ANDROID_native_buffer: could not obtain "
                 "image memory type index");
-            teardownAndroidNativeBufferImage(vk, out);
-            return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+            return nullptr;
         }
 
-        out->imageMemoryTypeIndex = imageMemoryTypeIndex;
+        out->mImageMemoryTypeIndex = imageMemoryTypeIndex;
 
-        VkMemoryAllocateInfo allocInfo = {
+        const VkMemoryAllocateInfo allocInfo = {
             VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
             0,
-            out->memReqs.size,
-            out->imageMemoryTypeIndex,
+            out->mImageMemoryRequirements.size,
+            out->mImageMemoryTypeIndex,
         };
-
-        if (VK_SUCCESS != vk->vkAllocateMemory(device, &allocInfo, nullptr, &out->imageMemory)) {
+        if (VK_SUCCESS != vk->vkAllocateMemory(device, &allocInfo, nullptr, &out->mImageMemory)) {
             VK_ANB_ERR(
                 "VK_ANDROID_native_buffer: could not allocate "
                 "image memory. requested size: %zu",
-                (size_t)(out->memReqs.size));
-            teardownAndroidNativeBufferImage(vk, out);
-            return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+                (size_t)(out->mImageMemoryRequirements.size));
+            return nullptr;
         }
     }
 
-    if (VK_SUCCESS != vk->vkBindImageMemory(device, out->image, out->imageMemory, bindOffset)) {
+    if (VK_SUCCESS != vk->vkBindImageMemory(device, out->mImage, out->mImageMemory, bindOffset)) {
         VK_ANB_ERR(
             "VK_ANDROID_native_buffer: could not bind "
             "image memory.");
-        teardownAndroidNativeBufferImage(vk, out);
-        return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+        return nullptr;
     }
 
     // Allocate a staging memory and set up the staging buffer.
@@ -322,123 +325,115 @@
             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
             0,
             0,
-            out->memReqs.size,
+            out->mImageMemoryRequirements.size,
             VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
             VK_SHARING_MODE_EXCLUSIVE,
             0,
             nullptr,
         };
-        if (out->queueFamilyIndices.size() > 1) {
+        if (out->mQueueFamilyIndices.size() > 1) {
             stagingBufferCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT;
             stagingBufferCreateInfo.queueFamilyIndexCount =
-                static_cast<uint32_t>(out->queueFamilyIndices.size());
-            stagingBufferCreateInfo.pQueueFamilyIndices = out->queueFamilyIndices.data();
+                static_cast<uint32_t>(out->mQueueFamilyIndices.size());
+            stagingBufferCreateInfo.pQueueFamilyIndices = out->mQueueFamilyIndices.data();
         }
 
         if (VK_SUCCESS !=
-            vk->vkCreateBuffer(device, &stagingBufferCreateInfo, nullptr, &out->stagingBuffer)) {
+            vk->vkCreateBuffer(device, &stagingBufferCreateInfo, nullptr, &out->mStagingBuffer)) {
             VK_ANB_ERR(
                 "VK_ANDROID_native_buffer: could not create "
                 "staging buffer.");
-            teardownAndroidNativeBufferImage(vk, out);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
+            return nullptr;
         }
 
-        VkMemoryRequirements stagingMemReqs;
-        vk->vkGetBufferMemoryRequirements(device, out->stagingBuffer, &stagingMemReqs);
-        if (stagingMemReqs.size < out->memReqs.size) {
-            VK_ANB_ERR(
-                "VK_ANDROID_native_buffer: unexpected staging buffer size");
-            teardownAndroidNativeBufferImage(vk, out);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        VkMemoryRequirements stagingMemoryRequirements;
+        vk->vkGetBufferMemoryRequirements(device, out->mStagingBuffer, &stagingMemoryRequirements);
+        if (stagingMemoryRequirements.size < out->mImageMemoryRequirements.size) {
+            VK_ANB_ERR("VK_ANDROID_native_buffer: unexpected staging buffer size");
+            return nullptr;
         }
 
+        uint32_t stagingMemoryTypeIndex = -1;
         bool stagingIndexRes =
-            getStagingMemoryTypeIndex(vk, device, memProps, &out->stagingMemoryTypeIndex);
-
+            getStagingMemoryTypeIndex(vk, device, memProps, &stagingMemoryTypeIndex);
         if (!stagingIndexRes) {
             VK_ANB_ERR(
                 "VK_ANDROID_native_buffer: could not obtain "
                 "staging memory type index");
-            teardownAndroidNativeBufferImage(vk, out);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
+            return nullptr;
         }
 
         VkMemoryAllocateInfo allocInfo = {
             VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
             0,
-            stagingMemReqs.size,
-            out->stagingMemoryTypeIndex,
+            stagingMemoryRequirements.size,
+            stagingMemoryTypeIndex,
         };
 
-        VkResult res = vk->vkAllocateMemory(device, &allocInfo, nullptr, &out->stagingMemory);
+        VkResult res =
+            vk->vkAllocateMemory(device, &allocInfo, nullptr, &out->mStagingBufferMemory);
         if (VK_SUCCESS != res) {
             VK_ANB_ERR(
                 "VK_ANDROID_native_buffer: could not allocate staging memory. "
                 "res = %d. requested size: %zu",
-                (int)res, (size_t)(out->memReqs.size));
-            teardownAndroidNativeBufferImage(vk, out);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
+                (int)res, (size_t)(stagingMemoryRequirements.size));
+            return nullptr;
         }
 
         if (VK_SUCCESS !=
-            vk->vkBindBufferMemory(device, out->stagingBuffer, out->stagingMemory, 0)) {
+            vk->vkBindBufferMemory(device, out->mStagingBuffer, out->mStagingBufferMemory, 0)) {
             VK_ANB_ERR(
                 "VK_ANDROID_native_buffer: could not bind "
                 "staging buffer to staging memory.");
-            teardownAndroidNativeBufferImage(vk, out);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
+            return nullptr;
         }
 
-        if (VK_SUCCESS != vk->vkMapMemory(device, out->stagingMemory, 0, VK_WHOLE_SIZE, 0,
-                                          (void**)&out->mappedStagingPtr)) {
-            VK_ANB_ERR(
-                "VK_ANDROID_native_buffer: could not map "
-                "staging buffer.");
-            teardownAndroidNativeBufferImage(vk, out);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        if (VK_SUCCESS != vk->vkMapMemory(device, out->mStagingBufferMemory, 0, VK_WHOLE_SIZE, 0,
+                                          (void**)&out->mMappedStagingPtr)) {
+            VK_ANB_ERR("VK_ANDROID_native_buffer: could not map staging buffer.");
+            return nullptr;
         }
     }
 
-    out->qsriWaitFencePool =
-        std::make_unique<AndroidNativeBufferInfo::QsriWaitFencePool>(out->vk, out->device);
-    out->qsriTimeline = std::make_unique<VkQsriTimeline>();
-    return VK_SUCCESS;
+    out->mQsriWaitFencePool = std::make_unique<AndroidNativeBufferInfo::QsriWaitFencePool>(
+        out->mDeviceDispatch, out->mDevice);
+    out->mQsriTimeline = std::make_unique<VkQsriTimeline>();
+
+    return out;
 }
 
-void teardownAndroidNativeBufferImage(VulkanDispatch* vk, AndroidNativeBufferInfo* anbInfo) {
-    auto device = anbInfo->device;
-
-    auto image = anbInfo->image;
-    auto imageMemory = anbInfo->imageMemory;
-
-    auto stagingBuffer = anbInfo->stagingBuffer;
-    auto mappedPtr = anbInfo->mappedStagingPtr;
-    auto stagingMemory = anbInfo->stagingMemory;
-
-    for (auto queueState : anbInfo->queueStates) {
-        queueState.teardown(vk, device);
+AndroidNativeBufferInfo::~AndroidNativeBufferInfo() {
+    if (mDeviceDispatch == nullptr) {
+        return;
     }
 
-    anbInfo->queueStates.clear();
+    if (mDevice == VK_NULL_HANDLE) {
+        return;
+    }
 
-    anbInfo->acquireQueueState.teardown(vk, device);
+    for (auto& queueState : mQueueStates) {
+        queueState.teardown(mDeviceDispatch, mDevice);
+    }
+    mQueueStates.clear();
 
-    if (image) vk->vkDestroyImage(device, image, nullptr);
-    if (imageMemory) vk->vkFreeMemory(device, imageMemory, nullptr);
-    if (stagingBuffer) vk->vkDestroyBuffer(device, stagingBuffer, nullptr);
-    if (mappedPtr) vk->vkUnmapMemory(device, stagingMemory);
-    if (stagingMemory) vk->vkFreeMemory(device, stagingMemory, nullptr);
+    mAcquireQueueState.teardown(mDeviceDispatch, mDevice);
 
-    anbInfo->vk = nullptr;
-    anbInfo->device = VK_NULL_HANDLE;
-    anbInfo->image = VK_NULL_HANDLE;
-    anbInfo->imageMemory = VK_NULL_HANDLE;
-    anbInfo->stagingBuffer = VK_NULL_HANDLE;
-    anbInfo->mappedStagingPtr = nullptr;
-    anbInfo->stagingMemory = VK_NULL_HANDLE;
+    if (mImage != VK_NULL_HANDLE) {
+        mDeviceDispatch->vkDestroyImage(mDevice, mImage, nullptr);
+    }
+    if (mImageMemory != VK_NULL_HANDLE) {
+        mDeviceDispatch->vkFreeMemory(mDevice, mImageMemory, nullptr);
+    }
 
-    anbInfo->qsriWaitFencePool = nullptr;
+    if (mMappedStagingPtr != nullptr) {
+        mDeviceDispatch->vkUnmapMemory(mDevice, mStagingBufferMemory);
+    }
+    if (mStagingBuffer != VK_NULL_HANDLE) {
+        mDeviceDispatch->vkDestroyBuffer(mDevice, mStagingBuffer, nullptr);
+    }
+    if (mStagingBufferMemory != VK_NULL_HANDLE) {
+        mDeviceDispatch->vkFreeMemory(mDevice, mStagingBufferMemory, nullptr);
+    }
 }
 
 void getGralloc0Usage(VkFormat format, VkImageUsageFlags imageUsage, int* usage_out) {
@@ -546,15 +541,14 @@
     queueFamilyIndex = 0;
 }
 
-VkResult setAndroidNativeImageSemaphoreSignaled(VkEmulation* emu, VulkanDispatch* vk,
-                                                VkDevice device, VkQueue defaultQueue,
-                                                uint32_t defaultQueueFamilyIndex,
-                                                std::mutex* defaultQueueMutex,
-                                                VkSemaphore semaphore, VkFence fence,
-                                                AndroidNativeBufferInfo* anbInfo) {
-    bool firstTimeSetup = !anbInfo->everSynced && !anbInfo->everAcquired;
-
-    anbInfo->everAcquired = true;
+VkResult AndroidNativeBufferInfo::on_vkAcquireImageANDROID(VkEmulation* emu,
+                                                           VulkanDispatch* vk, VkDevice device,
+                                                           VkQueue defaultQueue,
+                                                           uint32_t defaultQueueFamilyIndex,
+                                                           std::mutex* defaultQueueMutex,
+                                                           VkSemaphore semaphore, VkFence fence) {
+    const bool firstTimeSetup = !mEverSynced && !mEverAcquired;
+    mEverAcquired = true;
 
     if (firstTimeSetup) {
         VkSubmitInfo submitInfo = {
@@ -570,92 +564,90 @@
         };
         std::lock_guard<std::mutex> qlock(*defaultQueueMutex);
         VK_CHECK(vk->vkQueueSubmit(defaultQueue, 1, &submitInfo, fence));
+        return VK_SUCCESS;
+    }
+
+    // Setup queue state for this queue family index.
+    auto queueFamilyIndex = mLastUsedQueueFamilyIndex;
+    if (queueFamilyIndex >= mQueueStates.size()) {
+        mQueueStates.resize(queueFamilyIndex + 1);
+    }
+    QueueState& queueState = mQueueStates[queueFamilyIndex];
+    if (!queueState.queue) {
+        queueState.setup(mDeviceDispatch, mDevice, defaultQueue, queueFamilyIndex,
+                         defaultQueueMutex);
+    }
+
+    // If we used the Vulkan image without copying it back
+    // to the CPU, reset the layout to PRESENT.
+    if (mUseVulkanNativeImage) {
+        VkCommandBufferBeginInfo beginInfo = {
+            VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+            0,
+            VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+            nullptr /* no inheritance info */,
+        };
+
+        vk->vkBeginCommandBuffer(queueState.cb2, &beginInfo);
+
+        emu->getDebugUtilsHelper().cmdBeginDebugLabel(
+            queueState.cb2, "vkAcquireImageANDROID(ColorBuffer:%d)", mColorBufferHandle);
+
+        VkImageMemoryBarrier queueTransferBarrier = {
+            .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+            .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
+            .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
+            .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+            .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+            .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
+            .dstQueueFamilyIndex = mLastUsedQueueFamilyIndex,
+            .image = mImage,
+            .subresourceRange =
+                {
+                    VK_IMAGE_ASPECT_COLOR_BIT,
+                    0,
+                    1,
+                    0,
+                    1,
+                },
+        };
+        vk->vkCmdPipelineBarrier(queueState.cb2, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+                                 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
+                                 &queueTransferBarrier);
+
+        emu->getDebugUtilsHelper().cmdEndDebugLabel(queueState.cb2);
+
+        vk->vkEndCommandBuffer(queueState.cb2);
+
+        VkSubmitInfo submitInfo = {
+            VK_STRUCTURE_TYPE_SUBMIT_INFO,
+            0,
+            0,
+            nullptr,
+            nullptr,
+            1,
+            &queueState.cb2,
+            (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
+            semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
+        };
+
+        std::lock_guard<std::mutex> queueLock(*queueState.queueMutex);
+        // TODO(kaiyili): initiate ownership transfer from DisplayVk here
+        VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, fence));
     } else {
-        // Setup queue state for this queue family index.
-        auto queueFamilyIndex = anbInfo->lastUsedQueueFamilyIndex;
-        if (queueFamilyIndex >= anbInfo->queueStates.size()) {
-            anbInfo->queueStates.resize(queueFamilyIndex + 1);
-        }
-        AndroidNativeBufferInfo::QueueState& queueState =
-            anbInfo->queueStates[queueFamilyIndex];
-        if (!queueState.queue) {
-            queueState.setup(vk, anbInfo->device, defaultQueue, queueFamilyIndex, defaultQueueMutex);
-        }
-
-        // If we used the Vulkan image without copying it back
-        // to the CPU, reset the layout to PRESENT.
-        if (anbInfo->useVulkanNativeImage) {
-            VkCommandBufferBeginInfo beginInfo = {
-                VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
-                0,
-                VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
-                nullptr /* no inheritance info */,
-            };
-
-            vk->vkBeginCommandBuffer(queueState.cb2, &beginInfo);
-
-            emu->getDebugUtilsHelper().cmdBeginDebugLabel(queueState.cb2,
-                                                          "vkAcquireImageANDROID(ColorBuffer:%d)",
-                                                          anbInfo->colorBufferHandle);
-
-            VkImageMemoryBarrier queueTransferBarrier = {
-                .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
-                .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
-                .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
-                .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
-                .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
-                .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
-                .dstQueueFamilyIndex = anbInfo->lastUsedQueueFamilyIndex,
-                .image = anbInfo->image,
-                .subresourceRange =
-                    {
-                        VK_IMAGE_ASPECT_COLOR_BIT,
-                        0,
-                        1,
-                        0,
-                        1,
-                    },
-            };
-            vk->vkCmdPipelineBarrier(queueState.cb2, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
-                                     VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
-                                     1, &queueTransferBarrier);
-
-            emu->getDebugUtilsHelper().cmdEndDebugLabel(queueState.cb2);
-
-            vk->vkEndCommandBuffer(queueState.cb2);
-
-            VkSubmitInfo submitInfo = {
-                VK_STRUCTURE_TYPE_SUBMIT_INFO,
-                0,
-                0,
-                nullptr,
-                nullptr,
-                1,
-                &queueState.cb2,
-                (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
-                semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
-            };
-
-            std::lock_guard<std::mutex> queueLock(*queueState.queueMutex);
-            // TODO(kaiyili): initiate ownership transfer from DisplayVk here
-            VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, fence));
-        } else {
-            const AndroidNativeBufferInfo::QueueState& queueState =
-                anbInfo->queueStates[anbInfo->lastUsedQueueFamilyIndex];
-            VkSubmitInfo submitInfo = {
-                VK_STRUCTURE_TYPE_SUBMIT_INFO,
-                0,
-                0,
-                nullptr,
-                nullptr,
-                0,
-                nullptr,
-                (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
-                semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
-            };
-            std::lock_guard<std::mutex> queueLock(*queueState.queueMutex);
-            VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, fence));
-        }
+        const VkSubmitInfo submitInfo = {
+            VK_STRUCTURE_TYPE_SUBMIT_INFO,
+            0,
+            0,
+            nullptr,
+            nullptr,
+            0,
+            nullptr,
+            (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
+            semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
+        };
+        std::lock_guard<std::mutex> queueLock(*queueState.queueMutex);
+        VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, fence));
     }
 
     return VK_SUCCESS;
@@ -663,10 +655,10 @@
 
 static constexpr uint64_t kTimeoutNs = 3ULL * 1000000000ULL;
 
-VkResult syncImageToColorBuffer(VkEmulation* emu, VulkanDispatch* vk, uint32_t queueFamilyIndex,
-                                VkQueue queue, std::mutex* queueMutex, uint32_t waitSemaphoreCount,
-                                const VkSemaphore* pWaitSemaphores, int* pNativeFenceFd,
-                                AndroidNativeBufferInfo* anbInfo) {
+VkResult AndroidNativeBufferInfo::on_vkQueueSignalReleaseImageANDROID(
+    VkEmulation* emu, VulkanDispatch* vk, uint32_t queueFamilyIndex,
+    VkQueue queue, std::mutex* queueMutex, uint32_t waitSemaphoreCount,
+    const VkSemaphore* pWaitSemaphores, int* pNativeFenceFd) {
     const uint64_t traceId = gfxstream::host::GetUniqueTracingId();
     GFXSTREAM_TRACE_EVENT(GFXSTREAM_TRACE_DEFAULT_CATEGORY, "vkQSRI syncImageToColorBuffer()",
                           GFXSTREAM_TRACE_FLOW(traceId));
@@ -677,18 +669,18 @@
     // Implicitly synchronized
     *pNativeFenceFd = -1;
 
-    anbInfo->everSynced = true;
-    anbInfo->lastUsedQueueFamilyIndex = queueFamilyIndex;
+    mEverSynced = true;
+    mLastUsedQueueFamilyIndex = queueFamilyIndex;
 
     // Setup queue state for this queue family index.
-    if (queueFamilyIndex >= anbInfo->queueStates.size()) {
-        anbInfo->queueStates.resize(queueFamilyIndex + 1);
+    if (queueFamilyIndex >= mQueueStates.size()) {
+        mQueueStates.resize(queueFamilyIndex + 1);
     }
 
-    auto& queueState = anbInfo->queueStates[queueFamilyIndex];
+    auto& queueState = mQueueStates[queueFamilyIndex];
 
     if (!queueState.queue) {
-        queueState.setup(vk, anbInfo->device, queue, queueFamilyIndex, queueMutex);
+        queueState.setup(vk, mDevice, queue, queueFamilyIndex, queueMutex);
     }
 
     // Record our synchronization commands.
@@ -702,12 +694,11 @@
     vk->vkBeginCommandBuffer(queueState.cb, &beginInfo);
 
     emu->getDebugUtilsHelper().cmdBeginDebugLabel(
-        queueState.cb, "vkQueueSignalReleaseImageANDROID(ColorBuffer:%d)",
-        anbInfo->colorBufferHandle);
+        queueState.cb, "vkQueueSignalReleaseImageANDROID(ColorBuffer:%d)", mColorBufferHandle);
 
     // If using the Vulkan image directly (rather than copying it back to
     // the CPU), change its layout for that use.
-    if (anbInfo->useVulkanNativeImage) {
+    if (mUseVulkanNativeImage) {
         VkImageMemoryBarrier queueTransferBarrier = {
             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
             .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
@@ -716,7 +707,7 @@
             .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
             .srcQueueFamilyIndex = queueFamilyIndex,
             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
-            .image = anbInfo->image,
+            .image = mImage,
             .subresourceRange =
                 {
                     VK_IMAGE_ASPECT_COLOR_BIT,
@@ -747,7 +738,7 @@
             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
             VK_QUEUE_FAMILY_IGNORED,
             VK_QUEUE_FAMILY_IGNORED,
-            anbInfo->image,
+            mImage,
             {
                 VK_IMAGE_ASPECT_COLOR_BIT,
                 0,
@@ -763,8 +754,8 @@
 
         VkBufferImageCopy region = {
             0 /* buffer offset */,
-            anbInfo->extent.width,
-            anbInfo->extent.height,
+            mExtent.width,
+            mExtent.height,
             {
                 VK_IMAGE_ASPECT_COLOR_BIT,
                 0,
@@ -772,12 +763,11 @@
                 1,
             },
             {0, 0, 0},
-            anbInfo->extent,
+            mExtent,
         };
 
-        vk->vkCmdCopyImageToBuffer(queueState.cb, anbInfo->image,
-                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, anbInfo->stagingBuffer, 1,
-                                   &region);
+        vk->vkCmdCopyImageToBuffer(queueState.cb, mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                                   mStagingBuffer, 1, &region);
 
         // Transfer back to present src.
         VkImageMemoryBarrier backToPresentSrc = {
@@ -789,7 +779,7 @@
             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
             VK_QUEUE_FAMILY_IGNORED,
             VK_QUEUE_FAMILY_IGNORED,
-            anbInfo->image,
+            mImage,
             {
                 VK_IMAGE_ASPECT_COLOR_BIT,
                 0,
@@ -824,15 +814,15 @@
     };
 
     // TODO(kaiyili): initiate ownership transfer to DisplayVk here.
-    VkFence qsriFence = anbInfo->qsriWaitFencePool->getFenceFromPool();
+    VkFence qsriFence = mQsriWaitFencePool->getFenceFromPool();
     std::lock_guard<std::mutex> qLock(*queueMutex);
     VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, qsriFence));
-    auto waitForQsriFenceTask = [anbInfo, vk, device = anbInfo->device, qsriFence, traceId] {
+    auto waitForQsriFenceTask = [this, vk, device = mDevice, qsriFence, traceId] {
         GFXSTREAM_TRACE_EVENT(GFXSTREAM_TRACE_DEFAULT_CATEGORY, "Wait for QSRI fence",
                               GFXSTREAM_TRACE_FLOW(traceId));
 
-        VK_ANB_DEBUG_OBJ(anbInfo, "wait callback: enter");
-        VK_ANB_DEBUG_OBJ(anbInfo, "wait callback: wait for fence %p...", qsriFence);
+        VK_ANB_DEBUG_OBJ(this, "wait callback: enter");
+        VK_ANB_DEBUG_OBJ(this, "wait callback: wait for fence %p...", qsriFence);
         VkResult res = vk->vkWaitForFences(device, 1, &qsriFence, VK_FALSE, kTimeoutNs);
         switch (res) {
             case VK_SUCCESS:
@@ -844,38 +834,35 @@
                 ERR("Failed to wait for QSRI fence: %s\n", string_VkResult(res));
                 VK_CHECK(res);
         }
-        VK_ANB_DEBUG_OBJ(anbInfo, "wait callback: wait for fence %p...(done)", qsriFence);
-        anbInfo->qsriWaitFencePool->returnFence(qsriFence);
+        VK_ANB_DEBUG_OBJ(this, "wait callback: wait for fence %p...(done)", qsriFence);
+        mQsriWaitFencePool->returnFence(qsriFence);
     };
     fb->unlock();
 
-    if (anbInfo->useVulkanNativeImage) {
-        VK_ANB_DEBUG_OBJ(anbInfo, "using native image, so use sync thread to wait");
+    if (mUseVulkanNativeImage) {
+        VK_ANB_DEBUG_OBJ(this, "using native image, so use sync thread to wait");
         // Queue wait to sync thread with completion callback
         // Pass anbInfo by value to get a ref
         auto waitable = emu->getCallbacks().scheduleAsyncWork(
-            [waitForQsriFenceTask = std::move(waitForQsriFenceTask), anbInfo]() mutable {
+            [waitForQsriFenceTask = std::move(waitForQsriFenceTask), this]() mutable {
                 waitForQsriFenceTask();
-                anbInfo->qsriTimeline->signalNextPresentAndPoll();
+                mQsriTimeline->signalNextPresentAndPoll();
             },
             "wait for the guest Qsri VkFence signaled");
 
         queueState.latestUse = std::move(waitable);
     } else {
-        VK_ANB_DEBUG_OBJ(anbInfo, "not using native image, so wait right away");
+        VK_ANB_DEBUG_OBJ(this, "not using native image, so wait right away");
         waitForQsriFenceTask();
 
-        VkMappedMemoryRange toInvalidate = {
-            VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, anbInfo->stagingMemory, 0, VK_WHOLE_SIZE,
+        const VkMappedMemoryRange toInvalidate = {
+            VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, mStagingBufferMemory, 0, VK_WHOLE_SIZE,
         };
-
-        vk->vkInvalidateMappedMemoryRanges(anbInfo->device, 1, &toInvalidate);
-
-        uint32_t colorBufferHandle = anbInfo->colorBufferHandle;
+        vk->vkInvalidateMappedMemoryRanges(mDevice, 1, &toInvalidate);
 
         // Copy to from staging buffer to color buffer
         uint32_t bpp = 4; /* format always rgba8...not */
-        switch (anbInfo->vkFormat) {
+        switch (mVkFormat) {
             case VK_FORMAT_R5G6B5_UNORM_PACK16:
                 bpp = 2;
                 break;
@@ -888,15 +875,34 @@
                 bpp = 4;
                 break;
         }
-        const void* bytes = anbInfo->mappedStagingPtr;
-        const size_t bytesSize = bpp * anbInfo->extent.width * anbInfo->extent.height;
-        emu->getCallbacks().flushColorBufferFromBytes(colorBufferHandle, bytes, bytesSize);
+        const void* bytes = mMappedStagingPtr;
+        const size_t bytesSize = bpp * mExtent.width * mExtent.height;
+        emu->getCallbacks().flushColorBufferFromBytes(mColorBufferHandle, bytes, bytesSize);
 
-        anbInfo->qsriTimeline->signalNextPresentAndPoll();
+        mQsriTimeline->signalNextPresentAndPoll();
     }
 
     return VK_SUCCESS;
 }
 
+AsyncResult AndroidNativeBufferInfo::registerQsriCallback(VkImage image,
+                                                          VkQsriTimeline::Callback callback) {
+    if (!mDeviceDispatch) {
+        ERR("Attempted to register QSRI callback on VkImage:%p with uninitialized ANB info.",
+            image);
+        return AsyncResult::FAIL_AND_CALLBACK_NOT_SCHEDULED;
+    }
+
+    // Could be null or mismatched image, check later
+    if (image != mImage) {
+        ERR("Attempted on register QSRI callback on VkImage:%p with wrong image %p.", image,
+            mImage);
+        return AsyncResult::FAIL_AND_CALLBACK_NOT_SCHEDULED;
+    }
+
+    mQsriTimeline->registerCallbackForNextPresentAndPoll(std::move(callback));
+    return AsyncResult::OK_AND_CALLBACK_SCHEDULED;
+}
+
 }  // namespace vk
 }  // namespace gfxstream
diff --git a/host/vulkan/VkAndroidNativeBuffer.h b/host/vulkan/VkAndroidNativeBuffer.h
index fc04487..907ac4c 100644
--- a/host/vulkan/VkAndroidNativeBuffer.h
+++ b/host/vulkan/VkAndroidNativeBuffer.h
@@ -25,6 +25,7 @@
 
 #include "VkCommonOperations.h"
 #include "VkQsriTimeline.h"
+#include "aemu/base/AsyncResult.h"
 #include "aemu/base/BumpPool.h"
 #include "aemu/base/ThreadAnnotations.h"
 #include "aemu/base/synchronization/ConditionVariable.h"
@@ -35,37 +36,64 @@
 namespace gfxstream {
 namespace vk {
 
-struct AndroidNativeBufferInfo;
 struct VulkanDispatch;
 
 // This class provides methods to create and query information about Android
 // native buffers in the context of creating Android swapchain images that have
 // Android native buffer backing.
 
-// This is to be refactored to move to external memory only once we get that
-// working.
+class AndroidNativeBufferInfo {
+   public:
+    static std::unique_ptr<AndroidNativeBufferInfo> create(
+        VkEmulation* emu, VulkanDispatch* vk, VkDevice device, android::base::BumpPool& allocator,
+        const VkImageCreateInfo* pCreateInfo, const VkNativeBufferANDROID* nativeBufferANDROID,
+        const VkAllocationCallbacks* pAllocator, const VkPhysicalDeviceMemoryProperties* memProps);
 
-void teardownAndroidNativeBufferImage(VulkanDispatch* vk, AndroidNativeBufferInfo* anbInfo);
+    AndroidNativeBufferInfo(const AndroidNativeBufferInfo&) = delete;
+    AndroidNativeBufferInfo& operator=(const AndroidNativeBufferInfo&) = delete;
 
-struct AndroidNativeBufferInfo {
-    ~AndroidNativeBufferInfo() {
-        if (vk) {
-            teardownAndroidNativeBufferImage(vk, this);
-        }
-    }
+    AndroidNativeBufferInfo(AndroidNativeBufferInfo&&) = delete;
+    AndroidNativeBufferInfo& operator=(AndroidNativeBufferInfo&&) = delete;
 
-    VulkanDispatch* vk = nullptr;
-    VkDevice device = VK_NULL_HANDLE;
-    VkFormat vkFormat;
-    VkExtent3D extent;
-    VkImageUsageFlags usage;
-    std::vector<uint32_t> queueFamilyIndices;
+    ~AndroidNativeBufferInfo();
 
-    int format;
-    int stride;
-    uint32_t colorBufferHandle;
-    bool externallyBacked = false;
-    bool useVulkanNativeImage = false;
+    VkImage getImage() const { return mImage; }
+
+    bool isExternallyBacked() const { return mExternallyBacked; }
+
+    bool isUsingNativeImage() const { return mUseVulkanNativeImage; }
+
+    uint32_t getColorBufferHandle() const { return mColorBufferHandle; }
+
+    VkResult on_vkAcquireImageANDROID(VkEmulation* emu, VulkanDispatch* vk, VkDevice device, VkQueue defaultQueue,
+                                      uint32_t defaultQueueFamilyIndex,
+                                      std::mutex* defaultQueueMutex, VkSemaphore semaphore,
+                                      VkFence fence);
+
+    VkResult on_vkQueueSignalReleaseImageANDROID(VkEmulation* emu,
+                                                 VulkanDispatch* vk, uint32_t queueFamilyIndex,
+                                                 VkQueue queue, std::mutex* queueMutex,
+                                                 uint32_t waitSemaphoreCount,
+                                                 const VkSemaphore* pWaitSemaphores,
+                                                 int* pNativeFenceFd);
+
+    AsyncResult registerQsriCallback(VkImage image, VkQsriTimeline::Callback callback);
+
+   private:
+    AndroidNativeBufferInfo() = default;
+
+    VulkanDispatch* mDeviceDispatch = nullptr;
+    VkDevice mDevice = VK_NULL_HANDLE;
+    VkFormat mVkFormat;
+    VkExtent3D mExtent;
+    VkImageUsageFlags mUsage;
+    std::vector<uint32_t> mQueueFamilyIndices;
+
+    int mAhbFormat = 0;
+    int mStride = 0;
+    uint32_t mColorBufferHandle = 0;
+    bool mExternallyBacked = false;
+    bool mUseVulkanNativeImage = false;
 
     // We will be using separate allocations for image versus staging memory,
     // because not all host Vulkan drivers will support directly rendering to
@@ -73,19 +101,16 @@
 
     // If we are using external memory, these memories are imported
     // to the current instance.
-    VkDeviceMemory imageMemory = VK_NULL_HANDLE;
-    VkDeviceMemory stagingMemory = VK_NULL_HANDLE;
+    VkDeviceMemory mImageMemory = VK_NULL_HANDLE;
+    uint32_t mImageMemoryTypeIndex = -1;
 
-    VkBuffer stagingBuffer = VK_NULL_HANDLE;
-
-    uint32_t imageMemoryTypeIndex;
-    uint32_t stagingMemoryTypeIndex;
-
-    uint8_t* mappedStagingPtr = nullptr;
+    VkDeviceMemory mStagingBufferMemory = VK_NULL_HANDLE;
+    VkBuffer mStagingBuffer = VK_NULL_HANDLE;
+    uint8_t* mMappedStagingPtr = nullptr;
 
     // To be populated later as we go.
-    VkImage image = VK_NULL_HANDLE;
-    VkMemoryRequirements memReqs;
+    VkImage mImage = VK_NULL_HANDLE;
+    VkMemoryRequirements mImageMemoryRequirements;
 
     // The queue over which we send the buffer/image copy commands depends on
     // the queue over which vkQueueSignalReleaseImageANDROID happens.
@@ -106,7 +131,7 @@
     };
     // We keep one QueueState for each queue family index used by the guest
     // in vkQueuePresentKHR.
-    std::vector<QueueState> queueStates;
+    std::vector<QueueState> mQueueStates;
 
     // Did we ever sync the Vulkan image with a ColorBuffer?
     // If so, set everSynced along with the queue family index
@@ -114,14 +139,14 @@
     // If the swapchain image was created with exclusive sharing
     // mode (reflected in this struct's |sharingMode| field),
     // this part doesn't really matter.
-    bool everSynced = false;
-    uint32_t lastUsedQueueFamilyIndex;
+    bool mEverSynced = false;
+    uint32_t mLastUsedQueueFamilyIndex = -1;
 
     // On first acquire, we might use a different queue family
     // to initially set the semaphore/fence to be signaled.
     // Track that here.
-    bool everAcquired = false;
-    QueueState acquireQueueState;
+    bool mEverAcquired = false;
+    QueueState mAcquireQueueState;
 
     // State that is of interest when interacting with sync fds and SyncThread.
     // Protected by this lock and condition variable.
@@ -144,34 +169,14 @@
         std::unordered_set<VkFence> mUsedFences GUARDED_BY(mMutex);
     };
 
-    std::unique_ptr<QsriWaitFencePool> qsriWaitFencePool = nullptr;
-    std::unique_ptr<VkQsriTimeline> qsriTimeline = nullptr;
+    std::unique_ptr<QsriWaitFencePool> mQsriWaitFencePool;
+    std::unique_ptr<VkQsriTimeline> mQsriTimeline;
 };
 
-VkResult prepareAndroidNativeBufferImage(VkEmulation* emu, VulkanDispatch* vk, VkDevice device,
-                                         android::base::BumpPool& allocator,
-                                         const VkImageCreateInfo* pCreateInfo,
-                                         const VkNativeBufferANDROID* nativeBufferANDROID,
-                                         const VkAllocationCallbacks* pAllocator,
-                                         const VkPhysicalDeviceMemoryProperties* memProps,
-                                         AndroidNativeBufferInfo* out);
-
 void getGralloc0Usage(VkFormat format, VkImageUsageFlags imageUsage, int* usage_out);
 void getGralloc1Usage(VkFormat format, VkImageUsageFlags imageUsage,
                       VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
                       uint64_t* consumerUsage_out, uint64_t* producerUsage_out);
 
-VkResult setAndroidNativeImageSemaphoreSignaled(VkEmulation* emu, VulkanDispatch* vk,
-                                                VkDevice device, VkQueue defaultQueue,
-                                                uint32_t defaultQueueFamilyIndex,
-                                                std::mutex* defaultQueueMutex,
-                                                VkSemaphore semaphore, VkFence fence,
-                                                AndroidNativeBufferInfo* anbInfo);
-
-VkResult syncImageToColorBuffer(VkEmulation* emu, VulkanDispatch* vk, uint32_t queueFamilyIndex,
-                                VkQueue queue, std::mutex* queueMutex, uint32_t waitSemaphoreCount,
-                                const VkSemaphore* pWaitSemaphores, int* pNativeFenceFd,
-                                AndroidNativeBufferInfo* anbInfo);
-
 }  // namespace vk
 }  // namespace gfxstream
diff --git a/host/vulkan/VkDecoder.cpp b/host/vulkan/VkDecoder.cpp
index 9e57253..5a72ca0 100644
--- a/host/vulkan/VkDecoder.cpp
+++ b/host/vulkan/VkDecoder.cpp
@@ -220,7 +220,6 @@
                 .setAnnotations(std::move(executionData))
                 .build();
 
-        auto vk = m_vk;
         switch (opcode) {
 #ifdef VK_VERSION_1_0
             case OP_vkCreateInstance: {
@@ -1035,8 +1034,8 @@
                 }
                 VkResult vkEnumerateInstanceExtensionProperties_VkResult_return = (VkResult)0;
                 vkEnumerateInstanceExtensionProperties_VkResult_return =
-                    vk->vkEnumerateInstanceExtensionProperties(pLayerName, pPropertyCount,
-                                                               pProperties);
+                    m_vk->vkEnumerateInstanceExtensionProperties(pLayerName, pPropertyCount,
+                                                                 pProperties);
                 if ((vkEnumerateInstanceExtensionProperties_VkResult_return) ==
                     VK_ERROR_DEVICE_LOST)
                     m_state->on_DeviceLost();
@@ -1249,7 +1248,7 @@
                 }
                 VkResult vkEnumerateInstanceLayerProperties_VkResult_return = (VkResult)0;
                 vkEnumerateInstanceLayerProperties_VkResult_return =
-                    vk->vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties);
+                    m_vk->vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties);
                 if ((vkEnumerateInstanceLayerProperties_VkResult_return) == VK_ERROR_DEVICE_LOST)
                     m_state->on_DeviceLost();
                 m_state->on_CheckOutOfMemory(vkEnumerateInstanceLayerProperties_VkResult_return,
diff --git a/host/vulkan/VkDecoderGlobalState.cpp b/host/vulkan/VkDecoderGlobalState.cpp
index a50e8e8..18d60ed 100644
--- a/host/vulkan/VkDecoderGlobalState.cpp
+++ b/host/vulkan/VkDecoderGlobalState.cpp
@@ -2479,12 +2479,14 @@
             const VkPhysicalDeviceMemoryProperties& memoryProperties =
                 physicalDeviceInfo->memoryPropertiesHelper->getHostMemoryProperties();
 
-            anbInfo = std::make_unique<AndroidNativeBufferInfo>();
-            createRes = prepareAndroidNativeBufferImage(
-                m_vkEmulation, vk, device, *pool, pCreateInfo, nativeBufferANDROID, pAllocator,
-                &memoryProperties, anbInfo.get());
+            anbInfo = AndroidNativeBufferInfo::create(
+                m_vkEmulation, vk, device, *pool, pCreateInfo, nativeBufferANDROID, pAllocator, &memoryProperties);
+            if (anbInfo == nullptr) {
+                createRes = VK_ERROR_OUT_OF_DEVICE_MEMORY;
+            }
+
             if (createRes == VK_SUCCESS) {
-                *pImage = anbInfo->image;
+                *pImage = anbInfo->getImage();
             }
         } else {
             createRes = vk->vkCreateImage(device, pCreateInfo, pAllocator, pImage);
@@ -2509,7 +2511,7 @@
         imageInfo.cmpInfo = std::move(cmpInfo);
         imageInfo.imageCreateInfoShallow = vk_make_orphan_copy(*pCreateInfo);
         imageInfo.layout = pCreateInfo->initialLayout;
-        if (nativeBufferANDROID) imageInfo.anbInfo = std::move(anbInfo);
+        imageInfo.anbInfo = std::move(anbInfo);
 
         if (boxImage) {
             *pImage = new_boxed_non_dispatchable_VkImage(*pImage);
@@ -2781,7 +2783,7 @@
             createInfo.subresourceRange.baseMipLevel = 0;
             pCreateInfo = &createInfo;
         }
-        if (imageInfo->anbInfo && imageInfo->anbInfo->externallyBacked) {
+        if (imageInfo->anbInfo && imageInfo->anbInfo->isExternallyBacked()) {
             createInfo = *pCreateInfo;
             pCreateInfo = &createInfo;
         }
@@ -5811,9 +5813,9 @@
 
         AndroidNativeBufferInfo* anbInfo = imageInfo->anbInfo.get();
 
-        VkResult result = setAndroidNativeImageSemaphoreSignaled(
-            m_vkEmulation, vk, device, defaultQueue, defaultQueueFamilyIndex, defaultQueueMutex,
-            semaphore, usedFence, anbInfo);
+        VkResult result =
+            anbInfo->on_vkAcquireImageANDROID(m_vkEmulation, vk, device, defaultQueue, defaultQueueFamilyIndex,
+                                              defaultQueueMutex, semaphore, usedFence);
         if (result != VK_SUCCESS) {
             return result;
         }
@@ -5861,20 +5863,20 @@
         if (!imageInfo) return VK_ERROR_INITIALIZATION_FAILED;
 
         auto* anbInfo = imageInfo->anbInfo.get();
-        if (anbInfo->useVulkanNativeImage) {
+        if (anbInfo->isUsingNativeImage()) {
             // vkQueueSignalReleaseImageANDROID() is only called by the Android framework's
             // implementation of vkQueuePresentKHR(). The guest application is responsible for
             // transitioning the image layout of the image passed to vkQueuePresentKHR() to
             // VK_IMAGE_LAYOUT_PRESENT_SRC_KHR before the call. If the host is using native
             // Vulkan images where `image` is backed with the same memory as its ColorBuffer,
             // then we need to update the tracked layout for that ColorBuffer.
-            m_vkEmulation->setColorBufferCurrentLayout(anbInfo->colorBufferHandle,
-                                                       VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+            m_vkEmulation->setColorBufferCurrentLayout(anbInfo->getColorBufferHandle(),
+                                        VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
         }
 
-        return syncImageToColorBuffer(m_vkEmulation, vk, queueInfo->queueFamilyIndex, queue,
-                                      queueInfo->queueMutex.get(), waitSemaphoreCount,
-                                      pWaitSemaphores, pNativeFenceFd, anbInfo);
+        return anbInfo->on_vkQueueSignalReleaseImageANDROID(
+            m_vkEmulation, vk, queueInfo->queueFamilyIndex, queue, queueInfo->queueMutex.get(),
+            waitSemaphoreCount, pWaitSemaphores, pNativeFenceFd);
     }
 
     VkResult on_vkMapMemoryIntoAddressSpaceGOOGLE(android::base::BumpPool* pool,
@@ -7738,20 +7740,7 @@
             ERR("Attempted to register QSRI callback on VkImage:%p without ANB info.", image);
             return AsyncResult::FAIL_AND_CALLBACK_NOT_SCHEDULED;
         }
-        if (!anbInfo->vk) {
-            ERR("Attempted to register QSRI callback on VkImage:%p with uninitialized ANB info.",
-                image);
-            return AsyncResult::FAIL_AND_CALLBACK_NOT_SCHEDULED;
-        }
-        // Could be null or mismatched image, check later
-        if (image != anbInfo->image) {
-            ERR("Attempted on register QSRI callback on VkImage:%p with wrong image %p.", image,
-                anbInfo->image);
-            return AsyncResult::FAIL_AND_CALLBACK_NOT_SCHEDULED;
-        }
-
-        anbInfo->qsriTimeline->registerCallbackForNextPresentAndPoll(std::move(callback));
-        return AsyncResult::OK_AND_CALLBACK_SCHEDULED;
+        return anbInfo->registerQsriCallback(image, std::move(callback));
     }
 
 #define GUEST_EXTERNAL_MEMORY_HANDLE_TYPES                                \
diff --git a/host/vulkan/VkSubDecoder.cpp b/host/vulkan/VkSubDecoder.cpp
index ca8d17b..bc3e050 100644
--- a/host/vulkan/VkSubDecoder.cpp
+++ b/host/vulkan/VkSubDecoder.cpp
@@ -33,14 +33,14 @@
 #define MAX_STACK_ITEMS 16
 #define MAX_PACKET_LENGTH (400 * 1024 * 1024)  // 400MB
 size_t subDecode(VulkanMemReadingStream* readStream, VulkanDispatch* vk, void* boxed_dispatchHandle,
-                 void* dispatchHandle, VkDeviceSize dataSize, const void* pData,
+                 void* dispatchHandle, VkDeviceSize subDecodeDataSize, const void* pSubDecodeData,
                  const VkDecoderContext& context) {
     auto& metricsLogger = *context.metricsLogger;
     uint32_t count = 0;
-    unsigned char* buf = (unsigned char*)pData;
+    unsigned char* buf = (unsigned char*)pSubDecodeData;
     android::base::BumpPool* pool = readStream->pool();
-    unsigned char* ptr = (unsigned char*)pData;
-    const unsigned char* const end = (const unsigned char*)buf + dataSize;
+    unsigned char* ptr = (unsigned char*)pSubDecodeData;
+    const unsigned char* const end = (const unsigned char*)buf + subDecodeDataSize;
     VkDecoderGlobalState* globalstate = VkDecoderGlobalState::get();
     while (end - ptr >= 8) {
         uint32_t opcode = *(uint32_t*)ptr;