Build the opengl host support code

Bug: 171711491
Change-Id: Ie29cff78c68ee76ecb242679ba1a7bf63d0ea318
diff --git a/base/ArraySize.h b/base/ArraySize.h
index 6f04107..9650e67 100644
--- a/base/ArraySize.h
+++ b/base/ArraySize.h
@@ -27,6 +27,7 @@
 #else
 
 #include <array>
+#include <stddef.h>
 
 namespace android {
 namespace base {
diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt
index 7996b22..76ca1a2 100644
--- a/base/CMakeLists.txt
+++ b/base/CMakeLists.txt
@@ -6,6 +6,7 @@
     CompressingStream.cpp
     CpuTime.cpp
     DecompressingStream.cpp
+    FileUtils.cpp
     FunctorThread.cpp
     GLObjectCounter.cpp
     LayoutResolver.cpp
diff --git a/base/FileUtils.cpp b/base/FileUtils.cpp
new file mode 100644
index 0000000..d30d95b
--- /dev/null
+++ b/base/FileUtils.cpp
@@ -0,0 +1,98 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "base/FileUtils.h"
+#include "base/EintrWrapper.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef _MSC_VER
+#include "msvc-posix.h"
+#else
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <io.h>
+#endif
+
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace android {
+
+bool readFileIntoString(int fd, std::string* file_contents) {
+#ifdef _MSC_VER
+    if (fd < 0) return false; // msvc does not handle fd -1 very well.
+#endif
+
+    off_t size = lseek(fd, 0, SEEK_END);
+    if (size == (off_t)-1) {
+        return false;
+    }
+    off_t err = lseek(fd, 0, SEEK_SET);
+    if (err == (off_t)-1) {
+        return false;
+    }
+
+    std::string buf((size_t)size, '\0');
+    ssize_t result = HANDLE_EINTR(read(fd, &buf[0], size));
+    if (result != size) {
+        return false;
+    }
+    *file_contents = std::move(buf);
+    return true;
+}
+
+bool writeStringToFile(int fd, const std::string& file_contents) {
+#ifdef _MSC_VER
+    // msvc does not handle fd -1 very well.
+    if (fd < 0)  return false;
+
+    ssize_t result = HANDLE_EINTR(
+            _write(fd, file_contents.c_str(), file_contents.size()));
+#else
+    ssize_t result = HANDLE_EINTR(
+            write(fd, file_contents.c_str(), file_contents.size()));
+#endif
+    if (result != (ssize_t)file_contents.size()) {
+        return false;
+    }
+    return true;
+}
+
+base::Optional<std::string> readFileIntoString(const std::string& name) {
+    std::ifstream is(name, std::ios_base::binary);
+    if (!is) {
+        return {};
+    }
+
+    std::ostringstream ss;
+    ss << is.rdbuf();
+    return ss.str();
+}
+
+bool setFileSize(int fd, int64_t size) {
+#ifdef _WIN32
+#ifdef _MSC_VER
+    if (fd < 0) return false; // msvc does not handle fd -1 very well.
+#endif
+    return _chsize_s(fd, size) == 0;
+#else
+    return ftruncate(fd, size) == 0;
+#endif
+}
+
+}  // namespace android
diff --git a/base/FileUtils.h b/base/FileUtils.h
new file mode 100644
index 0000000..91dfc7c
--- /dev/null
+++ b/base/FileUtils.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#pragma once
+
+#include "base/Optional.h"
+
+#include <string>
+
+namespace android {
+
+// Reads from |fd| into |file_contents|
+// Returns false if something went wrong
+bool readFileIntoString(int fd, std::string* file_contents);
+
+// Reads |name| file
+base::Optional<std::string> readFileIntoString(const std::string& filename);
+
+// Writes |file_contents| to |fd|
+// Returns false if something went wrong
+bool writeStringToFile(int fd, const std::string& file_contents);
+
+// Sets the file size to |size|, could either extend or truncate it.
+bool setFileSize(int fd, int64_t size);
+
+}  // namespace android
diff --git a/base/FileUtils_unittest.cpp b/base/FileUtils_unittest.cpp
new file mode 100644
index 0000000..d975f6e
--- /dev/null
+++ b/base/FileUtils_unittest.cpp
@@ -0,0 +1,89 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/base/misc/FileUtils.h"
+
+#include "android/base/files/ScopedFd.h"
+#include "android/utils/eintr_wrapper.h"
+#include "android/utils/file_io.h"
+#include "android/utils/tempfile.h"
+
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <limits>
+#include <string>
+
+using android::base::ScopedFd;
+
+namespace android {
+
+TEST(FileUtils, stringToFile) {
+    const char test_pattern[] = "test pattern";
+    TempFile* tf = tempfile_create();
+
+    ScopedFd fd(HANDLE_EINTR(open(tempfile_path(tf), O_RDWR, 0600)));
+    EXPECT_NE(-1, fd.get());
+
+    EXPECT_FALSE(writeStringToFile(-1, test_pattern));
+    EXPECT_TRUE(writeStringToFile(fd.get(), test_pattern));
+
+    std::string dummy_buffer("dummy");
+    EXPECT_FALSE(readFileIntoString(-1, &dummy_buffer));
+    EXPECT_STREQ("dummy", dummy_buffer.c_str());
+
+    std::string read_buffer;
+    EXPECT_TRUE(readFileIntoString(fd.get(), &read_buffer));
+    EXPECT_STREQ(test_pattern, read_buffer.c_str());
+
+    fd.close();
+
+    auto readFailedRes = readFileIntoString("!@#%R#$%W$*@#$*");
+    EXPECT_FALSE(readFailedRes);
+
+    auto readSucceededRes = readFileIntoString(tempfile_path(tf));
+    EXPECT_TRUE(readSucceededRes);
+    EXPECT_STREQ(test_pattern, readSucceededRes->c_str());
+
+    tempfile_close(tf);
+}
+
+// Tests readFileIntoString
+TEST(FileUtils, fileToString) {
+    const int bytesToTest = 100;
+
+    std::vector<uint8_t> testPattern;
+
+    for (int i = 0; i < bytesToTest; i++) {
+        testPattern.push_back(i % 3 == 0 ? 0x0 : 0x1a);
+    }
+
+    TempFile* tf = tempfile_create();
+
+    ScopedFd fd(HANDLE_EINTR(open(tempfile_path(tf), O_RDWR, 0600)));
+    EXPECT_NE(-1, fd.get());
+
+    HANDLE_EINTR(write(fd.get(), testPattern.data(), bytesToTest));
+
+    fd.close();
+
+    const auto testOutput = readFileIntoString(tempfile_path(tf));
+
+    EXPECT_TRUE(testOutput);
+    EXPECT_EQ(bytesToTest, testOutput->size());
+
+    for (int i = 0; i < bytesToTest; i++) {
+        EXPECT_EQ((char)testPattern[i], (char)testOutput->at(i));
+    }
+}
+
+}  // namespace android
diff --git a/base/ScopedFd.h b/base/ScopedFd.h
new file mode 100644
index 0000000..ee6035e
--- /dev/null
+++ b/base/ScopedFd.h
@@ -0,0 +1,87 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#pragma once
+
+#include "base/Compiler.h"
+
+#include <errno.h>
+#ifdef _MSC_VER
+#include "msvc-posix.h"
+#else
+#include <unistd.h>
+#endif
+
+namespace android {
+namespace base {
+
+// Helper class to hold an integer file descriptor, and have the 'close'
+// function called automatically on scope exit, unless the 'release'
+// method was called previously.
+class ScopedFd {
+public:
+    // Default constructor will hold an invalid descriptor.
+    ScopedFd() : fd_(-1) {}
+
+    // Constructor takes ownership of |fd|.
+    explicit ScopedFd(int fd) : fd_(fd) {}
+
+    // Make it movable.
+    ScopedFd(ScopedFd&& other) : fd_(other.fd_) {
+        other.fd_ = -1;
+    }
+
+    ScopedFd& operator=(ScopedFd&& other) {
+        swap(&other);
+        return *this;
+    }
+
+    // Destructor calls close().
+    ~ScopedFd() { close(); }
+
+    // Return the file descriptor value, does _not_ transfer ownership.
+    int get() const { return fd_; }
+
+    // Return the file descriptor value, transfers ownership to the caller.
+    int release() {
+        int fd = fd_;
+        fd_ = -1;
+        return fd;
+    }
+
+    // Return true iff the file descriptor is valid.
+    bool valid() const { return fd_ >= 0; }
+
+    // Close the file descriptor (and make the wrapped value invalid).
+    void close() {
+        if (fd_ != -1) {
+            int save_errno = errno;
+            ::close(fd_);
+            fd_ = -1;
+            errno = save_errno;
+        }
+    }
+
+    // Swap two ScopedFd instances.
+    void swap(ScopedFd* other) {
+        int fd = fd_;
+        fd_ = other->fd_;
+        other->fd_ = fd;
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(ScopedFd);
+
+    int fd_;
+};
+
+}  // namespace base
+}  // namespace android
diff --git a/base/ScopedFd_unittest.cpp b/base/ScopedFd_unittest.cpp
new file mode 100644
index 0000000..10c38c3
--- /dev/null
+++ b/base/ScopedFd_unittest.cpp
@@ -0,0 +1,80 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/base/files/ScopedFd.h"
+
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace base {
+
+namespace {
+
+// The path of a file that can always be opened for reading on any platform.
+#ifdef _WIN32
+static const char kNullFile[] = "NUL";
+#else
+static const char kNullFile[] = "/dev/null";
+#endif
+
+int OpenNull() {
+    return ::open(kNullFile, O_RDONLY);
+}
+
+}  // namespace
+
+TEST(ScopedFd, DefaultConstructor) {
+    ScopedFd f;
+    EXPECT_FALSE(f.valid());
+    EXPECT_EQ(-1, f.get());
+}
+
+TEST(ScopedFd, Constructor) {
+    ScopedFd f(OpenNull());
+    EXPECT_TRUE(f.valid());
+}
+
+TEST(ScopedFd, Release) {
+    ScopedFd f(OpenNull());
+    EXPECT_TRUE(f.valid());
+    int fd = f.release();
+    EXPECT_FALSE(f.valid());
+    EXPECT_NE(-1, fd);
+    ::close(fd);
+}
+
+TEST(ScopedFd, Close) {
+    ScopedFd f(OpenNull());
+    EXPECT_TRUE(f.valid());
+    f.close();
+    EXPECT_FALSE(f.valid());
+}
+
+TEST(ScopedFd, Swap) {
+    ScopedFd f1;
+    ScopedFd f2(OpenNull());
+    EXPECT_FALSE(f1.valid());
+    EXPECT_TRUE(f2.valid());
+    int fd = f2.get();
+    f1.swap(&f2);
+    EXPECT_FALSE(f2.valid());
+    EXPECT_TRUE(f1.valid());
+    EXPECT_EQ(fd, f1.get());
+}
+
+
+}  // namespace base
+}  // namespace android
diff --git a/host-common/CMakeLists.txt b/host-common/CMakeLists.txt
index ef6d093..dbb7f0b 100644
--- a/host-common/CMakeLists.txt
+++ b/host-common/CMakeLists.txt
@@ -1,6 +1,20 @@
+if (APPLE)
+    set(gfxstream-host-common-opengles-platform-sources
+        opengl/macTouchOpengl.m
+        opengl/NativeGpuInfo_darwin.cpp)
+elseif (WIN32)
+    set(gfxstream-host-common-opengles-platform-sources
+        opengl/NativeGpuInfo_windows.cpp)
+else()
+    set(gfxstream-host-common-opengles-platform-sources
+        opengl/NativeGpuInfo_linux.cpp)
+endif()
+
 add_library(
     gfxstream-host-common
     STATIC
+
+    # emugl glue
     address_space_device_control_ops.cpp
     crash_reporter.cpp
     vm_operations.cpp
@@ -8,9 +22,35 @@
     dma_device.cpp
     sync_device.cpp
     misc.cpp
-    window_operations.cpp)
+    window_operations.cpp
+
+
+    # What used to be android-emu
+    HostmemIdMapping.cpp
+
+    # android-emu avd globals
+    avd/info.cpp
+
+    # general opengles host stuff, incl process pipe
+    # and opengl es pipe
+    opengles.cpp
+    opengl/EmuglBackendList.cpp
+    # opengl/EmuglBackendList_unittest.cpp
+    opengl/emugl_config.cpp
+    # opengl/emugl_config_unittest.cpp
+    opengl/GLProcessPipe.cpp
+    opengl/GpuFrameBridge.cpp
+    # opengl/GpuFrameBridge_unittest.cpp
+    opengl/gpuinfo.cpp
+    # opengl/gpuinfo_unittest.cpp
+    opengl/logger.cpp
+    opengl/OpenglEsPipe.cpp
+    ${gfxstream-host-common-opengles-platform-sources}
+
+    )
 target_include_directories(
     gfxstream-host-common
     PRIVATE
     ${GFXSTREAM_REPO_ROOT}
+    ${GFXSTREAM_REPO_ROOT}/include
     ${GFXSTREAM_REPO_ROOT}/stream-servers)
diff --git a/host-common/HostmemIdMapping.cpp b/host-common/HostmemIdMapping.cpp
index c859ea4..56d9835 100644
--- a/host-common/HostmemIdMapping.cpp
+++ b/host-common/HostmemIdMapping.cpp
@@ -26,7 +26,7 @@
 
 // static
 HostmemIdMapping* HostmemIdMapping::get() {
-    return sMapping.ptr();
+    return sMapping();
 }
 
 // TODO: Add registerHostmemFixed version that takes a predetermined id,
diff --git a/host-common/avd/info.c b/host-common/avd/info.c
deleted file mode 100644
index 4fba5b8..0000000
--- a/host-common/avd/info.c
+++ /dev/null
@@ -1,2069 +0,0 @@
-/* Copyright (C) 2008 The Android Open Source Project
-**
-** This software is licensed under the terms of the GNU General Public
-** License version 2, as published by the Free Software Foundation, and
-** may be copied, distributed, and modified under those terms.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-** GNU General Public License for more details.
-*/
-#include "android/avd/info.h"
-
-#include "android/android.h"
-#include "android/avd/util.h"
-#include "android/avd/keys.h"
-#include "android/base/ArraySize.h"
-#include "android/base/export.h"
-#include "android/cmdline-option.h"
-#include "android/emulation/bufprint_config_dirs.h"
-#include "android/featurecontrol/feature_control.h"
-#include "android/utils/bufprint.h"
-#include "android/utils/debug.h"
-#include "android/utils/dirscanner.h"
-#include "android/utils/file_data.h"
-#include "android/utils/filelock.h"
-#include "android/utils/path.h"
-#include "android/utils/property_file.h"
-#include "android/utils/string.h"
-#include "android/utils/tempfile.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-/* global variables - see android/globals.h */
-AvdInfoParams   android_avdParams[1];
-AvdInfo*        android_avdInfo;
-
-AEMU_EXPORT AvdInfo** aemu_get_android_avdInfoPtr() {
-    return &android_avdInfo;
-}
-
-/* set to 1 for debugging */
-#define DEBUG 0
-
-#if DEBUG >= 1
-#include <stdio.h>
-#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
-#define DD(...) VERBOSE_PRINT(avd_config,__VA_ARGS__)
-#else
-#define D(...) (void)0
-#define DD(...) (void)0
-#endif
-
-/* technical note on how all of this is supposed to work:
- *
- * Each AVD corresponds to a "content directory" that is used to
- * store persistent disk images and configuration files. Most remarkable
- * are:
- *
- * - a "config.ini" file used to hold configuration information for the
- *   AVD
- *
- * - mandatory user data image ("userdata-qemu.img") and cache image
- *   ("cache.img")
- *
- * - optional mutable system image ("system-qemu.img"), kernel image
- *   ("kernel-qemu") and read-only ramdisk ("ramdisk.img")
- *
- * When starting up an AVD, the emulator looks for relevant disk images
- * in the content directory. If it doesn't find a given image there, it
- * will try to search in the list of system directories listed in the
- * 'config.ini' file through one of the following (key,value) pairs:
- *
- *    images.sysdir.1 = <first search path>
- *    images.sysdir.2 = <second search path>
- *
- * The search paths can be absolute, or relative to the root SDK installation
- * path (which is determined from the emulator program's location, or from the
- * ANDROID_SDK_ROOT environment variable).
- *
- * Individual image disk search patch can be over-riden on the command-line
- * with one of the usual options.
- */
-
-/* certain disk image files are mounted read/write by the emulator
- * to ensure that several emulators referencing the same files
- * do not corrupt these files, we need to lock them and respond
- * to collision depending on the image type.
- *
- * the enumeration below is used to record information about
- * each image file path.
- *
- * READONLY means that the file will be mounted read-only
- * and this doesn't need to be locked. must be first in list
- *
- * MUSTLOCK means that the file should be locked before
- * being mounted by the emulator
- *
- * TEMPORARY means that the file has been copied to a
- * temporary image, which can be mounted read/write
- * but doesn't require locking.
- */
-typedef enum {
-    IMAGE_STATE_READONLY,     /* unlocked */
-    IMAGE_STATE_MUSTLOCK,     /* must be locked */
-    IMAGE_STATE_LOCKED,       /* locked */
-    IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
-    IMAGE_STATE_TEMPORARY,    /* copied to temp file (no lock needed) */
-} AvdImageState;
-
-struct AvdInfo {
-    /* for the Android build system case */
-    char      inAndroidBuild;
-    char*     androidOut;
-    char*     androidBuildRoot;
-    char*     targetArch;
-    char*     targetAbi;
-    char*     acpiIniPath;
-
-    /* for the normal virtual device case */
-    char*     deviceName;
-    char*     deviceId;
-    char*     sdkRootPath;
-    char*     searchPaths[ MAX_SEARCH_PATHS ];
-    int       numSearchPaths;
-    char*     contentPath;
-    char*     rootIniPath;
-    CIniFile* rootIni;   /* root <foo>.ini file, empty if missing */
-    CIniFile* configIni; /* virtual device's config.ini, NULL if missing */
-    CIniFile* skinHardwareIni; /* skin-specific hardware.ini */
-
-    /* for both */
-    int       apiLevel;
-    int       incrementalVersion;
-
-    /* For preview releases where we don't know the exact API level this flag
-     * indicates that at least we know it's M+ (for some code that needs to
-     * select either legacy or modern operation mode.
-     */
-    bool      isMarshmallowOrHigher;
-    bool      isGoogleApis;
-    bool      isUserBuild;
-    AvdFlavor flavor;
-    char*     skinName;     /* skin name */
-    char*     skinDirPath;  /* skin directory */
-    char*     coreHardwareIniPath;  /* core hardware.ini path */
-    char*     snapshotLockPath;  /* core snapshot.lock path */
-    char*     multiInstanceLockPath;
-
-    FileData  buildProperties[1];  /* build.prop file */
-    FileData  bootProperties[1];   /* boot.prop file */
-
-    /* image files */
-    char*     imagePath [ AVD_IMAGE_MAX ];
-    char      imageState[ AVD_IMAGE_MAX ];
-
-    /* skip checks */
-    bool noChecks;
-};
-
-
-void
-avdInfo_free( AvdInfo*  i )
-{
-    if (i) {
-        int  nn;
-
-        for (nn = 0; nn < AVD_IMAGE_MAX; nn++)
-            AFREE(i->imagePath[nn]);
-
-        AFREE(i->skinName);
-        AFREE(i->skinDirPath);
-        AFREE(i->coreHardwareIniPath);
-        AFREE(i->snapshotLockPath);
-
-        fileData_done(i->buildProperties);
-        fileData_done(i->bootProperties);
-
-        for (nn = 0; nn < i->numSearchPaths; nn++)
-            AFREE(i->searchPaths[nn]);
-
-        i->numSearchPaths = 0;
-
-        if (i->configIni) {
-            iniFile_free(i->configIni);
-            i->configIni = NULL;
-        }
-
-        if (i->skinHardwareIni) {
-            iniFile_free(i->skinHardwareIni);
-            i->skinHardwareIni = NULL;
-        }
-
-        if (i->rootIni) {
-            iniFile_free(i->rootIni);
-            i->rootIni = NULL;
-        }
-
-        AFREE(i->contentPath);
-        AFREE(i->sdkRootPath);
-        AFREE(i->rootIniPath);
-        AFREE(i->targetArch);
-        AFREE(i->targetAbi);
-
-        if (i->inAndroidBuild) {
-            AFREE(i->androidOut);
-            AFREE(i->androidBuildRoot);
-            AFREE(i->acpiIniPath);
-        }
-
-        AFREE(i->deviceName);
-        AFREE(i->deviceId);
-        AFREE(i);
-    }
-}
-
-/* list of default file names for each supported image file type */
-static const char*  const  _imageFileNames[ AVD_IMAGE_MAX ] = {
-#define  _AVD_IMG(x,y,z)  y,
-    AVD_IMAGE_LIST
-#undef _AVD_IMG
-};
-
-/***************************************************************
- ***************************************************************
- *****
- *****    UTILITY FUNCTIONS
- *****
- *****  The following functions do not depend on the AvdInfo
- *****  structure and could easily be moved elsewhere.
- *****
- *****/
-
-/* Parse a given config.ini file and extract the list of SDK search paths
- * from it. Returns the number of valid paths stored in 'searchPaths', or -1
- * in case of problem.
- *
- * Relative search paths in the config.ini will be stored as full pathnames
- * relative to 'sdkRootPath'.
- *
- * 'searchPaths' must be an array of char* pointers of at most 'maxSearchPaths'
- * entries.
- */
-static int _getSearchPaths(CIniFile* configIni,
-                           const char* sdkRootPath,
-                           int maxSearchPaths,
-                           char** searchPaths) {
-    char  temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
-    int   nn, count = 0;
-
-    for (nn = 0; nn < maxSearchPaths; nn++) {
-        char*  path;
-
-        p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
-        if (p >= end)
-            continue;
-
-        path = iniFile_getString(configIni, temp, NULL);
-        if (path != NULL) {
-            DD("    found image search path: %s", path);
-            if (!path_is_absolute(path)) {
-                p = bufprint(temp, end, "%s"PATH_SEP"%s", sdkRootPath, path);
-                AFREE(path);
-                path = ASTRDUP(temp);
-            }
-            searchPaths[count++] = path;
-        }
-    }
-    return count;
-}
-
-/* Check that an AVD name is valid. Returns 1 on success, 0 otherwise.
- */
-static int
-_checkAvdName( const char*  name )
-{
-    int  len  = strlen(name);
-    int  len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                             "abcdefghijklmnopqrstuvwxyz"
-                             "0123456789_.-");
-    return (len == len2);
-}
-
-/* Returns the full path of a given file.
- *
- * If 'fileName' is an absolute path, this returns a simple copy.
- * Otherwise, this returns a new string corresponding to <rootPath>/<fileName>
- *
- * This returns NULL if the paths are too long.
- */
-static char*
-_getFullFilePath( const char* rootPath, const char* fileName )
-{
-    if (path_is_absolute(fileName)) {
-        return ASTRDUP(fileName);
-    } else {
-        char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
-        p = bufprint(temp, end, "%s"PATH_SEP"%s", rootPath, fileName);
-        if (p >= end) {
-            return NULL;
-        }
-        return ASTRDUP(temp);
-    }
-}
-
-/* check that a given directory contains a valid skin.
- * returns 1 on success, 0 on failure.
- */
-static int
-_checkSkinPath( const char*  skinPath )
-{
-    char  temp[MAX_PATH], *p=temp, *end=p+sizeof(temp);
-
-    /* for now, if it has a 'layout' file, it is a valid skin path */
-    p = bufprint(temp, end, "%s"PATH_SEP"layout", skinPath);
-    if (p >= end || !path_exists(temp))
-        return 0;
-
-    return 1;
-}
-
-/* Check that there is a skin named 'skinName' listed from 'skinDirRoot'
- * this returns the full path of the skin directory (after alias expansions),
- * including the skin name, or NULL on failure.
- */
-static char*
-_checkSkinSkinsDir( const char*  skinDirRoot,
-                    const char*  skinName )
-{
-    DirScanner*  scanner;
-    char*        result;
-    char         temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
-
-    p = bufprint(temp, end, "%s"PATH_SEP"skins"PATH_SEP"%s", skinDirRoot, skinName);
-    DD("Probing skin directory: %s", temp);
-    if (p >= end || !path_exists(temp)) {
-        DD("    ignore bad skin directory %s", temp);
-        return NULL;
-    }
-
-    /* first, is this a normal skin directory ? */
-    if (_checkSkinPath(temp)) {
-        /* yes */
-        DD("    found skin directory: %s", temp);
-        return ASTRDUP(temp);
-    }
-
-    /* second, is it an alias to another skin ? */
-    *p      = 0;
-    result  = NULL;
-    scanner = dirScanner_new(temp);
-    if (scanner != NULL) {
-        for (;;) {
-            const char*  file = dirScanner_next(scanner);
-
-            if (file == NULL)
-                break;
-
-            if (strncmp(file, "alias-", 6) || file[6] == 0)
-                continue;
-
-            p = bufprint(temp, end, "%s"PATH_SEP"skins"PATH_SEP"%s", skinDirRoot, file+6);
-            if (p < end && _checkSkinPath(temp)) {
-                /* yes, it's an alias */
-                DD("    skin alias '%s' points to skin directory: %s",
-                   file+6, temp);
-                result = ASTRDUP(temp);
-                break;
-            }
-        }
-        dirScanner_free(scanner);
-    }
-    return result;
-}
-
-/* try to see if the skin name leads to a magic skin or skin path directly
- * returns 1 on success, 0 on error.
- *
- * on success, this sets up '*pSkinName' and '*pSkinDir'
- */
-static int
-_getSkinPathFromName( const char*  skinName,
-                      const char*  sdkRootPath,
-                      char**       pSkinName,
-                      char**       pSkinDir )
-{
-    char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
-    /* if the skin name has the format 'NNNNxNNN' where
-    * NNN is a decimal value, then this is a 'magic' skin
-    * name that doesn't require a skin directory
-    */
-    if (isdigit(skinName[0])) {
-        int  width, height;
-        if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
-            D("'magic' skin format detected: %s", skinName);
-            *pSkinName = ASTRDUP(skinName);
-            *pSkinDir  = NULL;
-            return 1;
-        }
-    }
-
-    /* is the skin name a direct path to the skin directory ? */
-    if (path_is_absolute(skinName) && _checkSkinPath(skinName)) {
-        goto FOUND_IT;
-    }
-
-    /* is the skin name a relative path from the SDK root ? */
-    p = bufprint(temp, end, "%s"PATH_SEP"%s", sdkRootPath, skinName);
-    if (p < end && _checkSkinPath(temp)) {
-        skinName = temp;
-        goto FOUND_IT;
-    }
-
-    /* nope */
-    return 0;
-
-FOUND_IT:
-    if (path_split(skinName, pSkinDir, pSkinName) < 0) {
-        derror("malformed skin name: %s", skinName);
-        return 0;
-    }
-    D("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
-    return 1;
-}
-
-/***************************************************************
- ***************************************************************
- *****
- *****    NORMAL VIRTUAL DEVICE SUPPORT
- *****
- *****/
-
-/* compute path to the root SDK directory
- * assume we are in $SDKROOT/tools/emulator[.exe]
- */
-static int
-_avdInfo_getSdkRoot( AvdInfo*  i )
-{
-
-    i->sdkRootPath = path_getSdkRoot();
-    if (i->sdkRootPath == NULL) {
-        derror("can't find SDK installation directory");
-        return -1;
-    }
-    return 0;
-}
-
-/* parse the root config .ini file. it is located in
- * ~/.android/avd/<name>.ini or Windows equivalent
- */
-static int
-_avdInfo_getRootIni( AvdInfo*  i )
-{
-    i->rootIniPath = path_getRootIniPath( i->deviceName );
-
-    if (i->rootIniPath == NULL) {
-        derror("unknown virtual device name: '%s'", i->deviceName);
-        return -1;
-    }
-
-    D("Android virtual device file at: %s", i->rootIniPath);
-
-    i->rootIni = iniFile_newFromFile(i->rootIniPath);
-
-    if (i->rootIni == NULL) {
-        derror("Corrupt virtual device config file!");
-        return -1;
-    }
-    return 0;
-}
-
-/* Returns the AVD's content path, i.e. the directory that contains
- * the AVD's content files (e.g. data partition, cache, sd card, etc...).
- *
- * We extract this by parsing the root config .ini file, looking for
- * a "path" elements.
- */
-static int
-_avdInfo_getContentPath( AvdInfo*  i )
-{
-    if (i->inAndroidBuild && i->androidOut && i->contentPath) {
-        return 0;
-    }
-
-    char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
-    i->contentPath = iniFile_getString(i->rootIni, ROOT_ABS_PATH_KEY, NULL);
-
-    if (i->contentPath == NULL) {
-        derror("bad config: %s",
-               "virtual device file lacks a "ROOT_ABS_PATH_KEY" entry");
-        return -1;
-    }
-
-    if (!path_is_dir(i->contentPath)) {
-        // If the absolute path doesn't match an actual directory, try
-        // the relative path if present.
-        const char* relPath = iniFile_getString(i->rootIni, ROOT_REL_PATH_KEY, NULL);
-        if (relPath != NULL) {
-            p = bufprint_config_path(temp, end);
-            p = bufprint(p, end, PATH_SEP "%s", relPath);
-            if (p < end && path_is_dir(temp)) {
-                str_reset(&i->contentPath, temp);
-            }
-        }
-    }
-
-    D("virtual device content at %s", i->contentPath);
-    return 0;
-}
-
-static int
-_avdInfo_getApiLevel(AvdInfo* i, bool* isMarshmallowOrHigher)
-{
-    char*       target;
-    const char* p;
-    const int   defaultLevel = kUnknownApiLevel;
-    int         level        = defaultLevel;
-
-#    define ROOT_TARGET_KEY   "target"
-
-    target = iniFile_getString(i->rootIni, ROOT_TARGET_KEY, NULL);
-    if (target == NULL) {
-        D("No target field in root AVD .ini file?");
-        D("Defaulting to API level %d", level);
-        return level;
-    }
-
-    DD("Found target field in root AVD .ini file: '%s'", target);
-
-    /* There are two acceptable formats for the target key.
-     *
-     * 1/  android-<level>
-     * 2/  <vendor-name>:<add-on-name>:<level>
-     *
-     * Where <level> can be either a _name_ (for experimental/preview SDK builds)
-     * or a decimal number. Note that if a _name_, it can start with a digit.
-     */
-
-    /* First, extract the level */
-    if (!memcmp(target, "android-", 8))
-        p = target + 8;
-    else {
-        /* skip two columns */
-        p = strchr(target, ':');
-        if (p != NULL) {
-            p = strchr(p+1, ':');
-            if (p != NULL)
-                p += 1;
-        }
-    }
-    if (p == NULL || !isdigit(*p)) {
-        // preview versions usually have a single letter instead of the API
-        // level.
-        if (p && isalpha(p[0]) && p[1] == 0) {
-            level = avdInfo_getApiLevelFromLetter(p[0]);
-            if (level > 99 && toupper(p[0]) >= 'M') {
-                *isMarshmallowOrHigher = true;
-            }
-        } else {
-            goto NOT_A_NUMBER;
-        }
-    } else {
-        char* end;
-        long  val = strtol(p, &end, 10);
-        if (end == NULL || *end != '\0' || val != (int)val) {
-            goto NOT_A_NUMBER;
-        }
-        level = (int)val;
-
-        /* Sanity check, we don't support anything prior to Android 1.5 */
-        if (level < 3)
-            level = 3;
-
-        D("Found AVD target API level: %d", level);
-    }
-EXIT:
-    AFREE(target);
-    return level;
-
-NOT_A_NUMBER:
-    if (p == NULL) {
-        D("Invalid target field in root AVD .ini file");
-    } else {
-        D("Target AVD api level is not a number");
-    }
-    D("Defaulting to API level %d", level);
-    goto EXIT;
-}
-
-bool
-avdInfo_isGoogleApis(const AvdInfo* i) {
-    return i->isGoogleApis;
-}
-
-bool
-avdInfo_isUserBuild(const AvdInfo* i) {
-    return i->isUserBuild;
-}
-
-AvdFlavor avdInfo_getAvdFlavor(const AvdInfo* i) {
-    return i->flavor;
-}
-
-int
-avdInfo_getApiLevel(const AvdInfo* i) {
-    return i->apiLevel;
-}
-
-// This information was taken from the SDK Manager:
-// Appearances & Behavior > System Settings > Android SDK > SDK Platforms
-static const struct {
-    int apiLevel;
-    const char* dessertName;
-    const char* fullName;
-} kApiLevelInfo[] = {
-    { 10, "Gingerbread", "2.3.3 (Gingerbread) - API 10 (Rev 2)" },
-    { 14, "Ice Cream Sandwich", "4.0 (Ice Cream Sandwich) - API 14 (Rev 4)" },
-    { 15, "Ice Cream Sandwich", "4.0.3 (Ice Cream Sandwich) - API 15 (Rev 5)" },
-    { 16, "Jelly Bean", "4.1 (Jelly Bean) - API 16 (Rev 5)" },
-    { 17, "Jelly Bean", "4.2 (Jelly Bean) - API 17 (Rev 3)" },
-    { 18, "Jelly Bean", "4.3 (Jelly Bean) - API 18 (Rev 3)" },
-    { 19, "KitKat", "4.4 (KitKat) - API 19 (Rev 4)" },
-    { 20, "KitKat", "4.4 (KitKat Wear) - API 20 (Rev 2)" },
-    { 21, "Lollipop", "5.0 (Lollipop) - API 21 (Rev 2)" },
-    { 22, "Lollipop", "5.1 (Lollipop) - API 22 (Rev 2)" },
-    { 23, "Marshmallow", "6.0 (Marshmallow) - API 23 (Rev 1)" },
-    { 24, "Nougat", "7.0 (Nougat) - API 24" },
-    { 25, "Nougat", "7.1 (Nougat) - API 25" },
-    { 26, "Oreo", "8.0 (Oreo) - API 26" },
-    { 27, "Oreo", "8.1 (Oreo) - API 27" },
-    { 28, "Pie", "9.0 (Pie) - API 28" },
-    { 29, "Q", "10.0 (Q) - API 29" },
-    { 30, "R", "11.0 (R) - API 30"}
-};
-
-const char* avdInfo_getApiDessertName(int apiLevel) {
-    int i = 0;
-    for (; i < ARRAY_SIZE(kApiLevelInfo); ++i) {
-        if (kApiLevelInfo[i].apiLevel == apiLevel) {
-            return kApiLevelInfo[i].dessertName;
-        }
-    }
-    return "";
-}
-
-void avdInfo_getFullApiName(int apiLevel, char* nameStr, int strLen) {
-    if (apiLevel < 0 || apiLevel > 99) {
-        strncpy(nameStr, "Unknown API version", strLen);
-        return;
-    }
-
-    int i = 0;
-    for (; i < ARRAY_SIZE(kApiLevelInfo); ++i) {
-        if (kApiLevelInfo[i].apiLevel == apiLevel) {
-            strncpy(nameStr, kApiLevelInfo[i].fullName, strLen);
-            return;
-        }
-    }
-    snprintf(nameStr, strLen, "API %d", apiLevel);
-}
-
-int avdInfo_getApiLevelFromLetter(char letter) {
-    const char letterUpper = toupper(letter);
-    int i = 0;
-    for (; i < ARRAY_SIZE(kApiLevelInfo); ++i) {
-        if (toupper(kApiLevelInfo[i].dessertName[0]) == letterUpper) {
-            return kApiLevelInfo[i].apiLevel;
-        }
-    }
-    return kUnknownApiLevel;
-}
-
-/* Look for a named file inside the AVD's content directory.
- * Returns NULL if it doesn't exist, or a strdup() copy otherwise.
- */
-static char*
-_avdInfo_getContentFilePath(const AvdInfo*  i, const char* fileName)
-{
-    char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
-
-    p = bufprint(p, end, "%s"PATH_SEP"%s", i->contentPath, fileName);
-    if (p >= end) {
-        derror("can't access virtual device content directory");
-        return NULL;
-    }
-    if (!path_exists(temp)) {
-        return NULL;
-    }
-    return ASTRDUP(temp);
-}
-
-/* find and parse the config.ini file from the content directory */
-static int
-_avdInfo_getConfigIni(AvdInfo*  i)
-{
-    char*  iniPath = _avdInfo_getContentFilePath(i, CORE_CONFIG_INI);
-
-    /* Allow non-existing config.ini */
-    if (iniPath == NULL) {
-        D("virtual device has no config file - no problem");
-        return 0;
-    }
-
-    D("virtual device config file: %s", iniPath);
-    i->configIni = iniFile_newFromFile(iniPath);
-    AFREE(iniPath);
-
-    if (i->configIni == NULL) {
-        derror("bad config: %s",
-               "virtual device has corrupted " CORE_CONFIG_INI);
-        return -1;
-    }
-    return 0;
-}
-
-/* The AVD's config.ini contains a list of search paths (all beginning
- * with SEARCH_PREFIX) which are directory locations searched for
- * AVD platform files.
- */
-static bool
-_avdInfo_getSearchPaths( AvdInfo*  i )
-{
-    if (i->configIni == NULL)
-        return true;
-
-    if (android_cmdLineOptions && android_cmdLineOptions->sysdir) {
-        // The user specified a path on the command line.
-        // Use only that.
-        i->numSearchPaths = 1;
-        i->searchPaths[0] = android_cmdLineOptions->sysdir;
-        DD("using one search path from the command line for this AVD");
-        return true;
-    }
-
-    i->numSearchPaths = _getSearchPaths( i->configIni,
-                                         i->sdkRootPath,
-                                         MAX_SEARCH_PATHS,
-                                         i->searchPaths );
-    if (i->numSearchPaths == 0) {
-        derror("no search paths found in this AVD's configuration.\n"
-               "Weird, the AVD's " CORE_CONFIG_INI " file is malformed. "
-               "Try re-creating it.\n");
-        return false;
-    }
-    else
-        DD("found a total of %d search paths for this AVD", i->numSearchPaths);
-    return true;
-}
-
-/* Search a file in the SDK search directories. Return NULL if not found,
- * or a strdup() otherwise.
- */
-static char*
-_avdInfo_getSdkFilePath(const AvdInfo*  i, const char*  fileName)
-{
-    char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
-
-    do {
-        /* try the search paths */
-        int  nn;
-
-        for (nn = 0; nn < i->numSearchPaths; nn++) {
-            const char* searchDir = i->searchPaths[nn];
-
-            p = bufprint(temp, end, "%s"PATH_SEP"%s", searchDir, fileName);
-            if (p < end && path_exists(temp)) {
-                DD("found %s in search dir: %s", fileName, searchDir);
-                goto FOUND;
-            }
-            DD("    no %s in search dir: %s", fileName, searchDir);
-        }
-
-        return NULL;
-
-    } while (0);
-
-FOUND:
-    return ASTRDUP(temp);
-}
-
-/* Search for a file in the content directory, and if not found, in the
- * SDK search directory. Returns NULL if not found.
- */
-static char*
-_avdInfo_getContentOrSdkFilePath(const AvdInfo*  i, const char*  fileName)
-{
-    char*  path;
-
-    path = _avdInfo_getContentFilePath(i, fileName);
-    if (path)
-        return path;
-
-    path = _avdInfo_getSdkFilePath(i, fileName);
-    if (path)
-        return path;
-
-    return NULL;
-}
-
-#if 0
-static int
-_avdInfo_findContentOrSdkImage(const AvdInfo* i, AvdImageType id)
-{
-    const char* fileName = _imageFileNames[id];
-    char*       path     = _avdInfo_getContentOrSdkFilePath(i, fileName);
-
-    i->imagePath[id]  = path;
-    i->imageState[id] = IMAGE_STATE_READONLY;
-
-    if (path == NULL)
-        return -1;
-    else
-        return 0;
-}
-#endif
-
-/* Returns path to the core hardware .ini file. This contains the
- * hardware configuration that is read by the core. The content of this
- * file is auto-generated before launching a core, but we need to know
- * its path before that.
- */
-static int
-_avdInfo_getCoreHwIniPath( AvdInfo* i, const char* basePath )
-{
-    i->coreHardwareIniPath = _getFullFilePath(basePath, CORE_HARDWARE_INI);
-    if (i->coreHardwareIniPath == NULL) {
-        DD("Path too long for %s: %s", CORE_HARDWARE_INI, basePath);
-        return -1;
-    }
-    D("using core hw config path: %s", i->coreHardwareIniPath);
-    return 0;
-}
-
-static int
-_avdInfo_getSnapshotLockFilePath( AvdInfo* i, const char* basePath )
-{
-    i->snapshotLockPath = _getFullFilePath(basePath, SNAPSHOT_LOCK);
-    if (i->snapshotLockPath == NULL) {
-        DD("Path too long for %s: %s", SNAPSHOT_LOCK, basePath);
-        return -1;
-    }
-    D("using snapshot lock path: %s", i->snapshotLockPath);
-    return 0;
-}
-
-static int
-_avdInfo_getMultiInstanceLockFilePath( AvdInfo* i, const char* basePath )
-{
-    i->multiInstanceLockPath = _getFullFilePath(basePath, MULTIINSTANCE_LOCK);
-    if (i->multiInstanceLockPath == NULL) {
-        DD("Path too long for %s: %s", MULTIINSTANCE_LOCK, basePath);
-        return -1;
-    }
-    D("using multi-instance lock path: %s", i->multiInstanceLockPath);
-    return 0;
-}
-
-static void
-_avdInfo_readPropertyFile(const AvdInfo* i,
-                          const char* filePath,
-                          FileData* data) {
-    int ret = fileData_initFromFile(data, filePath);
-    if (ret < 0) {
-        D("Error reading property file %s: %s", filePath, strerror(-ret));
-    } else {
-        D("Read property file at %s", filePath);
-    }
-}
-
-static void
-_avdInfo_extractBuildProperties(AvdInfo* i) {
-    i->targetArch = propertyFile_getTargetArch(i->buildProperties);
-    if (!i->targetArch) {
-        str_reset(&i->targetArch, "arm");
-        D("Cannot find target CPU architecture, defaulting to '%s'",
-          i->targetArch);
-    }
-    i->targetAbi = propertyFile_getTargetAbi(i->buildProperties);
-    if (!i->targetAbi) {
-        str_reset(&i->targetAbi, "armeabi");
-        D("Cannot find target CPU ABI, defaulting to '%s'",
-          i->targetAbi);
-    }
-    if (!i->apiLevel) {
-        // Note: for regular AVDs, the API level is already extracted
-        // from config.ini, besides, for older SDK platform images,
-        // there is no build.prop file and the following function
-        // would always return 1000, making the AVD unbootable!.
-        i->apiLevel = propertyFile_getApiLevel(i->buildProperties);
-        if (i->apiLevel < 3) {
-            i->apiLevel = 3;
-            D("Cannot find target API level, defaulting to %d",
-            i->apiLevel);
-        }
-    }
-
-    i->flavor = propertyFile_getAvdFlavor(i->buildProperties);
-
-    i->isGoogleApis = propertyFile_isGoogleApis(i->buildProperties);
-    i->isUserBuild = propertyFile_isUserBuild(i->buildProperties);
-    i->incrementalVersion = propertyFile_getInt(
-        i->buildProperties,
-        "ro.build.version.incremental",
-        -1,
-        NULL);
-}
-
-
-static void
-_avdInfo_getPropertyFile(AvdInfo* i,
-                         const char* propFileName,
-                         FileData* data ) {
-    char* filePath = _avdInfo_getContentOrSdkFilePath(i, propFileName);
-    if (!filePath) {
-        D("No %s property file found.", propFileName);
-        return;
-    }
-
-    _avdInfo_readPropertyFile(i, filePath, data);
-    free(filePath);
-}
-
-AvdInfo*
-avdInfo_new( const char*  name, AvdInfoParams*  params )
-{
-    AvdInfo*  i;
-
-    if (name == NULL)
-        return NULL;
-
-    if (!_checkAvdName(name)) {
-        derror("virtual device name contains invalid characters");
-        return NULL;
-    }
-
-    ANEW0(i);
-    str_reset(&i->deviceName, name);
-    str_reset(&i->deviceId, name);
-    i->noChecks = false;
-
-    if ( _avdInfo_getSdkRoot(i) < 0     ||
-         _avdInfo_getRootIni(i) < 0     ||
-         _avdInfo_getContentPath(i) < 0 ||
-         _avdInfo_getConfigIni(i)   < 0 ||
-         _avdInfo_getCoreHwIniPath(i, i->contentPath) < 0 ||
-         _avdInfo_getSnapshotLockFilePath(i, i->contentPath) < 0 ||
-         _avdInfo_getMultiInstanceLockFilePath(i, i->contentPath) < 0)
-        goto FAIL;
-
-    i->apiLevel = _avdInfo_getApiLevel(i, &i->isMarshmallowOrHigher);
-
-    /* look for image search paths. handle post 1.1/pre cupcake
-     * obsolete SDKs.
-     */
-    if (!_avdInfo_getSearchPaths(i)) {
-        goto FAIL;
-    }
-
-    // Find the build.prop and boot.prop files and read them.
-    _avdInfo_getPropertyFile(i, "build.prop", i->buildProperties);
-    _avdInfo_getPropertyFile(i, "boot.prop", i->bootProperties);
-
-    _avdInfo_extractBuildProperties(i);
-
-    /* don't need this anymore */
-    iniFile_free(i->rootIni);
-    i->rootIni = NULL;
-
-    return i;
-
-FAIL:
-    avdInfo_free(i);
-    return NULL;
-}
-
-void avdInfo_setAvdId( AvdInfo* i, const char* avdId)
-{
-    if (i == NULL) return;
-
-    str_reset(&i->deviceId, avdId);
-}
-
-/***************************************************************
- ***************************************************************
- *****
- *****    ANDROID BUILD SUPPORT
- *****
- *****    The code below corresponds to the case where we're
- *****    starting the emulator inside the Android build
- *****    system. The main differences are that:
- *****
- *****    - the $ANDROID_PRODUCT_OUT directory is used as the
- *****      content file.
- *****
- *****    - built images must not be modified by the emulator,
- *****      so system.img must be copied to a temporary file
- *****      and userdata.img must be copied to userdata-qemu.img
- *****      if the latter doesn't exist.
- *****
- *****    - the kernel and default skin directory are taken from
- *****      prebuilt
- *****
- *****    - there is no root .ini file, or any config.ini in
- *****      the content directory, no SDK images search path.
- *****/
-
-/* Read a hardware.ini if it is located in the skin directory */
-static int
-_avdInfo_getBuildSkinHardwareIni( AvdInfo*  i )
-{
-    char* skinName;
-    char* skinDirPath;
-
-    avdInfo_getSkinInfo(i, &skinName, &skinDirPath);
-    if (skinDirPath == NULL)
-        return 0;
-
-    int result = avdInfo_getSkinHardwareIni(i, skinName, skinDirPath);
-
-    AFREE(skinName);
-    AFREE(skinDirPath);
-
-    return result;
-}
-
-int avdInfo_getSkinHardwareIni( AvdInfo* i, char* skinName, char* skinDirPath)
-{
-    char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
-    p = bufprint(temp, end, "%s"PATH_SEP"%s"PATH_SEP"hardware.ini", skinDirPath, skinName);
-    if (p >= end || !path_exists(temp)) {
-        DD("no skin-specific hardware.ini in %s", skinDirPath);
-        return 0;
-    }
-
-    D("found skin-specific hardware.ini: %s", temp);
-    if (i->skinHardwareIni != NULL)
-        iniFile_free(i->skinHardwareIni);
-    i->skinHardwareIni = iniFile_newFromFile(temp);
-    if (i->skinHardwareIni == NULL)
-        return -1;
-
-    return 0;
-}
-
-AvdInfo*
-avdInfo_newForAndroidBuild( const char*     androidBuildRoot,
-                            const char*     androidOut,
-                            AvdInfoParams*  params )
-{
-    AvdInfo*  i;
-
-    ANEW0(i);
-
-    i->inAndroidBuild   = 1;
-    str_reset(&i->androidBuildRoot, androidBuildRoot);
-    str_reset(&i->androidOut, androidOut);
-    str_reset(&i->contentPath, androidOut);
-
-    // Find the build.prop file and read it.
-    char* buildPropPath = path_getBuildBuildProp(i->androidOut);
-    if (buildPropPath) {
-        _avdInfo_readPropertyFile(i, buildPropPath, i->buildProperties);
-        free(buildPropPath);
-    }
-
-    // FInd the boot.prop file and read it.
-    char* bootPropPath = path_getBuildBootProp(i->androidOut);
-    if (bootPropPath) {
-        _avdInfo_readPropertyFile(i, bootPropPath, i->bootProperties);
-        free(bootPropPath);
-    }
-
-    _avdInfo_extractBuildProperties(i);
-
-    str_reset(&i->deviceName, "<build>");
-    str_reset(&i->deviceId, "<build>");
-
-    i->numSearchPaths = 1;
-    i->searchPaths[0] = strdup(androidOut);
-    /* out/target/product/<name>/config.ini, if exists, provide configuration
-     * from build files. */
-    if (_avdInfo_getConfigIni(i) < 0 ||
-        _avdInfo_getCoreHwIniPath(i, i->androidOut) < 0 ||
-        _avdInfo_getSnapshotLockFilePath(i, i->androidOut) < 0 ||
-        _avdInfo_getMultiInstanceLockFilePath(i, i->androidOut) < 0)
-        goto FAIL;
-
-    /* Read the build skin's hardware.ini, if any */
-    _avdInfo_getBuildSkinHardwareIni(i);
-
-    return i;
-
-FAIL:
-    avdInfo_free(i);
-    return NULL;
-}
-
-const char*
-avdInfo_getName( const AvdInfo*  i )
-{
-    return i ? i->deviceName : NULL;
-}
-
-const char*
-avdInfo_getId( const AvdInfo*  i )
-{
-    return i ? i->deviceId : NULL;
-}
-
-const char*
-avdInfo_getImageFile( const AvdInfo*  i, AvdImageType  imageType )
-{
-    if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
-        return NULL;
-
-    return i->imagePath[imageType];
-}
-
-uint64_t
-avdInfo_getImageFileSize( const AvdInfo*  i, AvdImageType  imageType )
-{
-    const char* file = avdInfo_getImageFile(i, imageType);
-    uint64_t    size;
-
-    if (file == NULL)
-        return 0ULL;
-
-    if (path_get_size(file, &size) < 0)
-        return 0ULL;
-
-    return size;
-}
-
-int
-avdInfo_isImageReadOnly( const AvdInfo*  i, AvdImageType  imageType )
-{
-    if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
-        return 1;
-
-    return (i->imageState[imageType] == IMAGE_STATE_READONLY);
-}
-
-char*
-avdInfo_getKernelPath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_KERNEL ];
-
-    char*  kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
-
-    do {
-        if (kernelPath || !i->inAndroidBuild)
-            break;
-
-        /* When in the Android build, look into the prebuilt directory
-         * for our target architecture.
-         */
-        char temp[PATH_MAX], *p = temp, *end = p + sizeof(temp);
-        const char* suffix = "";
-
-        // If the target ABI is armeabi-v7a, then look for
-        // kernel-qemu-armv7 instead of kernel-qemu in the prebuilt
-        // directory.
-        if (!strcmp(i->targetAbi, "armeabi-v7a")) {
-            suffix = "-armv7";
-        }
-
-        p = bufprint(temp, end, "%s"PATH_SEP"kernel", i->androidOut);
-        if (p < end && path_exists(temp)) {
-            str_reset(&kernelPath, temp);
-            break;
-        }
-
-        p = bufprint(temp, end, "%s"PATH_SEP"prebuilts"PATH_SEP"qemu-kernel"PATH_SEP"%s"PATH_SEP"kernel-qemu%s",
-                     i->androidBuildRoot, i->targetArch, suffix);
-        if (p >= end || !path_exists(temp)) {
-            derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
-            kernelPath = NULL;
-            break;
-        }
-        str_reset(&kernelPath, temp);
-
-    } while (0);
-
-    return kernelPath;
-}
-
-char*
-avdInfo_getRanchuKernelPath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_KERNELRANCHU64 ];
-    char*  kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
-    if (kernelPath) {
-        return kernelPath;
-    }
-
-    imageName = _imageFileNames[ AVD_IMAGE_KERNELRANCHU ];
-    kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
-
-    //old flow, checks the prebuilds/qemu-kernel, ignore //32bit-image-on-64bit scenario:
-    //the build process should have a copy of kernel-ranchu/kernel-ranchu-64 in the
-    //android out already,and will be handled by _avdInfo_getContentOrSdkFilePath()
-    do {
-        if (kernelPath || !i->inAndroidBuild)
-            break;
-
-        /* When in the Android build, look into the prebuilt directory
-         * for our target architecture.
-         */
-        char temp[PATH_MAX], *p = temp, *end = p + sizeof(temp);
-        const char* suffix = "";
-
-        /* mips/ranchu holds distinct images for mips & mips32[r5|r6] */
-        if (!strcmp(i->targetAbi, "mips32r6")) {
-            suffix = "-mips32r6";
-        } else if (!strcmp(i->targetAbi, "mips32r5")) {
-            suffix = "-mips32r5";
-        }
-
-        p = bufprint(temp, end, "%s"PATH_SEP"prebuilts"PATH_SEP"qemu-kernel"PATH_SEP"%s"PATH_SEP"ranchu"PATH_SEP"kernel-qemu%s",
-                     i->androidBuildRoot, i->targetArch, suffix);
-        if (p >= end || !path_exists(temp)) {
-            /* arm64 and mips64 are special: their kernel-qemu is actually kernel-ranchu */
-            if (!strcmp(i->targetArch, "arm64") || !strcmp(i->targetArch, "mips64")) {
-                return avdInfo_getKernelPath(i);
-            } else {
-                derror("bad workspace: cannot find prebuilt ranchu kernel in: %s", temp);
-                kernelPath = NULL;
-                break;
-            }
-        }
-        str_reset(&kernelPath, temp);
-    } while (0);
-
-    return kernelPath;
-}
-
-
-char*
-avdInfo_getRamdiskPath( const AvdInfo* i )
-{
-    const char* userImageName = _imageFileNames[ AVD_IMAGE_USERRAMDISK ];
-    char* result = _avdInfo_getContentOrSdkFilePath(i, userImageName);
-    if (result) return result;
-
-    const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ];
-    return _avdInfo_getContentOrSdkFilePath(i, imageName);
-}
-
-char*  avdInfo_getCachePath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
-    return _avdInfo_getContentFilePath(i, imageName);
-}
-
-char*  avdInfo_getDefaultCachePath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
-    return _getFullFilePath(i->contentPath, imageName);
-}
-
-char*  avdInfo_getSdCardPath( const AvdInfo* i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_SDCARD ];
-    char*       path;
-
-    /* Special case, the config.ini can have a SDCARD_PATH entry
-     * that gives the full path to the SD Card.
-     */
-    if (i->configIni != NULL) {
-        path = iniFile_getString(i->configIni, SDCARD_PATH, NULL);
-        if (path != NULL) {
-            if (path_exists(path))
-                return path;
-
-            dwarning("Ignoring invalid SDCard path: %s", path);
-            AFREE(path);
-        }
-    }
-
-    if (i->imagePath[ AVD_IMAGE_SDCARD ] != NULL) {
-        path = ASTRDUP(i->imagePath[ AVD_IMAGE_SDCARD ]);
-        if (path_exists(path))
-            return path;
-
-        dwarning("Ignoring invalid SDCard path: %s", path);
-        AFREE(path);
-    }
-
-    /* Otherwise, simply look into the content directory */
-    return _avdInfo_getContentFilePath(i, imageName);
-}
-
-char* avdInfo_getEncryptionKeyImagePath(const AvdInfo* i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_ENCRYPTIONKEY ];
-    return _avdInfo_getContentFilePath(i, imageName);
-}
-
-char*
-avdInfo_getSnapStoragePath( const AvdInfo* i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ];
-    return _avdInfo_getContentFilePath(i, imageName);
-}
-
-char*
-avdInfo_getSystemImagePath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ];
-    return _avdInfo_getContentFilePath(i, imageName);
-}
-
-char*
-avdInfo_getVerifiedBootParamsPath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_VERIFIEDBOOTPARAMS ];
-    return _avdInfo_getContentOrSdkFilePath(i, imageName);
-}
-
-char*
-avdInfo_getSystemInitImagePath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ];
-    return _avdInfo_getContentOrSdkFilePath(i, imageName);
-}
-
-char*
-avdInfo_getVendorImagePath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_USERVENDOR ];
-    return _avdInfo_getContentFilePath(i, imageName);
-}
-
-char*
-avdInfo_getVendorInitImagePath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_INITVENDOR ];
-    return _avdInfo_getContentOrSdkFilePath(i, imageName);
-}
-
-static bool
-is_x86ish(const AvdInfo* i)
-{
-    if (strncmp(i->targetAbi, "x86", 3) == 0) {
-        return true;
-    } else {
-        return false;
-    }
-}
-
-static bool
-is_armish(const AvdInfo* i)
-{
-    if (strncmp(i->targetAbi, "arm", 3) == 0) {
-        return true;
-    } else {
-        return false;
-    }
-}
-
-static bool
-is_mipsish(const AvdInfo* i)
-{
-    if (strncmp(i->targetAbi, "mips", 4) == 0) {
-        return true;
-    } else {
-        return false;
-    }
-}
-
-/*
-    arm is pretty tricky: the system image device path
-    changes depending on the number of disks: the last
-    one seems always a003e00, we need to know how many
-    devices it actually has
-*/
-const char* const arm_device_id[] = {
-    "a003e00",
-    "a003c00",
-    "a003a00",
-    "a003800",
-    "a003600",
-    "a003400",
-};
-
-const char* const mips_device_id[] = {
-    "1f03d000",
-    "1f03d200",
-    "1f03d400",
-    "1f03d600",
-    "1f03d800",
-};
-
-static
-bool has_sdcard(const AvdInfo* i) {
-    char* path = avdInfo_getSdCardPath(i);
-    if (path) {
-        free(path);
-        return true;
-    }
-    return false;
-}
-
-static
-bool has_vendor(const AvdInfo* i) {
-    char* path = avdInfo_getVendorInitImagePath(i);
-    if (path) {
-        free(path);
-        return true;
-    }
-    path = avdInfo_getVendorImagePath(i);
-    if (path) {
-        free(path);
-        return true;
-    }
-    return false;
-}
-
-static
-bool has_encryption(const AvdInfo* i) {
-    char* path = avdInfo_getEncryptionKeyImagePath(i);
-    if (path) {
-        free(path);
-        return true;
-    }
-    return false;
-}
-
-
-static
-char* get_device_path(const AvdInfo* info, const char* image)
-{
-    const char* device_table[6] = {"", "","" ,"" ,"" , ""};
-    int i = 0;
-    if (has_sdcard(info)) {
-        device_table[i++] = "sdcard";
-    }
-    if (has_vendor(info)) {
-        device_table[i++] = "vendor";
-    }
-    if (has_encryption(info)) {
-        device_table[i++] = "encryption";
-    }
-    device_table[i++] = "userdata";
-    device_table[i++] = "cache";
-    device_table[i++] = "system";
-    int count = ARRAY_SIZE(device_table);
-    for ( i=0; i < count; ++i) {
-        if (strcmp(image, device_table[i]) ==0) {
-            break;
-        }
-    }
-    if (i == count) {
-        return NULL;
-    }
-    char buf[1024];
-
-    if (is_armish(info)) {
-        snprintf(buf, sizeof(buf), "/dev/block/platform/%s.virtio_mmio/by-name/%s",
-                arm_device_id[i], image);
-    } else if (is_mipsish(info)) {
-        snprintf(buf, sizeof(buf), "/dev/block/platform/%s.virtio_mmio/by-name/%s",
-                mips_device_id[i], image);
-    }
-    return strdup(buf);
-}
-
-char*
-avdInfo_getVendorImageDevicePathInGuest( const AvdInfo*  i )
-{
-    if (!has_vendor(i)) {
-        return NULL;
-    }
-
-    if (is_x86ish(i)) {
-        if (has_encryption(i)) {
-            return strdup("/dev/block/pci/pci0000:00/0000:00:07.0/by-name/vendor");
-        } else {
-            return strdup("/dev/block/pci/pci0000:00/0000:00:06.0/by-name/vendor");
-        }
-    } else {
-        return get_device_path(i, "vendor");
-    }
-    return NULL;
-}
-
-char*
-avdInfo_getDynamicPartitionBootDevice( const AvdInfo*  i )
-{
-    if (is_x86ish(i)) {
-        return strdup("pci0000:00/0000:00:03.0");
-    }
-
-    char* system_path = get_device_path(i, "system");
-    if (!system_path) {
-        return NULL;
-    }
-
-    char* bootdev = strdup(system_path + strlen("/dev/block/platform/"));
-    char* end = strstr(bootdev, "/by-name/system");
-    *end = '\0';
-    return bootdev;
-}
-
-char*
-avdInfo_getSystemImageDevicePathInGuest( const AvdInfo*  i )
-{
-    if (feature_is_enabled(kFeature_SystemAsRoot)) {
-        return NULL;
-    }
-    if (is_x86ish(i)) {
-        return strdup("/dev/block/pci/pci0000:00/0000:00:03.0/by-name/system");
-    } else {
-        return get_device_path(i, "system");
-    }
-}
-
-char*
-avdInfo_getDataImagePath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
-    return _avdInfo_getContentFilePath(i, imageName);
-}
-
-char*
-avdInfo_getDefaultDataImagePath( const AvdInfo*  i )
-{
-    const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
-    return _getFullFilePath(i->contentPath, imageName);
-}
-
-char* avdInfo_getDefaultSystemFeatureControlPath(const AvdInfo* i) {
-    char* retVal = _avdInfo_getSdkFilePath(i, "advancedFeatures.ini");
-    return retVal;
-}
-
-char* avdInfo_getDataInitImagePath(const AvdInfo* i) {
-    const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ];
-    return _avdInfo_getContentOrSdkFilePath(i, imageName);
-}
-
-char* avdInfo_getDataInitDirPath(const AvdInfo* i) {
-    const char* imageName = _imageFileNames[ AVD_IMAGE_INITZIP ];
-    return _avdInfo_getSdkFilePath(i, imageName);
-}
-
-int
-avdInfo_initHwConfig(const AvdInfo* i, AndroidHwConfig*  hw, bool isQemu2)
-{
-    int  ret = 0;
-
-    androidHwConfig_init(hw, i->apiLevel);
-
-    /* First read the skin's hardware.ini, if any */
-    if (i->skinHardwareIni != NULL) {
-        ret = androidHwConfig_read(hw, i->skinHardwareIni);
-    }
-
-    /* The device's config.ini can override the skin's values
-     * (which is preferable to the opposite order)
-     */
-    if (ret == 0 && i->configIni != NULL) {
-        ret = androidHwConfig_read(hw, i->configIni);
-        /* We will set hw.arc in avd manager when creating new avd.
-         * Before new avd manager released, we check tag.id to see
-         * if it's a Chrome OS image.
-         */
-        if (ret == 0 && !hw->hw_arc) {
-            char *tag = iniFile_getString(i->configIni, TAG_ID, "default");
-            if (!strcmp(tag, TAG_ID_CHROMEOS)) {
-                hw->hw_arc = true;
-            }
-            AFREE(tag);
-        }
-    }
-
-    /* Auto-disable keyboard emulation on sapphire platform builds */
-    if (i->androidOut != NULL) {
-        char*  p = strrchr(i->androidOut, *PATH_SEP);
-        if (p != NULL && !strcmp(p,"sapphire")) {
-            hw->hw_keyboard = 0;
-        }
-    }
-
-    // for api <= 10 there is no multi-touch support in any of the ranchu
-    // or goldfish kernels and GUI won't respond as a result;
-    // force it to be "touch"
-    //
-    // for api <= 21 the goldfish kernel is not updated to
-    // support multi-touch yet; so just force touch
-    // bug: https://code.google.com/p/android/issues/detail?id=199289
-    //
-    // System images above 10 support multi-touch if they have a ranchu kernel
-    // and we're using QEMU2 as indicated by the isQemu2 flag.
-    //
-    // TODO: There is currently an issue related to this to track the release of
-    // system images with ranchu kernels for API 21 and below at:
-    // https://code.google.com/p/android/issues/detail?id=200332
-    if (i->apiLevel <= 10 || (!isQemu2 && i->apiLevel <= 21)) {
-            str_reset(&hw->hw_screen, "touch");
-    }
-
-    if (hw->hw_arc) {
-        // Chrome OS GPU acceleration is not perfect now, disable it
-        // in "default" mode, it still can be enabled with explicit
-        // setting.
-        if (hw->hw_gpu_mode == NULL || !strcmp(hw->hw_gpu_mode, "auto"))
-            str_reset(&hw->hw_gpu_mode, "off");
-        str_reset(&hw->hw_cpu_arch, "x86_64");
-    }
-
-    return ret;
-}
-
-void
-avdInfo_setImageFile( AvdInfo*  i, AvdImageType  imageType,
-                      const char*  imagePath )
-{
-    assert(i != NULL && (unsigned)imageType < AVD_IMAGE_MAX);
-
-    i->imagePath[imageType] = ASTRDUP(imagePath);
-}
-
-void
-avdInfo_setAcpiIniPath( AvdInfo* i, const char* iniPath )
-{
-    assert(i != NULL);
-
-    i->acpiIniPath = ASTRDUP(iniPath);
-}
-const char*
-avdInfo_getContentPath( const AvdInfo*  i )
-{
-    return i->contentPath;
-}
-
-const char*
-avdInfo_getRootIniPath( const AvdInfo*  i )
-{
-    return i->rootIniPath;
-}
-
-const char*
-avdInfo_getAcpiIniPath( const AvdInfo* i )
-{
-    return i->acpiIniPath;
-}
-
-int
-avdInfo_inAndroidBuild( const AvdInfo*  i )
-{
-    return i->inAndroidBuild;
-}
-
-char*
-avdInfo_getTargetCpuArch(const AvdInfo* i) {
-    return ASTRDUP(i->targetArch);
-}
-
-char*
-avdInfo_getTargetAbi( const AvdInfo* i )
-{
-    /* For now, we can't get the ABI from SDK AVDs */
-    return ASTRDUP(i->targetAbi);
-}
-
-bool avdInfo_is_x86ish(const AvdInfo* i)
-{
-    return is_x86ish(i);
-}
-
-char*
-avdInfo_getCodeProfilePath( const AvdInfo*  i, const char*  profileName )
-{
-    char   tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
-
-    if (i == NULL || profileName == NULL || profileName[0] == 0)
-        return NULL;
-
-    if (i->inAndroidBuild) {
-        p = bufprint( p, end, "%s" PATH_SEP "profiles" PATH_SEP "%s",
-                      i->androidOut, profileName );
-    } else {
-        p = bufprint( p, end, "%s" PATH_SEP "profiles" PATH_SEP "%s",
-                      i->contentPath, profileName );
-    }
-    return ASTRDUP(tmp);
-}
-
-const char*
-avdInfo_getCoreHwIniPath( const AvdInfo* i )
-{
-    return i->coreHardwareIniPath;
-}
-
-const char*
-avdInfo_getSnapshotLockFilePath( const AvdInfo* i )
-{
-    return i->snapshotLockPath;
-}
-
-const char*
-avdInfo_getMultiInstanceLockFilePath( const AvdInfo* i )
-{
-    return i->multiInstanceLockPath;
-}
-
-void
-avdInfo_getSkinInfo( const AvdInfo*  i, char** pSkinName, char** pSkinDir )
-{
-    char*  skinName = NULL;
-    char*  skinPath;
-    char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
-    *pSkinName = NULL;
-    *pSkinDir  = NULL;
-
-    if (!i->contentPath) {
-        *pSkinName = ASTRDUP(SKIN_DEFAULT);
-        return;
-    }
-
-    /* First, see if the config.ini contains a SKIN_PATH entry that
-     * names the full directory path for the skin.
-     */
-    if (i->configIni != NULL ) {
-        skinPath = iniFile_getString( i->configIni, SKIN_PATH, NULL );
-        if (skinPath != NULL) {
-            /* If this skin name is magic or a direct directory path
-            * we have our result right here.
-            */
-            if (_getSkinPathFromName(skinPath, i->sdkRootPath,
-                                     pSkinName, pSkinDir )) {
-                AFREE(skinPath);
-                return;
-            }
-        }
-
-        /* The SKIN_PATH entry was not valid, so look at SKIN_NAME */
-        D("Warning: " CORE_CONFIG_INI " contains invalid %s entry: %s",
-          SKIN_PATH, skinPath);
-        AFREE(skinPath);
-
-        skinName = iniFile_getString( i->configIni, SKIN_NAME, NULL );
-    }
-
-    if (skinName == NULL) {
-        /* If there is no skin listed in the config.ini, try to see if
-         * there is one single 'skin' directory in the content directory.
-         */
-        p = bufprint(temp, end, "%s"PATH_SEP"skin", i->contentPath);
-        if (p < end && _checkSkinPath(temp)) {
-            D("using skin content from %s", temp);
-            AFREE(i->skinName);
-            *pSkinName = ASTRDUP("skin");
-            *pSkinDir  = ASTRDUP(i->contentPath);
-            return;
-        }
-
-        if (i->configIni != NULL ) {
-            /* We need to create a name.
-             * Make a "magical" name using the screen size from config.ini
-             * (parse_skin_files() in main-common-ui.c parses this name
-             *  to determine the screen size.)
-             */
-            int width = iniFile_getInteger(i->configIni, "hw.lcd.width", 0);
-            int height = iniFile_getInteger(i->configIni, "hw.lcd.height", 0);
-            if (width > 0 && height > 0) {
-                char skinNameBuf[64];
-                snprintf(skinNameBuf, sizeof skinNameBuf, "%dx%d", width, height);
-                skinName = ASTRDUP(skinNameBuf);
-            } else {
-                skinName = ASTRDUP(SKIN_DEFAULT);
-            }
-        } else {
-            skinName = ASTRDUP(SKIN_DEFAULT);
-        }
-    }
-
-    /* now try to find the skin directory for that name -
-     */
-    do {
-        /* first try the content directory, i.e. $CONTENT/skins/<name> */
-        skinPath = _checkSkinSkinsDir(i->contentPath, skinName);
-        if (skinPath != NULL)
-            break;
-
-#define  PREBUILT_SKINS_ROOT "development"PATH_SEP"tools"PATH_SEP"emulator"
-
-        /* if we are in the Android build, try the prebuilt directory */
-        if (i->inAndroidBuild) {
-            p = bufprint( temp, end, "%s"PATH_SEP"%s",
-                        i->androidBuildRoot, PREBUILT_SKINS_ROOT );
-            if (p < end) {
-                skinPath = _checkSkinSkinsDir(temp, skinName);
-                if (skinPath != NULL)
-                    break;
-            }
-
-            /* or in the parent directory of the system dir */
-            {
-                char* parentDir = path_parent(i->androidOut, 1);
-                if (parentDir != NULL) {
-                    skinPath = _checkSkinSkinsDir(parentDir, skinName);
-                    AFREE(parentDir);
-                    if (skinPath != NULL)
-                        break;
-                }
-            }
-        }
-
-        /* look in the search paths. For each <dir> in the list,
-         * look into <dir>/../skins/<name>/ */
-        {
-            int  nn;
-            for (nn = 0; nn < i->numSearchPaths; nn++) {
-                char*  parentDir = path_parent(i->searchPaths[nn], 1);
-                if (parentDir == NULL)
-                    continue;
-                skinPath = _checkSkinSkinsDir(parentDir, skinName);
-                AFREE(parentDir);
-                if (skinPath != NULL)
-                  break;
-            }
-            if (nn < i->numSearchPaths)
-                break;
-        }
-
-        /* We didn't find anything ! */
-        *pSkinName = skinName;
-        return;
-
-    } while (0);
-
-    if (path_split(skinPath, pSkinDir, pSkinName) < 0) {
-        derror("weird skin path: %s", skinPath);
-        AFREE(skinPath);
-        return;
-    }
-    DD("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
-    AFREE(skinPath);
-    return;
-}
-
-char*
-avdInfo_getCharmapFile( const AvdInfo* i, const char* charmapName )
-{
-    char        fileNameBuff[PATH_MAX];
-    const char* fileName;
-
-    if (charmapName == NULL || charmapName[0] == '\0')
-        return NULL;
-
-    if (strstr(charmapName, ".kcm") == NULL) {
-        snprintf(fileNameBuff, sizeof fileNameBuff, "%s.kcm", charmapName);
-        fileName = fileNameBuff;
-    } else {
-        fileName = charmapName;
-    }
-
-    return _avdInfo_getContentOrSdkFilePath(i, fileName);
-}
-
-AdbdCommunicationMode avdInfo_getAdbdCommunicationMode(const AvdInfo* i,
-                                                       bool isQemu2)
-{
-    if (isQemu2) {
-        // All qemu2-compatible system images support modern communication mode.
-        return ADBD_COMMUNICATION_MODE_PIPE;
-    }
-
-    if (i->apiLevel < 16 || (i->apiLevel > 99 && !i->isMarshmallowOrHigher)) {
-        // QEMU pipe for ADB communication was added in android-4.1.1_r1 API 16
-        D("API < 16 or unknown, forcing ro.adb.qemud==0");
-        return ADBD_COMMUNICATION_MODE_LEGACY;
-    }
-
-    // Ignore property file since all system images have been updated a long
-    // time ago to support the pipe service for API level >= 16.
-    return ADBD_COMMUNICATION_MODE_PIPE;
-}
-
-int avdInfo_getSnapshotPresent(const AvdInfo* i)
-{
-    if (i->configIni == NULL) {
-        return 0;
-    } else {
-        return iniFile_getBoolean(i->configIni, SNAPSHOT_PRESENT, "no");
-    }
-}
-
-const FileData* avdInfo_getBootProperties(const AvdInfo* i) {
-    return i->bootProperties;
-}
-
-const FileData* avdInfo_getBuildProperties(const AvdInfo* i) {
-    return i->buildProperties;
-}
-
-CIniFile* avdInfo_getConfigIni(const AvdInfo* i) {
-    return i->configIni;
-}
-
-int avdInfo_getSysImgIncrementalVersion(const AvdInfo* i) {
-    return i->incrementalVersion;
-}
-
-const char* avdInfo_getTag(const AvdInfo* i) {
-    char temp[PATH_MAX];
-    char* tagId = "default";
-    char* tagDisplay = "Default";
-    if (i->configIni) {
-        tagId = iniFile_getString(i->configIni, TAG_ID, "default");
-        tagDisplay = iniFile_getString(i->configIni, TAG_DISPLAY, "Default");
-    }
-    snprintf(temp, PATH_MAX, "%s [%s]", tagId, tagDisplay);
-    return ASTRDUP(temp);
-}
-
-const char* avdInfo_getSdCardSize(const AvdInfo* i) {
-    return (i->configIni) ? iniFile_getString(i->configIni, SDCARD_SIZE, "")
-                          : NULL;
-}
-
-// Guest rendering is deprecated in future API level.  This function controls
-// the current guest rendering blacklist status; particular builds of system
-// images and particular API levels cannot run guest rendering.
-bool avdInfo_sysImgGuestRenderingBlacklisted(const AvdInfo* i) {
-    switch (i->apiLevel) {
-    // Allow guest rendering for older API levels
-    case 9:
-    case 10:
-    case 15:
-    case 16:
-    case 17:
-    case 18:
-        return false;
-    // Disallow guest rendering for some problematic builds
-    case 19:
-        return i->incrementalVersion == 4087698;
-    case 21:
-        return i->incrementalVersion == 4088174;
-    case 22:
-        return i->incrementalVersion == 4088218;
-    case 23:
-        return i->incrementalVersion == 4088240;
-    case 24:
-        return i->incrementalVersion == 4088244;
-    case 25:
-        return i->incrementalVersion == 4153093;
-    case 26:
-        return i->incrementalVersion == 4074420;
-    case 27:
-        return false;
-    // bug 111971822
-    // Guest side Swiftshader becomes much harder to maintain
-    // after SELinux changes that disallow executable memory.
-    case 28:
-    default:
-        return true;
-    }
-}
-
-void avdInfo_replaceDataPartitionSizeInConfigIni(AvdInfo* i, int64_t sizeBytes) {
-    if (!i || !i->configIni) return;
-    iniFile_setInt64(i->configIni, "disk.dataPartition.size", sizeBytes);
-
-    char*  iniPath = _avdInfo_getContentFilePath(i, CORE_CONFIG_INI);
-    iniFile_saveToFile(i->configIni, iniPath);
-}
-
-bool avdInfo_isMarshmallowOrHigher(AvdInfo* i) {
-    return i->isMarshmallowOrHigher;
-}
-
-AvdInfo* avdInfo_newCustom(
-    const char* name,
-    int apiLevel,
-    const char* abi,
-    const char* arch,
-    bool isGoogleApis,
-    AvdFlavor flavor) {
-
-    AvdInfo* i;
-    ANEW0(i);
-    str_reset(&i->deviceName, name);
-    str_reset(&i->deviceId, name);
-    i->noChecks = true;
-
-    i->apiLevel = apiLevel;
-    i->targetAbi = strdup(abi);
-    i->targetArch = strdup(arch);
-    i->isGoogleApis = isGoogleApis;
-    i->flavor = flavor;
-
-    return i;
-}
-
-void avdInfo_setCustomContentPath(AvdInfo* info, const char* path) {
-    info->contentPath = strdup(path);
-}
-
-void avdInfo_setCustomCoreHwIniPath(AvdInfo* info, const char* path) {
-    info->coreHardwareIniPath = strdup(path);
-}
-
-void avdInfo_replaceMultiDisplayInConfigIni(AvdInfo* i, int index,
-                                            int x, int y,
-                                            int w, int h,
-                                            int dpi, int flag ) {
-    if (!i || !i->configIni) return;
-
-//    char x_s[] = "hw.display0.xOffset";
-//    char y_s[] = "hw.display0.yOffset";
-    char w_s[] = "hw.display0.width";
-    char h_s[] = "hw.display0.height";
-    char d_s[] = "hw.display0.density";
-    char f_s[] = "hw.display0.flag";
-    bool write = false;
-
-//    x_s[10] += index;
-//    y_s[10] += index;
-    w_s[10] += index;
-    h_s[10] += index;
-    d_s[10] += index;
-    f_s[10] += index;
-
-//    if (iniFile_getInteger(i->configIni, x_s, -1) != x) {
-//        iniFile_setInteger(i->configIni, x_s, x);
-//        write = true;
-//    }
-//    if (iniFile_getInteger(i->configIni, y_s, -1) != y) {
-//        iniFile_setInteger(i->configIni, y_s, y);
-//        write = true;
-//    }
-    if (iniFile_getInteger(i->configIni, w_s, 0) != w) {
-        iniFile_setInteger(i->configIni, w_s, w);
-        write = true;
-    }
-    if (iniFile_getInteger(i->configIni, h_s, 0) != h) {
-        iniFile_setInteger(i->configIni, h_s, h);
-        write = true;
-    }
-    if (iniFile_getInteger(i->configIni, d_s, 0) != dpi) {
-        iniFile_setInteger(i->configIni, d_s, dpi);
-        write = true;
-    }
-    if (iniFile_getInteger(i->configIni, f_s, 0) != flag) {
-        iniFile_setInteger(i->configIni, f_s, flag);
-        write = true;
-    }
-
-    char*  iniPath = _avdInfo_getContentFilePath(i, CORE_CONFIG_INI);
-    if (iniPath && write)
-        iniFile_saveToFile(i->configIni, iniPath);
-}
-
-
diff --git a/host-common/avd/info.cpp b/host-common/avd/info.cpp
new file mode 100644
index 0000000..b9d11b9
--- /dev/null
+++ b/host-common/avd/info.cpp
@@ -0,0 +1,1998 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#include "info.h"
+
+#include "util.h"
+#include "keys.h"
+#include "base/ArraySize.h"
+#include "base/export.h"
+#include "host-common/feature_control.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* global variables - see android/globals.h */
+AvdInfoParams   android_avdParams[1];
+AvdInfo*        android_avdInfo;
+
+AEMU_EXPORT AvdInfo** aemu_get_android_avdInfoPtr() {
+    return &android_avdInfo;
+}
+
+/* set to 1 for debugging */
+#define DEBUG 0
+
+#if DEBUG >= 1
+#include <stdio.h>
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+#define DD(...) VERBOSE_PRINT(avd_config,__VA_ARGS__)
+#else
+#define D(...) (void)0
+#define DD(...) (void)0
+#endif
+
+/* technical note on how all of this is supposed to work:
+ *
+ * Each AVD corresponds to a "content directory" that is used to
+ * store persistent disk images and configuration files. Most remarkable
+ * are:
+ *
+ * - a "config.ini" file used to hold configuration information for the
+ *   AVD
+ *
+ * - mandatory user data image ("userdata-qemu.img") and cache image
+ *   ("cache.img")
+ *
+ * - optional mutable system image ("system-qemu.img"), kernel image
+ *   ("kernel-qemu") and read-only ramdisk ("ramdisk.img")
+ *
+ * When starting up an AVD, the emulator looks for relevant disk images
+ * in the content directory. If it doesn't find a given image there, it
+ * will try to search in the list of system directories listed in the
+ * 'config.ini' file through one of the following (key,value) pairs:
+ *
+ *    images.sysdir.1 = <first search path>
+ *    images.sysdir.2 = <second search path>
+ *
+ * The search paths can be absolute, or relative to the root SDK installation
+ * path (which is determined from the emulator program's location, or from the
+ * ANDROID_SDK_ROOT environment variable).
+ *
+ * Individual image disk search patch can be over-riden on the command-line
+ * with one of the usual options.
+ */
+
+/* certain disk image files are mounted read/write by the emulator
+ * to ensure that several emulators referencing the same files
+ * do not corrupt these files, we need to lock them and respond
+ * to collision depending on the image type.
+ *
+ * the enumeration below is used to record information about
+ * each image file path.
+ *
+ * READONLY means that the file will be mounted read-only
+ * and this doesn't need to be locked. must be first in list
+ *
+ * MUSTLOCK means that the file should be locked before
+ * being mounted by the emulator
+ *
+ * TEMPORARY means that the file has been copied to a
+ * temporary image, which can be mounted read/write
+ * but doesn't require locking.
+ */
+typedef enum {
+    IMAGE_STATE_READONLY,     /* unlocked */
+    IMAGE_STATE_MUSTLOCK,     /* must be locked */
+    IMAGE_STATE_LOCKED,       /* locked */
+    IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
+    IMAGE_STATE_TEMPORARY,    /* copied to temp file (no lock needed) */
+} AvdImageState;
+
+struct AvdInfo {
+    /* for the Android build system case */
+    char      inAndroidBuild;
+    char*     androidOut;
+    char*     androidBuildRoot;
+    char*     targetArch;
+    char*     targetAbi;
+    char*     acpiIniPath;
+
+    /* for the normal virtual device case */
+    char*     deviceName;
+    char*     deviceId;
+    char*     sdkRootPath;
+    char*     searchPaths[ MAX_SEARCH_PATHS ];
+    int       numSearchPaths;
+    char*     contentPath;
+    char*     rootIniPath;
+    CIniFile* rootIni;   /* root <foo>.ini file, empty if missing */
+    CIniFile* configIni; /* virtual device's config.ini, NULL if missing */
+    CIniFile* skinHardwareIni; /* skin-specific hardware.ini */
+
+    /* for both */
+    int       apiLevel;
+    int       incrementalVersion;
+
+    /* For preview releases where we don't know the exact API level this flag
+     * indicates that at least we know it's M+ (for some code that needs to
+     * select either legacy or modern operation mode.
+     */
+    bool      isMarshmallowOrHigher;
+    bool      isGoogleApis;
+    bool      isUserBuild;
+    AvdFlavor flavor;
+    char*     skinName;     /* skin name */
+    char*     skinDirPath;  /* skin directory */
+    char*     coreHardwareIniPath;  /* core hardware.ini path */
+    char*     snapshotLockPath;  /* core snapshot.lock path */
+    char*     multiInstanceLockPath;
+
+    // FileData  buildProperties[1];  /* build.prop file */
+    // FileData  bootProperties[1];   /* boot.prop file */
+
+    /* image files */
+    char*     imagePath [ AVD_IMAGE_MAX ];
+    char      imageState[ AVD_IMAGE_MAX ];
+
+    /* skip checks */
+    bool noChecks;
+};
+
+
+// void
+// avdInfo_free( AvdInfo*  i )
+// {
+//     if (i) {
+//         int  nn;
+// 
+//         for (nn = 0; nn < AVD_IMAGE_MAX; nn++)
+//             AFREE(i->imagePath[nn]);
+// 
+//         AFREE(i->skinName);
+//         AFREE(i->skinDirPath);
+//         AFREE(i->coreHardwareIniPath);
+//         AFREE(i->snapshotLockPath);
+// 
+//         fileData_done(i->buildProperties);
+//         fileData_done(i->bootProperties);
+// 
+//         for (nn = 0; nn < i->numSearchPaths; nn++)
+//             AFREE(i->searchPaths[nn]);
+// 
+//         i->numSearchPaths = 0;
+// 
+//         if (i->configIni) {
+//             iniFile_free(i->configIni);
+//             i->configIni = NULL;
+//         }
+// 
+//         if (i->skinHardwareIni) {
+//             iniFile_free(i->skinHardwareIni);
+//             i->skinHardwareIni = NULL;
+//         }
+// 
+//         if (i->rootIni) {
+//             iniFile_free(i->rootIni);
+//             i->rootIni = NULL;
+//         }
+// 
+//         AFREE(i->contentPath);
+//         AFREE(i->sdkRootPath);
+//         AFREE(i->rootIniPath);
+//         AFREE(i->targetArch);
+//         AFREE(i->targetAbi);
+// 
+//         if (i->inAndroidBuild) {
+//             AFREE(i->androidOut);
+//             AFREE(i->androidBuildRoot);
+//             AFREE(i->acpiIniPath);
+//         }
+// 
+//         AFREE(i->deviceName);
+//         AFREE(i->deviceId);
+//         AFREE(i);
+//     }
+// }
+// 
+// /* list of default file names for each supported image file type */
+// static const char*  const  _imageFileNames[ AVD_IMAGE_MAX ] = {
+// #define  _AVD_IMG(x,y,z)  y,
+//     AVD_IMAGE_LIST
+// #undef _AVD_IMG
+// };
+// 
+// /***************************************************************
+//  ***************************************************************
+//  *****
+//  *****    UTILITY FUNCTIONS
+//  *****
+//  *****  The following functions do not depend on the AvdInfo
+//  *****  structure and could easily be moved elsewhere.
+//  *****
+//  *****/
+// 
+// /* Parse a given config.ini file and extract the list of SDK search paths
+//  * from it. Returns the number of valid paths stored in 'searchPaths', or -1
+//  * in case of problem.
+//  *
+//  * Relative search paths in the config.ini will be stored as full pathnames
+//  * relative to 'sdkRootPath'.
+//  *
+//  * 'searchPaths' must be an array of char* pointers of at most 'maxSearchPaths'
+//  * entries.
+//  */
+// static int _getSearchPaths(CIniFile* configIni,
+//                            const char* sdkRootPath,
+//                            int maxSearchPaths,
+//                            char** searchPaths) {
+//     char  temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
+//     int   nn, count = 0;
+// 
+//     for (nn = 0; nn < maxSearchPaths; nn++) {
+//         char*  path;
+// 
+//         p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
+//         if (p >= end)
+//             continue;
+// 
+//         path = iniFile_getString(configIni, temp, NULL);
+//         if (path != NULL) {
+//             DD("    found image search path: %s", path);
+//             if (!path_is_absolute(path)) {
+//                 p = bufprint(temp, end, "%s"PATH_SEP"%s", sdkRootPath, path);
+//                 AFREE(path);
+//                 path = ASTRDUP(temp);
+//             }
+//             searchPaths[count++] = path;
+//         }
+//     }
+//     return count;
+// }
+// 
+// /* Check that an AVD name is valid. Returns 1 on success, 0 otherwise.
+//  */
+// static int
+// _checkAvdName( const char*  name )
+// {
+//     int  len  = strlen(name);
+//     int  len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+//                              "abcdefghijklmnopqrstuvwxyz"
+//                              "0123456789_.-");
+//     return (len == len2);
+// }
+// 
+// /* Returns the full path of a given file.
+//  *
+//  * If 'fileName' is an absolute path, this returns a simple copy.
+//  * Otherwise, this returns a new string corresponding to <rootPath>/<fileName>
+//  *
+//  * This returns NULL if the paths are too long.
+//  */
+// static char*
+// _getFullFilePath( const char* rootPath, const char* fileName )
+// {
+//     if (path_is_absolute(fileName)) {
+//         return ASTRDUP(fileName);
+//     } else {
+//         char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+// 
+//         p = bufprint(temp, end, "%s"PATH_SEP"%s", rootPath, fileName);
+//         if (p >= end) {
+//             return NULL;
+//         }
+//         return ASTRDUP(temp);
+//     }
+// }
+// 
+// /* check that a given directory contains a valid skin.
+//  * returns 1 on success, 0 on failure.
+//  */
+// static int
+// _checkSkinPath( const char*  skinPath )
+// {
+//     char  temp[MAX_PATH], *p=temp, *end=p+sizeof(temp);
+// 
+//     /* for now, if it has a 'layout' file, it is a valid skin path */
+//     p = bufprint(temp, end, "%s"PATH_SEP"layout", skinPath);
+//     if (p >= end || !path_exists(temp))
+//         return 0;
+// 
+//     return 1;
+// }
+// 
+// /* Check that there is a skin named 'skinName' listed from 'skinDirRoot'
+//  * this returns the full path of the skin directory (after alias expansions),
+//  * including the skin name, or NULL on failure.
+//  */
+// static char*
+// _checkSkinSkinsDir( const char*  skinDirRoot,
+//                     const char*  skinName )
+// {
+//     DirScanner*  scanner;
+//     char*        result;
+//     char         temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
+// 
+//     p = bufprint(temp, end, "%s"PATH_SEP"skins"PATH_SEP"%s", skinDirRoot, skinName);
+//     DD("Probing skin directory: %s", temp);
+//     if (p >= end || !path_exists(temp)) {
+//         DD("    ignore bad skin directory %s", temp);
+//         return NULL;
+//     }
+// 
+//     /* first, is this a normal skin directory ? */
+//     if (_checkSkinPath(temp)) {
+//         /* yes */
+//         DD("    found skin directory: %s", temp);
+//         return ASTRDUP(temp);
+//     }
+// 
+//     /* second, is it an alias to another skin ? */
+//     *p      = 0;
+//     result  = NULL;
+//     scanner = dirScanner_new(temp);
+//     if (scanner != NULL) {
+//         for (;;) {
+//             const char*  file = dirScanner_next(scanner);
+// 
+//             if (file == NULL)
+//                 break;
+// 
+//             if (strncmp(file, "alias-", 6) || file[6] == 0)
+//                 continue;
+// 
+//             p = bufprint(temp, end, "%s"PATH_SEP"skins"PATH_SEP"%s", skinDirRoot, file+6);
+//             if (p < end && _checkSkinPath(temp)) {
+//                 /* yes, it's an alias */
+//                 DD("    skin alias '%s' points to skin directory: %s",
+//                    file+6, temp);
+//                 result = ASTRDUP(temp);
+//                 break;
+//             }
+//         }
+//         dirScanner_free(scanner);
+//     }
+//     return result;
+// }
+// 
+// /* try to see if the skin name leads to a magic skin or skin path directly
+//  * returns 1 on success, 0 on error.
+//  *
+//  * on success, this sets up '*pSkinName' and '*pSkinDir'
+//  */
+// static int
+// _getSkinPathFromName( const char*  skinName,
+//                       const char*  sdkRootPath,
+//                       char**       pSkinName,
+//                       char**       pSkinDir )
+// {
+//     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+// 
+//     /* if the skin name has the format 'NNNNxNNN' where
+//     * NNN is a decimal value, then this is a 'magic' skin
+//     * name that doesn't require a skin directory
+//     */
+//     if (isdigit(skinName[0])) {
+//         int  width, height;
+//         if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
+//             D("'magic' skin format detected: %s", skinName);
+//             *pSkinName = ASTRDUP(skinName);
+//             *pSkinDir  = NULL;
+//             return 1;
+//         }
+//     }
+// 
+//     /* is the skin name a direct path to the skin directory ? */
+//     if (path_is_absolute(skinName) && _checkSkinPath(skinName)) {
+//         goto FOUND_IT;
+//     }
+// 
+//     /* is the skin name a relative path from the SDK root ? */
+//     p = bufprint(temp, end, "%s"PATH_SEP"%s", sdkRootPath, skinName);
+//     if (p < end && _checkSkinPath(temp)) {
+//         skinName = temp;
+//         goto FOUND_IT;
+//     }
+// 
+//     /* nope */
+//     return 0;
+// 
+// FOUND_IT:
+//     if (path_split(skinName, pSkinDir, pSkinName) < 0) {
+//         derror("malformed skin name: %s", skinName);
+//         return 0;
+//     }
+//     D("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
+//     return 1;
+// }
+// 
+// /***************************************************************
+//  ***************************************************************
+//  *****
+//  *****    NORMAL VIRTUAL DEVICE SUPPORT
+//  *****
+//  *****/
+// 
+// /* compute path to the root SDK directory
+//  * assume we are in $SDKROOT/tools/emulator[.exe]
+//  */
+// static int
+// _avdInfo_getSdkRoot( AvdInfo*  i )
+// {
+// 
+//     i->sdkRootPath = path_getSdkRoot();
+//     if (i->sdkRootPath == NULL) {
+//         derror("can't find SDK installation directory");
+//         return -1;
+//     }
+//     return 0;
+// }
+// 
+// /* parse the root config .ini file. it is located in
+//  * ~/.android/avd/<name>.ini or Windows equivalent
+//  */
+// static int
+// _avdInfo_getRootIni( AvdInfo*  i )
+// {
+//     i->rootIniPath = path_getRootIniPath( i->deviceName );
+// 
+//     if (i->rootIniPath == NULL) {
+//         derror("unknown virtual device name: '%s'", i->deviceName);
+//         return -1;
+//     }
+// 
+//     D("Android virtual device file at: %s", i->rootIniPath);
+// 
+//     i->rootIni = iniFile_newFromFile(i->rootIniPath);
+// 
+//     if (i->rootIni == NULL) {
+//         derror("Corrupt virtual device config file!");
+//         return -1;
+//     }
+//     return 0;
+// }
+// 
+// /* Returns the AVD's content path, i.e. the directory that contains
+//  * the AVD's content files (e.g. data partition, cache, sd card, etc...).
+//  *
+//  * We extract this by parsing the root config .ini file, looking for
+//  * a "path" elements.
+//  */
+// static int
+// _avdInfo_getContentPath( AvdInfo*  i )
+// {
+//     if (i->inAndroidBuild && i->androidOut && i->contentPath) {
+//         return 0;
+//     }
+// 
+//     char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+// 
+//     i->contentPath = iniFile_getString(i->rootIni, ROOT_ABS_PATH_KEY, NULL);
+// 
+//     if (i->contentPath == NULL) {
+//         derror("bad config: %s",
+//                "virtual device file lacks a "ROOT_ABS_PATH_KEY" entry");
+//         return -1;
+//     }
+// 
+//     if (!path_is_dir(i->contentPath)) {
+//         // If the absolute path doesn't match an actual directory, try
+//         // the relative path if present.
+//         const char* relPath = iniFile_getString(i->rootIni, ROOT_REL_PATH_KEY, NULL);
+//         if (relPath != NULL) {
+//             p = bufprint_config_path(temp, end);
+//             p = bufprint(p, end, PATH_SEP "%s", relPath);
+//             if (p < end && path_is_dir(temp)) {
+//                 str_reset(&i->contentPath, temp);
+//             }
+//         }
+//     }
+// 
+//     D("virtual device content at %s", i->contentPath);
+//     return 0;
+// }
+// 
+// static int
+// _avdInfo_getApiLevel(AvdInfo* i, bool* isMarshmallowOrHigher)
+// {
+//     char*       target;
+//     const char* p;
+//     const int   defaultLevel = kUnknownApiLevel;
+//     int         level        = defaultLevel;
+// 
+// #    define ROOT_TARGET_KEY   "target"
+// 
+//     target = iniFile_getString(i->rootIni, ROOT_TARGET_KEY, NULL);
+//     if (target == NULL) {
+//         D("No target field in root AVD .ini file?");
+//         D("Defaulting to API level %d", level);
+//         return level;
+//     }
+// 
+//     DD("Found target field in root AVD .ini file: '%s'", target);
+// 
+//     /* There are two acceptable formats for the target key.
+//      *
+//      * 1/  android-<level>
+//      * 2/  <vendor-name>:<add-on-name>:<level>
+//      *
+//      * Where <level> can be either a _name_ (for experimental/preview SDK builds)
+//      * or a decimal number. Note that if a _name_, it can start with a digit.
+//      */
+// 
+//     /* First, extract the level */
+//     if (!memcmp(target, "android-", 8))
+//         p = target + 8;
+//     else {
+//         /* skip two columns */
+//         p = strchr(target, ':');
+//         if (p != NULL) {
+//             p = strchr(p+1, ':');
+//             if (p != NULL)
+//                 p += 1;
+//         }
+//     }
+//     if (p == NULL || !isdigit(*p)) {
+//         // preview versions usually have a single letter instead of the API
+//         // level.
+//         if (p && isalpha(p[0]) && p[1] == 0) {
+//             level = avdInfo_getApiLevelFromLetter(p[0]);
+//             if (level > 99 && toupper(p[0]) >= 'M') {
+//                 *isMarshmallowOrHigher = true;
+//             }
+//         } else {
+//             goto NOT_A_NUMBER;
+//         }
+//     } else {
+//         char* end;
+//         long  val = strtol(p, &end, 10);
+//         if (end == NULL || *end != '\0' || val != (int)val) {
+//             goto NOT_A_NUMBER;
+//         }
+//         level = (int)val;
+// 
+//         /* Sanity check, we don't support anything prior to Android 1.5 */
+//         if (level < 3)
+//             level = 3;
+// 
+//         D("Found AVD target API level: %d", level);
+//     }
+// EXIT:
+//     AFREE(target);
+//     return level;
+// 
+// NOT_A_NUMBER:
+//     if (p == NULL) {
+//         D("Invalid target field in root AVD .ini file");
+//     } else {
+//         D("Target AVD api level is not a number");
+//     }
+//     D("Defaulting to API level %d", level);
+//     goto EXIT;
+// }
+// 
+// bool
+// avdInfo_isGoogleApis(const AvdInfo* i) {
+//     return i->isGoogleApis;
+// }
+// 
+// bool
+// avdInfo_isUserBuild(const AvdInfo* i) {
+//     return i->isUserBuild;
+// }
+// 
+// AvdFlavor avdInfo_getAvdFlavor(const AvdInfo* i) {
+//     return i->flavor;
+// }
+// 
+// int
+// avdInfo_getApiLevel(const AvdInfo* i) {
+//     return i->apiLevel;
+// }
+// 
+// // This information was taken from the SDK Manager:
+// // Appearances & Behavior > System Settings > Android SDK > SDK Platforms
+// static const struct {
+//     int apiLevel;
+//     const char* dessertName;
+//     const char* fullName;
+// } kApiLevelInfo[] = {
+//     { 10, "Gingerbread", "2.3.3 (Gingerbread) - API 10 (Rev 2)" },
+//     { 14, "Ice Cream Sandwich", "4.0 (Ice Cream Sandwich) - API 14 (Rev 4)" },
+//     { 15, "Ice Cream Sandwich", "4.0.3 (Ice Cream Sandwich) - API 15 (Rev 5)" },
+//     { 16, "Jelly Bean", "4.1 (Jelly Bean) - API 16 (Rev 5)" },
+//     { 17, "Jelly Bean", "4.2 (Jelly Bean) - API 17 (Rev 3)" },
+//     { 18, "Jelly Bean", "4.3 (Jelly Bean) - API 18 (Rev 3)" },
+//     { 19, "KitKat", "4.4 (KitKat) - API 19 (Rev 4)" },
+//     { 20, "KitKat", "4.4 (KitKat Wear) - API 20 (Rev 2)" },
+//     { 21, "Lollipop", "5.0 (Lollipop) - API 21 (Rev 2)" },
+//     { 22, "Lollipop", "5.1 (Lollipop) - API 22 (Rev 2)" },
+//     { 23, "Marshmallow", "6.0 (Marshmallow) - API 23 (Rev 1)" },
+//     { 24, "Nougat", "7.0 (Nougat) - API 24" },
+//     { 25, "Nougat", "7.1 (Nougat) - API 25" },
+//     { 26, "Oreo", "8.0 (Oreo) - API 26" },
+//     { 27, "Oreo", "8.1 (Oreo) - API 27" },
+//     { 28, "Pie", "9.0 (Pie) - API 28" },
+//     { 29, "Q", "10.0 (Q) - API 29" },
+//     { 30, "R", "11.0 (R) - API 30"}
+// };
+// 
+// const char* avdInfo_getApiDessertName(int apiLevel) {
+//     int i = 0;
+//     for (; i < ARRAY_SIZE(kApiLevelInfo); ++i) {
+//         if (kApiLevelInfo[i].apiLevel == apiLevel) {
+//             return kApiLevelInfo[i].dessertName;
+//         }
+//     }
+//     return "";
+// }
+// 
+// void avdInfo_getFullApiName(int apiLevel, char* nameStr, int strLen) {
+//     if (apiLevel < 0 || apiLevel > 99) {
+//         strncpy(nameStr, "Unknown API version", strLen);
+//         return;
+//     }
+// 
+//     int i = 0;
+//     for (; i < ARRAY_SIZE(kApiLevelInfo); ++i) {
+//         if (kApiLevelInfo[i].apiLevel == apiLevel) {
+//             strncpy(nameStr, kApiLevelInfo[i].fullName, strLen);
+//             return;
+//         }
+//     }
+//     snprintf(nameStr, strLen, "API %d", apiLevel);
+// }
+// 
+// int avdInfo_getApiLevelFromLetter(char letter) {
+//     const char letterUpper = toupper(letter);
+//     int i = 0;
+//     for (; i < ARRAY_SIZE(kApiLevelInfo); ++i) {
+//         if (toupper(kApiLevelInfo[i].dessertName[0]) == letterUpper) {
+//             return kApiLevelInfo[i].apiLevel;
+//         }
+//     }
+//     return kUnknownApiLevel;
+// }
+// 
+// /* Look for a named file inside the AVD's content directory.
+//  * Returns NULL if it doesn't exist, or a strdup() copy otherwise.
+//  */
+// static char*
+// _avdInfo_getContentFilePath(const AvdInfo*  i, const char* fileName)
+// {
+//     char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
+// 
+//     p = bufprint(p, end, "%s"PATH_SEP"%s", i->contentPath, fileName);
+//     if (p >= end) {
+//         derror("can't access virtual device content directory");
+//         return NULL;
+//     }
+//     if (!path_exists(temp)) {
+//         return NULL;
+//     }
+//     return ASTRDUP(temp);
+// }
+// 
+// /* find and parse the config.ini file from the content directory */
+// static int
+// _avdInfo_getConfigIni(AvdInfo*  i)
+// {
+//     char*  iniPath = _avdInfo_getContentFilePath(i, CORE_CONFIG_INI);
+// 
+//     /* Allow non-existing config.ini */
+//     if (iniPath == NULL) {
+//         D("virtual device has no config file - no problem");
+//         return 0;
+//     }
+// 
+//     D("virtual device config file: %s", iniPath);
+//     i->configIni = iniFile_newFromFile(iniPath);
+//     AFREE(iniPath);
+// 
+//     if (i->configIni == NULL) {
+//         derror("bad config: %s",
+//                "virtual device has corrupted " CORE_CONFIG_INI);
+//         return -1;
+//     }
+//     return 0;
+// }
+// 
+// /* The AVD's config.ini contains a list of search paths (all beginning
+//  * with SEARCH_PREFIX) which are directory locations searched for
+//  * AVD platform files.
+//  */
+// static bool
+// _avdInfo_getSearchPaths( AvdInfo*  i )
+// {
+//     if (i->configIni == NULL)
+//         return true;
+// 
+//     if (android_cmdLineOptions && android_cmdLineOptions->sysdir) {
+//         // The user specified a path on the command line.
+//         // Use only that.
+//         i->numSearchPaths = 1;
+//         i->searchPaths[0] = android_cmdLineOptions->sysdir;
+//         DD("using one search path from the command line for this AVD");
+//         return true;
+//     }
+// 
+//     i->numSearchPaths = _getSearchPaths( i->configIni,
+//                                          i->sdkRootPath,
+//                                          MAX_SEARCH_PATHS,
+//                                          i->searchPaths );
+//     if (i->numSearchPaths == 0) {
+//         derror("no search paths found in this AVD's configuration.\n"
+//                "Weird, the AVD's " CORE_CONFIG_INI " file is malformed. "
+//                "Try re-creating it.\n");
+//         return false;
+//     }
+//     else
+//         DD("found a total of %d search paths for this AVD", i->numSearchPaths);
+//     return true;
+// }
+// 
+// /* Search a file in the SDK search directories. Return NULL if not found,
+//  * or a strdup() otherwise.
+//  */
+// static char*
+// _avdInfo_getSdkFilePath(const AvdInfo*  i, const char*  fileName)
+// {
+//     char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
+// 
+//     do {
+//         /* try the search paths */
+//         int  nn;
+// 
+//         for (nn = 0; nn < i->numSearchPaths; nn++) {
+//             const char* searchDir = i->searchPaths[nn];
+// 
+//             p = bufprint(temp, end, "%s"PATH_SEP"%s", searchDir, fileName);
+//             if (p < end && path_exists(temp)) {
+//                 DD("found %s in search dir: %s", fileName, searchDir);
+//                 goto FOUND;
+//             }
+//             DD("    no %s in search dir: %s", fileName, searchDir);
+//         }
+// 
+//         return NULL;
+// 
+//     } while (0);
+// 
+// FOUND:
+//     return ASTRDUP(temp);
+// }
+// 
+// /* Search for a file in the content directory, and if not found, in the
+//  * SDK search directory. Returns NULL if not found.
+//  */
+// static char*
+// _avdInfo_getContentOrSdkFilePath(const AvdInfo*  i, const char*  fileName)
+// {
+//     char*  path;
+// 
+//     path = _avdInfo_getContentFilePath(i, fileName);
+//     if (path)
+//         return path;
+// 
+//     path = _avdInfo_getSdkFilePath(i, fileName);
+//     if (path)
+//         return path;
+// 
+//     return NULL;
+// }
+// 
+// #if 0
+// static int
+// _avdInfo_findContentOrSdkImage(const AvdInfo* i, AvdImageType id)
+// {
+//     const char* fileName = _imageFileNames[id];
+//     char*       path     = _avdInfo_getContentOrSdkFilePath(i, fileName);
+// 
+//     i->imagePath[id]  = path;
+//     i->imageState[id] = IMAGE_STATE_READONLY;
+// 
+//     if (path == NULL)
+//         return -1;
+//     else
+//         return 0;
+// }
+// #endif
+// 
+// /* Returns path to the core hardware .ini file. This contains the
+//  * hardware configuration that is read by the core. The content of this
+//  * file is auto-generated before launching a core, but we need to know
+//  * its path before that.
+//  */
+// static int
+// _avdInfo_getCoreHwIniPath( AvdInfo* i, const char* basePath )
+// {
+//     i->coreHardwareIniPath = _getFullFilePath(basePath, CORE_HARDWARE_INI);
+//     if (i->coreHardwareIniPath == NULL) {
+//         DD("Path too long for %s: %s", CORE_HARDWARE_INI, basePath);
+//         return -1;
+//     }
+//     D("using core hw config path: %s", i->coreHardwareIniPath);
+//     return 0;
+// }
+// 
+// static int
+// _avdInfo_getSnapshotLockFilePath( AvdInfo* i, const char* basePath )
+// {
+//     i->snapshotLockPath = _getFullFilePath(basePath, SNAPSHOT_LOCK);
+//     if (i->snapshotLockPath == NULL) {
+//         DD("Path too long for %s: %s", SNAPSHOT_LOCK, basePath);
+//         return -1;
+//     }
+//     D("using snapshot lock path: %s", i->snapshotLockPath);
+//     return 0;
+// }
+// 
+// static int
+// _avdInfo_getMultiInstanceLockFilePath( AvdInfo* i, const char* basePath )
+// {
+//     i->multiInstanceLockPath = _getFullFilePath(basePath, MULTIINSTANCE_LOCK);
+//     if (i->multiInstanceLockPath == NULL) {
+//         DD("Path too long for %s: %s", MULTIINSTANCE_LOCK, basePath);
+//         return -1;
+//     }
+//     D("using multi-instance lock path: %s", i->multiInstanceLockPath);
+//     return 0;
+// }
+// 
+// static void
+// _avdInfo_readPropertyFile(const AvdInfo* i,
+//                           const char* filePath,
+//                           FileData* data) {
+//     int ret = fileData_initFromFile(data, filePath);
+//     if (ret < 0) {
+//         D("Error reading property file %s: %s", filePath, strerror(-ret));
+//     } else {
+//         D("Read property file at %s", filePath);
+//     }
+// }
+// 
+// static void
+// _avdInfo_extractBuildProperties(AvdInfo* i) {
+//     i->targetArch = propertyFile_getTargetArch(i->buildProperties);
+//     if (!i->targetArch) {
+//         str_reset(&i->targetArch, "arm");
+//         D("Cannot find target CPU architecture, defaulting to '%s'",
+//           i->targetArch);
+//     }
+//     i->targetAbi = propertyFile_getTargetAbi(i->buildProperties);
+//     if (!i->targetAbi) {
+//         str_reset(&i->targetAbi, "armeabi");
+//         D("Cannot find target CPU ABI, defaulting to '%s'",
+//           i->targetAbi);
+//     }
+//     if (!i->apiLevel) {
+//         // Note: for regular AVDs, the API level is already extracted
+//         // from config.ini, besides, for older SDK platform images,
+//         // there is no build.prop file and the following function
+//         // would always return 1000, making the AVD unbootable!.
+//         i->apiLevel = propertyFile_getApiLevel(i->buildProperties);
+//         if (i->apiLevel < 3) {
+//             i->apiLevel = 3;
+//             D("Cannot find target API level, defaulting to %d",
+//             i->apiLevel);
+//         }
+//     }
+// 
+//     i->flavor = propertyFile_getAvdFlavor(i->buildProperties);
+// 
+//     i->isGoogleApis = propertyFile_isGoogleApis(i->buildProperties);
+//     i->isUserBuild = propertyFile_isUserBuild(i->buildProperties);
+//     i->incrementalVersion = propertyFile_getInt(
+//         i->buildProperties,
+//         "ro.build.version.incremental",
+//         -1,
+//         NULL);
+// }
+// 
+// 
+// static void
+// _avdInfo_getPropertyFile(AvdInfo* i,
+//                          const char* propFileName,
+//                          FileData* data ) {
+//     char* filePath = _avdInfo_getContentOrSdkFilePath(i, propFileName);
+//     if (!filePath) {
+//         D("No %s property file found.", propFileName);
+//         return;
+//     }
+// 
+//     _avdInfo_readPropertyFile(i, filePath, data);
+//     free(filePath);
+// }
+// 
+// AvdInfo*
+// avdInfo_new( const char*  name, AvdInfoParams*  params )
+// {
+//     AvdInfo*  i;
+// 
+//     if (name == NULL)
+//         return NULL;
+// 
+//     if (!_checkAvdName(name)) {
+//         derror("virtual device name contains invalid characters");
+//         return NULL;
+//     }
+// 
+//     ANEW0(i);
+//     str_reset(&i->deviceName, name);
+//     str_reset(&i->deviceId, name);
+//     i->noChecks = false;
+// 
+//     if ( _avdInfo_getSdkRoot(i) < 0     ||
+//          _avdInfo_getRootIni(i) < 0     ||
+//          _avdInfo_getContentPath(i) < 0 ||
+//          _avdInfo_getConfigIni(i)   < 0 ||
+//          _avdInfo_getCoreHwIniPath(i, i->contentPath) < 0 ||
+//          _avdInfo_getSnapshotLockFilePath(i, i->contentPath) < 0 ||
+//          _avdInfo_getMultiInstanceLockFilePath(i, i->contentPath) < 0)
+//         goto FAIL;
+// 
+//     i->apiLevel = _avdInfo_getApiLevel(i, &i->isMarshmallowOrHigher);
+// 
+//     /* look for image search paths. handle post 1.1/pre cupcake
+//      * obsolete SDKs.
+//      */
+//     if (!_avdInfo_getSearchPaths(i)) {
+//         goto FAIL;
+//     }
+// 
+//     // Find the build.prop and boot.prop files and read them.
+//     _avdInfo_getPropertyFile(i, "build.prop", i->buildProperties);
+//     _avdInfo_getPropertyFile(i, "boot.prop", i->bootProperties);
+// 
+//     _avdInfo_extractBuildProperties(i);
+// 
+//     /* don't need this anymore */
+//     iniFile_free(i->rootIni);
+//     i->rootIni = NULL;
+// 
+//     return i;
+// 
+// FAIL:
+//     avdInfo_free(i);
+//     return NULL;
+// }
+// 
+// void avdInfo_setAvdId( AvdInfo* i, const char* avdId)
+// {
+//     if (i == NULL) return;
+// 
+//     str_reset(&i->deviceId, avdId);
+// }
+// 
+// /***************************************************************
+//  ***************************************************************
+//  *****
+//  *****    ANDROID BUILD SUPPORT
+//  *****
+//  *****    The code below corresponds to the case where we're
+//  *****    starting the emulator inside the Android build
+//  *****    system. The main differences are that:
+//  *****
+//  *****    - the $ANDROID_PRODUCT_OUT directory is used as the
+//  *****      content file.
+//  *****
+//  *****    - built images must not be modified by the emulator,
+//  *****      so system.img must be copied to a temporary file
+//  *****      and userdata.img must be copied to userdata-qemu.img
+//  *****      if the latter doesn't exist.
+//  *****
+//  *****    - the kernel and default skin directory are taken from
+//  *****      prebuilt
+//  *****
+//  *****    - there is no root .ini file, or any config.ini in
+//  *****      the content directory, no SDK images search path.
+//  *****/
+// 
+// /* Read a hardware.ini if it is located in the skin directory */
+// static int
+// _avdInfo_getBuildSkinHardwareIni( AvdInfo*  i )
+// {
+//     char* skinName;
+//     char* skinDirPath;
+// 
+//     avdInfo_getSkinInfo(i, &skinName, &skinDirPath);
+//     if (skinDirPath == NULL)
+//         return 0;
+// 
+//     int result = avdInfo_getSkinHardwareIni(i, skinName, skinDirPath);
+// 
+//     AFREE(skinName);
+//     AFREE(skinDirPath);
+// 
+//     return result;
+// }
+// 
+// int avdInfo_getSkinHardwareIni( AvdInfo* i, char* skinName, char* skinDirPath)
+// {
+//     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+// 
+//     p = bufprint(temp, end, "%s"PATH_SEP"%s"PATH_SEP"hardware.ini", skinDirPath, skinName);
+//     if (p >= end || !path_exists(temp)) {
+//         DD("no skin-specific hardware.ini in %s", skinDirPath);
+//         return 0;
+//     }
+// 
+//     D("found skin-specific hardware.ini: %s", temp);
+//     if (i->skinHardwareIni != NULL)
+//         iniFile_free(i->skinHardwareIni);
+//     i->skinHardwareIni = iniFile_newFromFile(temp);
+//     if (i->skinHardwareIni == NULL)
+//         return -1;
+// 
+//     return 0;
+// }
+// 
+// AvdInfo*
+// avdInfo_newForAndroidBuild( const char*     androidBuildRoot,
+//                             const char*     androidOut,
+//                             AvdInfoParams*  params )
+// {
+//     AvdInfo*  i;
+// 
+//     ANEW0(i);
+// 
+//     i->inAndroidBuild   = 1;
+//     str_reset(&i->androidBuildRoot, androidBuildRoot);
+//     str_reset(&i->androidOut, androidOut);
+//     str_reset(&i->contentPath, androidOut);
+// 
+//     // Find the build.prop file and read it.
+//     char* buildPropPath = path_getBuildBuildProp(i->androidOut);
+//     if (buildPropPath) {
+//         _avdInfo_readPropertyFile(i, buildPropPath, i->buildProperties);
+//         free(buildPropPath);
+//     }
+// 
+//     // FInd the boot.prop file and read it.
+//     char* bootPropPath = path_getBuildBootProp(i->androidOut);
+//     if (bootPropPath) {
+//         _avdInfo_readPropertyFile(i, bootPropPath, i->bootProperties);
+//         free(bootPropPath);
+//     }
+// 
+//     _avdInfo_extractBuildProperties(i);
+// 
+//     str_reset(&i->deviceName, "<build>");
+//     str_reset(&i->deviceId, "<build>");
+// 
+//     i->numSearchPaths = 1;
+//     i->searchPaths[0] = strdup(androidOut);
+//     /* out/target/product/<name>/config.ini, if exists, provide configuration
+//      * from build files. */
+//     if (_avdInfo_getConfigIni(i) < 0 ||
+//         _avdInfo_getCoreHwIniPath(i, i->androidOut) < 0 ||
+//         _avdInfo_getSnapshotLockFilePath(i, i->androidOut) < 0 ||
+//         _avdInfo_getMultiInstanceLockFilePath(i, i->androidOut) < 0)
+//         goto FAIL;
+// 
+//     /* Read the build skin's hardware.ini, if any */
+//     _avdInfo_getBuildSkinHardwareIni(i);
+// 
+//     return i;
+// 
+// FAIL:
+//     avdInfo_free(i);
+//     return NULL;
+// }
+// 
+// const char*
+// avdInfo_getName( const AvdInfo*  i )
+// {
+//     return i ? i->deviceName : NULL;
+// }
+// 
+// const char*
+// avdInfo_getId( const AvdInfo*  i )
+// {
+//     return i ? i->deviceId : NULL;
+// }
+// 
+// const char*
+// avdInfo_getImageFile( const AvdInfo*  i, AvdImageType  imageType )
+// {
+//     if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
+//         return NULL;
+// 
+//     return i->imagePath[imageType];
+// }
+// 
+// uint64_t
+// avdInfo_getImageFileSize( const AvdInfo*  i, AvdImageType  imageType )
+// {
+//     const char* file = avdInfo_getImageFile(i, imageType);
+//     uint64_t    size;
+// 
+//     if (file == NULL)
+//         return 0ULL;
+// 
+//     if (path_get_size(file, &size) < 0)
+//         return 0ULL;
+// 
+//     return size;
+// }
+// 
+// int
+// avdInfo_isImageReadOnly( const AvdInfo*  i, AvdImageType  imageType )
+// {
+//     if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
+//         return 1;
+// 
+//     return (i->imageState[imageType] == IMAGE_STATE_READONLY);
+// }
+// 
+// char*
+// avdInfo_getKernelPath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_KERNEL ];
+// 
+//     char*  kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
+// 
+//     do {
+//         if (kernelPath || !i->inAndroidBuild)
+//             break;
+// 
+//         /* When in the Android build, look into the prebuilt directory
+//          * for our target architecture.
+//          */
+//         char temp[PATH_MAX], *p = temp, *end = p + sizeof(temp);
+//         const char* suffix = "";
+// 
+//         // If the target ABI is armeabi-v7a, then look for
+//         // kernel-qemu-armv7 instead of kernel-qemu in the prebuilt
+//         // directory.
+//         if (!strcmp(i->targetAbi, "armeabi-v7a")) {
+//             suffix = "-armv7";
+//         }
+// 
+//         p = bufprint(temp, end, "%s"PATH_SEP"kernel", i->androidOut);
+//         if (p < end && path_exists(temp)) {
+//             str_reset(&kernelPath, temp);
+//             break;
+//         }
+// 
+//         p = bufprint(temp, end, "%s"PATH_SEP"prebuilts"PATH_SEP"qemu-kernel"PATH_SEP"%s"PATH_SEP"kernel-qemu%s",
+//                      i->androidBuildRoot, i->targetArch, suffix);
+//         if (p >= end || !path_exists(temp)) {
+//             derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
+//             kernelPath = NULL;
+//             break;
+//         }
+//         str_reset(&kernelPath, temp);
+// 
+//     } while (0);
+// 
+//     return kernelPath;
+// }
+// 
+// char*
+// avdInfo_getRanchuKernelPath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_KERNELRANCHU64 ];
+//     char*  kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
+//     if (kernelPath) {
+//         return kernelPath;
+//     }
+// 
+//     imageName = _imageFileNames[ AVD_IMAGE_KERNELRANCHU ];
+//     kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
+// 
+//     //old flow, checks the prebuilds/qemu-kernel, ignore //32bit-image-on-64bit scenario:
+//     //the build process should have a copy of kernel-ranchu/kernel-ranchu-64 in the
+//     //android out already,and will be handled by _avdInfo_getContentOrSdkFilePath()
+//     do {
+//         if (kernelPath || !i->inAndroidBuild)
+//             break;
+// 
+//         /* When in the Android build, look into the prebuilt directory
+//          * for our target architecture.
+//          */
+//         char temp[PATH_MAX], *p = temp, *end = p + sizeof(temp);
+//         const char* suffix = "";
+// 
+//         /* mips/ranchu holds distinct images for mips & mips32[r5|r6] */
+//         if (!strcmp(i->targetAbi, "mips32r6")) {
+//             suffix = "-mips32r6";
+//         } else if (!strcmp(i->targetAbi, "mips32r5")) {
+//             suffix = "-mips32r5";
+//         }
+// 
+//         p = bufprint(temp, end, "%s"PATH_SEP"prebuilts"PATH_SEP"qemu-kernel"PATH_SEP"%s"PATH_SEP"ranchu"PATH_SEP"kernel-qemu%s",
+//                      i->androidBuildRoot, i->targetArch, suffix);
+//         if (p >= end || !path_exists(temp)) {
+//             /* arm64 and mips64 are special: their kernel-qemu is actually kernel-ranchu */
+//             if (!strcmp(i->targetArch, "arm64") || !strcmp(i->targetArch, "mips64")) {
+//                 return avdInfo_getKernelPath(i);
+//             } else {
+//                 derror("bad workspace: cannot find prebuilt ranchu kernel in: %s", temp);
+//                 kernelPath = NULL;
+//                 break;
+//             }
+//         }
+//         str_reset(&kernelPath, temp);
+//     } while (0);
+// 
+//     return kernelPath;
+// }
+// 
+// 
+// char*
+// avdInfo_getRamdiskPath( const AvdInfo* i )
+// {
+//     const char* userImageName = _imageFileNames[ AVD_IMAGE_USERRAMDISK ];
+//     char* result = _avdInfo_getContentOrSdkFilePath(i, userImageName);
+//     if (result) return result;
+// 
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ];
+//     return _avdInfo_getContentOrSdkFilePath(i, imageName);
+// }
+// 
+// char*  avdInfo_getCachePath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
+//     return _avdInfo_getContentFilePath(i, imageName);
+// }
+// 
+// char*  avdInfo_getDefaultCachePath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
+//     return _getFullFilePath(i->contentPath, imageName);
+// }
+// 
+// char*  avdInfo_getSdCardPath( const AvdInfo* i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_SDCARD ];
+//     char*       path;
+// 
+//     /* Special case, the config.ini can have a SDCARD_PATH entry
+//      * that gives the full path to the SD Card.
+//      */
+//     if (i->configIni != NULL) {
+//         path = iniFile_getString(i->configIni, SDCARD_PATH, NULL);
+//         if (path != NULL) {
+//             if (path_exists(path))
+//                 return path;
+// 
+//             dwarning("Ignoring invalid SDCard path: %s", path);
+//             AFREE(path);
+//         }
+//     }
+// 
+//     if (i->imagePath[ AVD_IMAGE_SDCARD ] != NULL) {
+//         path = ASTRDUP(i->imagePath[ AVD_IMAGE_SDCARD ]);
+//         if (path_exists(path))
+//             return path;
+// 
+//         dwarning("Ignoring invalid SDCard path: %s", path);
+//         AFREE(path);
+//     }
+// 
+//     /* Otherwise, simply look into the content directory */
+//     return _avdInfo_getContentFilePath(i, imageName);
+// }
+// 
+// char* avdInfo_getEncryptionKeyImagePath(const AvdInfo* i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_ENCRYPTIONKEY ];
+//     return _avdInfo_getContentFilePath(i, imageName);
+// }
+// 
+// char*
+// avdInfo_getSnapStoragePath( const AvdInfo* i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ];
+//     return _avdInfo_getContentFilePath(i, imageName);
+// }
+// 
+// char*
+// avdInfo_getSystemImagePath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ];
+//     return _avdInfo_getContentFilePath(i, imageName);
+// }
+// 
+// char*
+// avdInfo_getVerifiedBootParamsPath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_VERIFIEDBOOTPARAMS ];
+//     return _avdInfo_getContentOrSdkFilePath(i, imageName);
+// }
+// 
+// char*
+// avdInfo_getSystemInitImagePath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ];
+//     return _avdInfo_getContentOrSdkFilePath(i, imageName);
+// }
+// 
+// char*
+// avdInfo_getVendorImagePath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_USERVENDOR ];
+//     return _avdInfo_getContentFilePath(i, imageName);
+// }
+// 
+// char*
+// avdInfo_getVendorInitImagePath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_INITVENDOR ];
+//     return _avdInfo_getContentOrSdkFilePath(i, imageName);
+// }
+// 
+// static bool
+// is_x86ish(const AvdInfo* i)
+// {
+//     if (strncmp(i->targetAbi, "x86", 3) == 0) {
+//         return true;
+//     } else {
+//         return false;
+//     }
+// }
+// 
+// static bool
+// is_armish(const AvdInfo* i)
+// {
+//     if (strncmp(i->targetAbi, "arm", 3) == 0) {
+//         return true;
+//     } else {
+//         return false;
+//     }
+// }
+// 
+// static bool
+// is_mipsish(const AvdInfo* i)
+// {
+//     if (strncmp(i->targetAbi, "mips", 4) == 0) {
+//         return true;
+//     } else {
+//         return false;
+//     }
+// }
+// 
+// /*
+//     arm is pretty tricky: the system image device path
+//     changes depending on the number of disks: the last
+//     one seems always a003e00, we need to know how many
+//     devices it actually has
+// */
+// const char* const arm_device_id[] = {
+//     "a003e00",
+//     "a003c00",
+//     "a003a00",
+//     "a003800",
+//     "a003600",
+//     "a003400",
+// };
+// 
+// const char* const mips_device_id[] = {
+//     "1f03d000",
+//     "1f03d200",
+//     "1f03d400",
+//     "1f03d600",
+//     "1f03d800",
+// };
+// 
+// static
+// bool has_sdcard(const AvdInfo* i) {
+//     char* path = avdInfo_getSdCardPath(i);
+//     if (path) {
+//         free(path);
+//         return true;
+//     }
+//     return false;
+// }
+// 
+// static
+// bool has_vendor(const AvdInfo* i) {
+//     char* path = avdInfo_getVendorInitImagePath(i);
+//     if (path) {
+//         free(path);
+//         return true;
+//     }
+//     path = avdInfo_getVendorImagePath(i);
+//     if (path) {
+//         free(path);
+//         return true;
+//     }
+//     return false;
+// }
+// 
+// static
+// bool has_encryption(const AvdInfo* i) {
+//     char* path = avdInfo_getEncryptionKeyImagePath(i);
+//     if (path) {
+//         free(path);
+//         return true;
+//     }
+//     return false;
+// }
+// 
+// 
+// static
+// char* get_device_path(const AvdInfo* info, const char* image)
+// {
+//     const char* device_table[6] = {"", "","" ,"" ,"" , ""};
+//     int i = 0;
+//     if (has_sdcard(info)) {
+//         device_table[i++] = "sdcard";
+//     }
+//     if (has_vendor(info)) {
+//         device_table[i++] = "vendor";
+//     }
+//     if (has_encryption(info)) {
+//         device_table[i++] = "encryption";
+//     }
+//     device_table[i++] = "userdata";
+//     device_table[i++] = "cache";
+//     device_table[i++] = "system";
+//     int count = ARRAY_SIZE(device_table);
+//     for ( i=0; i < count; ++i) {
+//         if (strcmp(image, device_table[i]) ==0) {
+//             break;
+//         }
+//     }
+//     if (i == count) {
+//         return NULL;
+//     }
+//     char buf[1024];
+// 
+//     if (is_armish(info)) {
+//         snprintf(buf, sizeof(buf), "/dev/block/platform/%s.virtio_mmio/by-name/%s",
+//                 arm_device_id[i], image);
+//     } else if (is_mipsish(info)) {
+//         snprintf(buf, sizeof(buf), "/dev/block/platform/%s.virtio_mmio/by-name/%s",
+//                 mips_device_id[i], image);
+//     }
+//     return strdup(buf);
+// }
+// 
+// char*
+// avdInfo_getVendorImageDevicePathInGuest( const AvdInfo*  i )
+// {
+//     if (!has_vendor(i)) {
+//         return NULL;
+//     }
+// 
+//     if (is_x86ish(i)) {
+//         if (has_encryption(i)) {
+//             return strdup("/dev/block/pci/pci0000:00/0000:00:07.0/by-name/vendor");
+//         } else {
+//             return strdup("/dev/block/pci/pci0000:00/0000:00:06.0/by-name/vendor");
+//         }
+//     } else {
+//         return get_device_path(i, "vendor");
+//     }
+//     return NULL;
+// }
+// 
+// char*
+// avdInfo_getDynamicPartitionBootDevice( const AvdInfo*  i )
+// {
+//     if (is_x86ish(i)) {
+//         return strdup("pci0000:00/0000:00:03.0");
+//     }
+// 
+//     char* system_path = get_device_path(i, "system");
+//     if (!system_path) {
+//         return NULL;
+//     }
+// 
+//     char* bootdev = strdup(system_path + strlen("/dev/block/platform/"));
+//     char* end = strstr(bootdev, "/by-name/system");
+//     *end = '\0';
+//     return bootdev;
+// }
+// 
+// char*
+// avdInfo_getSystemImageDevicePathInGuest( const AvdInfo*  i )
+// {
+//     if (feature_is_enabled(kFeature_SystemAsRoot)) {
+//         return NULL;
+//     }
+//     if (is_x86ish(i)) {
+//         return strdup("/dev/block/pci/pci0000:00/0000:00:03.0/by-name/system");
+//     } else {
+//         return get_device_path(i, "system");
+//     }
+// }
+// 
+// char*
+// avdInfo_getDataImagePath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
+//     return _avdInfo_getContentFilePath(i, imageName);
+// }
+// 
+// char*
+// avdInfo_getDefaultDataImagePath( const AvdInfo*  i )
+// {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
+//     return _getFullFilePath(i->contentPath, imageName);
+// }
+// 
+// char* avdInfo_getDefaultSystemFeatureControlPath(const AvdInfo* i) {
+//     char* retVal = _avdInfo_getSdkFilePath(i, "advancedFeatures.ini");
+//     return retVal;
+// }
+// 
+// char* avdInfo_getDataInitImagePath(const AvdInfo* i) {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ];
+//     return _avdInfo_getContentOrSdkFilePath(i, imageName);
+// }
+// 
+// char* avdInfo_getDataInitDirPath(const AvdInfo* i) {
+//     const char* imageName = _imageFileNames[ AVD_IMAGE_INITZIP ];
+//     return _avdInfo_getSdkFilePath(i, imageName);
+// }
+// 
+// int
+// avdInfo_initHwConfig(const AvdInfo* i, AndroidHwConfig*  hw, bool isQemu2)
+// {
+//     int  ret = 0;
+// 
+//     androidHwConfig_init(hw, i->apiLevel);
+// 
+//     /* First read the skin's hardware.ini, if any */
+//     if (i->skinHardwareIni != NULL) {
+//         ret = androidHwConfig_read(hw, i->skinHardwareIni);
+//     }
+// 
+//     /* The device's config.ini can override the skin's values
+//      * (which is preferable to the opposite order)
+//      */
+//     if (ret == 0 && i->configIni != NULL) {
+//         ret = androidHwConfig_read(hw, i->configIni);
+//         /* We will set hw.arc in avd manager when creating new avd.
+//          * Before new avd manager released, we check tag.id to see
+//          * if it's a Chrome OS image.
+//          */
+//         if (ret == 0 && !hw->hw_arc) {
+//             char *tag = iniFile_getString(i->configIni, TAG_ID, "default");
+//             if (!strcmp(tag, TAG_ID_CHROMEOS)) {
+//                 hw->hw_arc = true;
+//             }
+//             AFREE(tag);
+//         }
+//     }
+// 
+//     /* Auto-disable keyboard emulation on sapphire platform builds */
+//     if (i->androidOut != NULL) {
+//         char*  p = strrchr(i->androidOut, *PATH_SEP);
+//         if (p != NULL && !strcmp(p,"sapphire")) {
+//             hw->hw_keyboard = 0;
+//         }
+//     }
+// 
+//     // for api <= 10 there is no multi-touch support in any of the ranchu
+//     // or goldfish kernels and GUI won't respond as a result;
+//     // force it to be "touch"
+//     //
+//     // for api <= 21 the goldfish kernel is not updated to
+//     // support multi-touch yet; so just force touch
+//     // bug: https://code.google.com/p/android/issues/detail?id=199289
+//     //
+//     // System images above 10 support multi-touch if they have a ranchu kernel
+//     // and we're using QEMU2 as indicated by the isQemu2 flag.
+//     //
+//     // TODO: There is currently an issue related to this to track the release of
+//     // system images with ranchu kernels for API 21 and below at:
+//     // https://code.google.com/p/android/issues/detail?id=200332
+//     if (i->apiLevel <= 10 || (!isQemu2 && i->apiLevel <= 21)) {
+//             str_reset(&hw->hw_screen, "touch");
+//     }
+// 
+//     if (hw->hw_arc) {
+//         // Chrome OS GPU acceleration is not perfect now, disable it
+//         // in "default" mode, it still can be enabled with explicit
+//         // setting.
+//         if (hw->hw_gpu_mode == NULL || !strcmp(hw->hw_gpu_mode, "auto"))
+//             str_reset(&hw->hw_gpu_mode, "off");
+//         str_reset(&hw->hw_cpu_arch, "x86_64");
+//     }
+// 
+//     return ret;
+// }
+// 
+// void
+// avdInfo_setImageFile( AvdInfo*  i, AvdImageType  imageType,
+//                       const char*  imagePath )
+// {
+//     assert(i != NULL && (unsigned)imageType < AVD_IMAGE_MAX);
+// 
+//     i->imagePath[imageType] = ASTRDUP(imagePath);
+// }
+// 
+// void
+// avdInfo_setAcpiIniPath( AvdInfo* i, const char* iniPath )
+// {
+//     assert(i != NULL);
+// 
+//     i->acpiIniPath = ASTRDUP(iniPath);
+// }
+// const char*
+// avdInfo_getContentPath( const AvdInfo*  i )
+// {
+//     return i->contentPath;
+// }
+// 
+// const char*
+// avdInfo_getRootIniPath( const AvdInfo*  i )
+// {
+//     return i->rootIniPath;
+// }
+// 
+// const char*
+// avdInfo_getAcpiIniPath( const AvdInfo* i )
+// {
+//     return i->acpiIniPath;
+// }
+// 
+// int
+// avdInfo_inAndroidBuild( const AvdInfo*  i )
+// {
+//     return i->inAndroidBuild;
+// }
+// 
+// char*
+// avdInfo_getTargetCpuArch(const AvdInfo* i) {
+//     return ASTRDUP(i->targetArch);
+// }
+// 
+// char*
+// avdInfo_getTargetAbi( const AvdInfo* i )
+// {
+//     /* For now, we can't get the ABI from SDK AVDs */
+//     return ASTRDUP(i->targetAbi);
+// }
+// 
+// bool avdInfo_is_x86ish(const AvdInfo* i)
+// {
+//     return is_x86ish(i);
+// }
+// 
+// char*
+// avdInfo_getCodeProfilePath( const AvdInfo*  i, const char*  profileName )
+// {
+//     char   tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
+// 
+//     if (i == NULL || profileName == NULL || profileName[0] == 0)
+//         return NULL;
+// 
+//     if (i->inAndroidBuild) {
+//         p = bufprint( p, end, "%s" PATH_SEP "profiles" PATH_SEP "%s",
+//                       i->androidOut, profileName );
+//     } else {
+//         p = bufprint( p, end, "%s" PATH_SEP "profiles" PATH_SEP "%s",
+//                       i->contentPath, profileName );
+//     }
+//     return ASTRDUP(tmp);
+// }
+// 
+// const char*
+// avdInfo_getCoreHwIniPath( const AvdInfo* i )
+// {
+//     return i->coreHardwareIniPath;
+// }
+// 
+// const char*
+// avdInfo_getSnapshotLockFilePath( const AvdInfo* i )
+// {
+//     return i->snapshotLockPath;
+// }
+// 
+// const char*
+// avdInfo_getMultiInstanceLockFilePath( const AvdInfo* i )
+// {
+//     return i->multiInstanceLockPath;
+// }
+// 
+// void
+// avdInfo_getSkinInfo( const AvdInfo*  i, char** pSkinName, char** pSkinDir )
+// {
+//     char*  skinName = NULL;
+//     char*  skinPath;
+//     char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+// 
+//     *pSkinName = NULL;
+//     *pSkinDir  = NULL;
+// 
+//     if (!i->contentPath) {
+//         *pSkinName = ASTRDUP(SKIN_DEFAULT);
+//         return;
+//     }
+// 
+//     /* First, see if the config.ini contains a SKIN_PATH entry that
+//      * names the full directory path for the skin.
+//      */
+//     if (i->configIni != NULL ) {
+//         skinPath = iniFile_getString( i->configIni, SKIN_PATH, NULL );
+//         if (skinPath != NULL) {
+//             /* If this skin name is magic or a direct directory path
+//             * we have our result right here.
+//             */
+//             if (_getSkinPathFromName(skinPath, i->sdkRootPath,
+//                                      pSkinName, pSkinDir )) {
+//                 AFREE(skinPath);
+//                 return;
+//             }
+//         }
+// 
+//         /* The SKIN_PATH entry was not valid, so look at SKIN_NAME */
+//         D("Warning: " CORE_CONFIG_INI " contains invalid %s entry: %s",
+//           SKIN_PATH, skinPath);
+//         AFREE(skinPath);
+// 
+//         skinName = iniFile_getString( i->configIni, SKIN_NAME, NULL );
+//     }
+// 
+//     if (skinName == NULL) {
+//         /* If there is no skin listed in the config.ini, try to see if
+//          * there is one single 'skin' directory in the content directory.
+//          */
+//         p = bufprint(temp, end, "%s"PATH_SEP"skin", i->contentPath);
+//         if (p < end && _checkSkinPath(temp)) {
+//             D("using skin content from %s", temp);
+//             AFREE(i->skinName);
+//             *pSkinName = ASTRDUP("skin");
+//             *pSkinDir  = ASTRDUP(i->contentPath);
+//             return;
+//         }
+// 
+//         if (i->configIni != NULL ) {
+//             /* We need to create a name.
+//              * Make a "magical" name using the screen size from config.ini
+//              * (parse_skin_files() in main-common-ui.c parses this name
+//              *  to determine the screen size.)
+//              */
+//             int width = iniFile_getInteger(i->configIni, "hw.lcd.width", 0);
+//             int height = iniFile_getInteger(i->configIni, "hw.lcd.height", 0);
+//             if (width > 0 && height > 0) {
+//                 char skinNameBuf[64];
+//                 snprintf(skinNameBuf, sizeof skinNameBuf, "%dx%d", width, height);
+//                 skinName = ASTRDUP(skinNameBuf);
+//             } else {
+//                 skinName = ASTRDUP(SKIN_DEFAULT);
+//             }
+//         } else {
+//             skinName = ASTRDUP(SKIN_DEFAULT);
+//         }
+//     }
+// 
+//     /* now try to find the skin directory for that name -
+//      */
+//     do {
+//         /* first try the content directory, i.e. $CONTENT/skins/<name> */
+//         skinPath = _checkSkinSkinsDir(i->contentPath, skinName);
+//         if (skinPath != NULL)
+//             break;
+// 
+// #define  PREBUILT_SKINS_ROOT "development"PATH_SEP"tools"PATH_SEP"emulator"
+// 
+//         /* if we are in the Android build, try the prebuilt directory */
+//         if (i->inAndroidBuild) {
+//             p = bufprint( temp, end, "%s"PATH_SEP"%s",
+//                         i->androidBuildRoot, PREBUILT_SKINS_ROOT );
+//             if (p < end) {
+//                 skinPath = _checkSkinSkinsDir(temp, skinName);
+//                 if (skinPath != NULL)
+//                     break;
+//             }
+// 
+//             /* or in the parent directory of the system dir */
+//             {
+//                 char* parentDir = path_parent(i->androidOut, 1);
+//                 if (parentDir != NULL) {
+//                     skinPath = _checkSkinSkinsDir(parentDir, skinName);
+//                     AFREE(parentDir);
+//                     if (skinPath != NULL)
+//                         break;
+//                 }
+//             }
+//         }
+// 
+//         /* look in the search paths. For each <dir> in the list,
+//          * look into <dir>/../skins/<name>/ */
+//         {
+//             int  nn;
+//             for (nn = 0; nn < i->numSearchPaths; nn++) {
+//                 char*  parentDir = path_parent(i->searchPaths[nn], 1);
+//                 if (parentDir == NULL)
+//                     continue;
+//                 skinPath = _checkSkinSkinsDir(parentDir, skinName);
+//                 AFREE(parentDir);
+//                 if (skinPath != NULL)
+//                   break;
+//             }
+//             if (nn < i->numSearchPaths)
+//                 break;
+//         }
+// 
+//         /* We didn't find anything ! */
+//         *pSkinName = skinName;
+//         return;
+// 
+//     } while (0);
+// 
+//     if (path_split(skinPath, pSkinDir, pSkinName) < 0) {
+//         derror("weird skin path: %s", skinPath);
+//         AFREE(skinPath);
+//         return;
+//     }
+//     DD("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
+//     AFREE(skinPath);
+//     return;
+// }
+// 
+// char*
+// avdInfo_getCharmapFile( const AvdInfo* i, const char* charmapName )
+// {
+//     char        fileNameBuff[PATH_MAX];
+//     const char* fileName;
+// 
+//     if (charmapName == NULL || charmapName[0] == '\0')
+//         return NULL;
+// 
+//     if (strstr(charmapName, ".kcm") == NULL) {
+//         snprintf(fileNameBuff, sizeof fileNameBuff, "%s.kcm", charmapName);
+//         fileName = fileNameBuff;
+//     } else {
+//         fileName = charmapName;
+//     }
+// 
+//     return _avdInfo_getContentOrSdkFilePath(i, fileName);
+// }
+// 
+// AdbdCommunicationMode avdInfo_getAdbdCommunicationMode(const AvdInfo* i,
+//                                                        bool isQemu2)
+// {
+//     if (isQemu2) {
+//         // All qemu2-compatible system images support modern communication mode.
+//         return ADBD_COMMUNICATION_MODE_PIPE;
+//     }
+// 
+//     if (i->apiLevel < 16 || (i->apiLevel > 99 && !i->isMarshmallowOrHigher)) {
+//         // QEMU pipe for ADB communication was added in android-4.1.1_r1 API 16
+//         D("API < 16 or unknown, forcing ro.adb.qemud==0");
+//         return ADBD_COMMUNICATION_MODE_LEGACY;
+//     }
+// 
+//     // Ignore property file since all system images have been updated a long
+//     // time ago to support the pipe service for API level >= 16.
+//     return ADBD_COMMUNICATION_MODE_PIPE;
+// }
+// 
+// int avdInfo_getSnapshotPresent(const AvdInfo* i)
+// {
+//     if (i->configIni == NULL) {
+//         return 0;
+//     } else {
+//         return iniFile_getBoolean(i->configIni, SNAPSHOT_PRESENT, "no");
+//     }
+// }
+// 
+// const FileData* avdInfo_getBootProperties(const AvdInfo* i) {
+//     return i->bootProperties;
+// }
+// 
+// const FileData* avdInfo_getBuildProperties(const AvdInfo* i) {
+//     return i->buildProperties;
+// }
+// 
+// CIniFile* avdInfo_getConfigIni(const AvdInfo* i) {
+//     return i->configIni;
+// }
+// 
+// int avdInfo_getSysImgIncrementalVersion(const AvdInfo* i) {
+//     return i->incrementalVersion;
+// }
+// 
+// const char* avdInfo_getTag(const AvdInfo* i) {
+//     char temp[PATH_MAX];
+//     char* tagId = "default";
+//     char* tagDisplay = "Default";
+//     if (i->configIni) {
+//         tagId = iniFile_getString(i->configIni, TAG_ID, "default");
+//         tagDisplay = iniFile_getString(i->configIni, TAG_DISPLAY, "Default");
+//     }
+//     snprintf(temp, PATH_MAX, "%s [%s]", tagId, tagDisplay);
+//     return ASTRDUP(temp);
+// }
+// 
+// const char* avdInfo_getSdCardSize(const AvdInfo* i) {
+//     return (i->configIni) ? iniFile_getString(i->configIni, SDCARD_SIZE, "")
+//                           : NULL;
+// }
+// 
+// // Guest rendering is deprecated in future API level.  This function controls
+// // the current guest rendering blacklist status; particular builds of system
+// // images and particular API levels cannot run guest rendering.
+// bool avdInfo_sysImgGuestRenderingBlacklisted(const AvdInfo* i) {
+//     switch (i->apiLevel) {
+//     // Allow guest rendering for older API levels
+//     case 9:
+//     case 10:
+//     case 15:
+//     case 16:
+//     case 17:
+//     case 18:
+//         return false;
+//     // Disallow guest rendering for some problematic builds
+//     case 19:
+//         return i->incrementalVersion == 4087698;
+//     case 21:
+//         return i->incrementalVersion == 4088174;
+//     case 22:
+//         return i->incrementalVersion == 4088218;
+//     case 23:
+//         return i->incrementalVersion == 4088240;
+//     case 24:
+//         return i->incrementalVersion == 4088244;
+//     case 25:
+//         return i->incrementalVersion == 4153093;
+//     case 26:
+//         return i->incrementalVersion == 4074420;
+//     case 27:
+//         return false;
+//     // bug 111971822
+//     // Guest side Swiftshader becomes much harder to maintain
+//     // after SELinux changes that disallow executable memory.
+//     case 28:
+//     default:
+//         return true;
+//     }
+// }
+// 
+// void avdInfo_replaceDataPartitionSizeInConfigIni(AvdInfo* i, int64_t sizeBytes) {
+//     if (!i || !i->configIni) return;
+//     iniFile_setInt64(i->configIni, "disk.dataPartition.size", sizeBytes);
+// 
+//     char*  iniPath = _avdInfo_getContentFilePath(i, CORE_CONFIG_INI);
+//     iniFile_saveToFile(i->configIni, iniPath);
+// }
+// 
+// bool avdInfo_isMarshmallowOrHigher(AvdInfo* i) {
+//     return i->isMarshmallowOrHigher;
+// }
+
+AvdInfo* avdInfo_newCustom(
+    const char* name,
+    int apiLevel,
+    const char* abi,
+    const char* arch,
+    bool isGoogleApis,
+    AvdFlavor flavor) {
+
+    AvdInfo* i = new AvdInfo;
+    memset(i, 0, sizeof(AvdInfo));
+
+    i->deviceName = strdup(name);
+    i->deviceId = strdup(name);
+
+    i->noChecks = true;
+
+    i->apiLevel = apiLevel;
+    i->targetAbi = strdup(abi);
+    i->targetArch = strdup(arch);
+    i->isGoogleApis = isGoogleApis;
+    i->flavor = flavor;
+
+    return i;
+}
diff --git a/host-common/opengl/EmuglBackendList.cpp b/host-common/opengl/EmuglBackendList.cpp
index f4d5bee..50bc220 100644
--- a/host-common/opengl/EmuglBackendList.cpp
+++ b/host-common/opengl/EmuglBackendList.cpp
@@ -9,13 +9,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
 
-#include "android/opengl/EmuglBackendList.h"
+#include "EmuglBackendList.h"
 
-#include "android/base/Log.h"
-#include "android/base/StringFormat.h"
-#include "android/base/system/System.h"
-#include "android/opengl/EmuglBackendScanner.h"
-#include "android/utils/path.h"
+#include "base/StringFormat.h"
+#include "base/System.h"
+#include "base/PathUtils.h"
 
 #define DEBUG 0
 
@@ -29,20 +27,6 @@
 namespace android {
 namespace opengl {
 
-using android::base::System;
-
-EmuglBackendList::EmuglBackendList(const char* execDir,
-                                   int programBitness) :
-        mDefaultName("auto"), mNames(), mProgramBitness(0), mExecDir(execDir) {
-    // Fix host bitness if needed.
-    if (!programBitness) {
-        programBitness = System::get()->getProgramBitness();
-    }
-    mProgramBitness = programBitness;
-
-    mNames = EmuglBackendScanner::scanDir(execDir, programBitness);
-}
-
 EmuglBackendList::EmuglBackendList(int programBitness,
                                    const std::vector<std::string>& names) :
         mDefaultName("auto"), mNames(names), mProgramBitness(programBitness) { }
@@ -58,18 +42,14 @@
 
 std::string EmuglBackendList::getLibDirPath(const char* name) {
     // remove the "_indirect" suffix
-    static constexpr android::base::StringView suffix("_indirect");
+    std::string suffix("_indirect");
     std::string nameNoSuffix(name);
     int nameNoSuffixLen = (int)nameNoSuffix.size() - (int)suffix.size();
     if (nameNoSuffixLen > 0 &&
         suffix == nameNoSuffix.c_str() + nameNoSuffixLen) {
         nameNoSuffix.erase(nameNoSuffixLen);
     }
-    return android::base::StringFormat(
-            "%s" PATH_SEP "%s" PATH_SEP "gles_%s",
-            mExecDir,
-            mProgramBitness == 64 ? "lib64" : "lib",
-            nameNoSuffix.c_str());
+    return android::base::pj({mExecDir, "lib64", std::string("gles_%s") + nameNoSuffix});
 }
 
 #ifdef _WIN32
@@ -97,17 +77,9 @@
         return false;
     }
 
-    std::string path = android::base::StringFormat(
-            "%s" PATH_SEP "lib%s%s",
-            getLibDirPath(name),
-            libraryName,
-            kLibSuffix);
+    std::string path = android::base::pj({
+            getLibDirPath(name), std::string("lib") + libraryName + kLibSuffix});
 
-    if (!System::get()->pathIsFile(path)) {
-        D("%s(name=%s lib=%s): File does not exist: %s\n",
-          __FUNCTION__, name, libraryName, path.c_str());
-        return false;
-    }
     *libPath = path;
     return true;
 }
diff --git a/host-common/opengl/EmuglBackendScanner.cpp b/host-common/opengl/EmuglBackendScanner.cpp
index 5de9215..0b2acdd 100644
--- a/host-common/opengl/EmuglBackendScanner.cpp
+++ b/host-common/opengl/EmuglBackendScanner.cpp
@@ -9,14 +9,10 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
 
-#include "android/opengl/EmuglBackendScanner.h"
+#include "EmuglBackendScanner.h"
 
-#include "android/base/Log.h"
-#include "android/base/StringFormat.h"
-#include "android/base/system/System.h"
-#include "android/base/misc/StringUtils.h"
-
-#include "android/utils/path.h"
+#include "base/StringFormat.h"
+#include "base/System.h"
 
 #include <algorithm>
 #include <string>
@@ -26,20 +22,21 @@
 namespace opengl {
 
 using android::base::StringFormat;
-using android::base::System;
 
 // static
 std::vector<std::string> EmuglBackendScanner::scanDir(const char* execDir,
                                                       int programBitness) {
     std::vector<std::string> names;
 
-    if (!execDir || !System::get()->pathExists(execDir)) {
-        LOG(ERROR) << "Invalid executable directory: " << execDir;
+    if (!execDir) {
+        fpritnf(stderr, "%s: invalid exec dir: %s\n", __func__, execDir);
         return names;
     }
+
     if (!programBitness) {
         programBitness = System::get()->getProgramBitness();
     }
+
     const char* subdir = (programBitness == 64) ? "lib64" : "lib";
     std::string subDir = StringFormat("%s" PATH_SEP "%s" PATH_SEP, execDir, subdir);
 
diff --git a/host-common/opengl/GLProcessPipe.cpp b/host-common/opengl/GLProcessPipe.cpp
index 63c234f..e263423 100644
--- a/host-common/opengl/GLProcessPipe.cpp
+++ b/host-common/opengl/GLProcessPipe.cpp
@@ -9,13 +9,15 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
 
-#include "android/emulation/AndroidPipe.h"
+#include "../AndroidPipe.h"
 
-#include "android/opengles.h"
+#include "../opengles.h"
 #include <assert.h>
 #include <atomic>
 #include <memory>
 
+#include <string.h>
+
 namespace android {
 namespace opengl {
 
diff --git a/host-common/opengl/GpuFrameBridge.cpp b/host-common/opengl/GpuFrameBridge.cpp
index c6a2702..ea3c0d7 100644
--- a/host-common/opengl/GpuFrameBridge.cpp
+++ b/host-common/opengl/GpuFrameBridge.cpp
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "android/opengl/GpuFrameBridge.h"
+#include "GpuFrameBridge.h"
 
 #include <stdio.h>   // for printf
 #include <stdlib.h>  // for NULL, free, malloc
@@ -21,11 +21,9 @@
 #include <atomic>  // for atomic_bool, memory_o...
 #include <memory>  // for unique_ptr
 
-#include "android/base/async/Looper.h"          // for Looper::Timer, Looper
-#include "android/base/async/ThreadLooper.h"    // for ThreadLooper
-#include "android/base/synchronization/Lock.h"  // for Lock, AutoLock
-#include "android/base/synchronization/MessageChannel.h"
-#include "android/opengles.h"  // for android_getFlushReadP...
+#include "base/Lock.h"  // for Lock, AutoLock
+#include "base/MessageChannel.h"
+#include "..//opengles.h"  // for android_getFlushReadP...
 
 #ifdef _WIN32
 #undef ERROR
@@ -36,7 +34,6 @@
 
 using android::base::AutoLock;
 using android::base::Lock;
-using android::base::Looper;
 using android::base::MessageChannel;
 
 namespace {
@@ -90,20 +87,20 @@
         }
     }
 
-    virtual void setLooper(android::base::Looper* aLooper) override {
-        mTimer = std::unique_ptr<android::base::Looper::Timer>(
-                aLooper->createTimer(_on_frame_notify, this));
-    }
+    // virtual void setLooper(android::base::Looper* aLooper) override {
+    //     mTimer = std::unique_ptr<android::base::Looper::Timer>(
+    //             aLooper->createTimer(_on_frame_notify, this));
+    // }
 
     void notify() {
         AutoLock delay(mDelayLock);
         switch (mDelayCallback) {
             case FrameDelay::Reschedule:
-                mTimer->startRelative(kFrameDelayMs);
+                // mTimer->startRelative(kFrameDelayMs);
                 mDelayCallback = FrameDelay::Scheduled;
                 break;
             case FrameDelay::Scheduled:
-                mTimer->stop();
+                // mTimer->stop();
                 mDelayCallback = FrameDelay::Firing;
                 delay.unlock();
                 mFlushPixelPipeline(mDisplayId);
@@ -113,11 +110,11 @@
         }
     }
 
-    static void _on_frame_notify(void* opaque,
-                                 android::base::Looper::Timer* timer) {
-        Bridge* worker = static_cast<Bridge*>(opaque);
-        worker->notify();
-    }
+    // static void _on_frame_notify(void* opaque,
+    //                              android::base::Looper::Timer* timer) {
+    //     Bridge* worker = static_cast<Bridge*>(opaque);
+    //     worker->notify();
+    // }
 
     // Implementation of the GpuFrameBridge::postRecordFrame() method, must be
     // called from the EmuGL thread.
@@ -196,7 +193,7 @@
             AutoLock delay(mDelayLock);
             switch (mDelayCallback) {
                 case FrameDelay::NotScheduled:
-                    mTimer->startRelative(kFrameDelayMs);
+                    // mTimer->startRelative(kFrameDelayMs);
                     mDelayCallback = FrameDelay::Scheduled;
                     break;
                 case FrameDelay::Firing:
@@ -231,7 +228,7 @@
     uint32_t mDisplayId = 0;
     FlushReadPixelPipeline mFlushPixelPipeline = 0;
 
-    std::unique_ptr<android::base::Looper::Timer> mTimer;
+    // std::unique_ptr<android::base::Looper::Timer> mTimer;
     Lock mDelayLock;
     FrameDelay mDelayCallback{FrameDelay::NotScheduled};
 };
diff --git a/host-common/opengl/GpuFrameBridge.h b/host-common/opengl/GpuFrameBridge.h
index 083004f..03bc1d5 100644
--- a/host-common/opengl/GpuFrameBridge.h
+++ b/host-common/opengl/GpuFrameBridge.h
@@ -15,7 +15,6 @@
 #pragma once
 
 #include <cstdint>
-#include "android/base/async/Looper.h"
 
 class Looper;
 namespace android {
@@ -67,7 +66,7 @@
 
     virtual void setDisplayId(uint32_t displayId) = 0;
 
-    virtual void setLooper(android::base::Looper* aLooper) = 0;
+    // virtual void setLooper(android::base::Looper* aLooper) = 0;
 
 protected:
     GpuFrameBridge() {}
diff --git a/host-common/opengl/NativeGpuInfo.h b/host-common/opengl/NativeGpuInfo.h
index 07753a3..d5b96e0 100644
--- a/host-common/opengl/NativeGpuInfo.h
+++ b/host-common/opengl/NativeGpuInfo.h
@@ -14,7 +14,7 @@
 
 #pragma once
 
-#include "android/opengl/gpuinfo.h"
+#include "gpuinfo.h"
 
 void getGpuInfoListNative(GpuInfoList*);
 
diff --git a/host-common/opengl/NativeGpuInfo_linux.cpp b/host-common/opengl/NativeGpuInfo_linux.cpp
index 98a0154..1641133 100644
--- a/host-common/opengl/NativeGpuInfo_linux.cpp
+++ b/host-common/opengl/NativeGpuInfo_linux.cpp
@@ -12,32 +12,26 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "android/opengl/NativeGpuInfo.h"
+#include "NativeGpuInfo.h"
 
-#include "android/base/StringView.h"
-#include "android/base/files/PathUtils.h"
-#include "android/base/files/ScopedFd.h"
-#include "android/base/memory/ScopedPtr.h"
-#include "android/base/misc/FileUtils.h"
-#include "android/base/system/System.h"
+#include "base/PathUtils.h"
+#include "base/ScopedFd.h"
+#include "base/FileUtils.h"
+#include "base/System.h"
 
 #include <string>
 
-using android::base::makeCustomScopedPtr;
 using android::base::PathUtils;
-using android::base::RunOptions;
 using android::base::ScopedFd;
-using android::base::StringView;
-using android::base::System;
 
 static const int kGPUInfoQueryTimeoutMs = 5000;
 
-static std::string load_gpu_info() {
-    // Execute the command to get GPU info.
-    return System::get()
-            ->runCommandWithResult({"lspci", "-mvnn"}, kGPUInfoQueryTimeoutMs)
-            .valueOr({});
-}
+// static std::string load_gpu_info() {
+//     // Execute the command to get GPU info.
+//     return System::get()
+//             ->runCommandWithResult({"lspci", "-mvnn"}, kGPUInfoQueryTimeoutMs)
+//             .valueOr({});
+// }
 
 static std::string parse_last_hexbrackets(const std::string& str) {
     size_t closebrace_p = str.rfind("]");
@@ -91,6 +85,7 @@
 }
 
 void getGpuInfoListNative(GpuInfoList* gpulist) {
+    (void)gpulist;
     // Load it in a traditional way - by parsing output of external process.
 
     // TODO: Don't do GPU info detection on Linux for now---lspci can be
@@ -98,9 +93,9 @@
 #ifdef ANDROID_DEBUG
     // Workaround for b/77586363, clang -O0 introduces some unexpected behavior
     // when it comes to the else. See the bug for details
-    load_gpu_info();
+    // load_gpu_info();
 #else
-    (void)load_gpu_info; // Make Werror happy
+    // (void)load_gpu_info; // Make Werror happy
 #endif
     // std::string gpu_info = load_gpu_info();
     // parse_gpu_info_list_linux(gpu_info, gpulist);
diff --git a/host-common/opengl/OpenglEsPipe.cpp b/host-common/opengl/OpenglEsPipe.cpp
index dc14907..581972c 100644
--- a/host-common/opengl/OpenglEsPipe.cpp
+++ b/host-common/opengl/OpenglEsPipe.cpp
@@ -8,22 +8,21 @@
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
-#include "android/opengl/OpenglEsPipe.h"
+#include "OpenglEsPipe.h"
 
-#include "android/base/Optional.h"
-#include "android/base/Stopwatch.h"
-#include "android/base/async/Looper.h"
-#include "android/base/files/PathUtils.h"
-#include "android/base/files/StreamSerializing.h"
-#include "android/base/threads/FunctorThread.h"
-#include "android/globals.h"
-#include "android/loadpng.h"
-#include "android/opengl/GLProcessPipe.h"
-#include "android/opengles-pipe.h"
-#include "android/opengles.h"
-#include "android/snapshot/Loader.h"
-#include "android/snapshot/Saver.h"
-#include "android/snapshot/Snapshotter.h"
+#include "base/Optional.h"
+#include "base/PathUtils.h"
+#include "base/StreamSerializing.h"
+#include "base/FunctorThread.h"
+#include "base/System.h"
+#include "../globals.h"
+// #include "loadpng.h"
+#include "GLProcessPipe.h"
+#include "../opengles-pipe.h"
+#include "../opengles.h"
+// #include "snapshot/Loader.h"
+// #include "snapshot/Saver.h"
+// #include "snapshot/Snapshotter.h"
 
 #include <atomic>
 
@@ -51,8 +50,8 @@
 using emugl::RenderChannelPtr;
 using ChannelState = emugl::RenderChannel::State;
 using IoResult = emugl::RenderChannel::IoResult;
-using android::base::Stopwatch;
-using android::snapshot::Snapshotter;
+// using android::base::Stopwatch;
+// using android::snapshot::Snapshotter;
 
 #define OPENGL_SAVE_VERSION 1
 
@@ -88,25 +87,25 @@
         bool canLoad() const override { return true; }
 
         virtual void preLoad(android::base::Stream* stream) override {
-#ifdef SNAPSHOT_PROFILE
-            mLoadMeter.restartUs();
-#endif
-            const bool hasRenderer = stream->getByte();
-            const auto& renderer = android_getOpenglesRenderer();
-            if (hasRenderer != (bool)renderer) {
-                // die?
-                return;
-            }
-            if (!hasRenderer) {
-                return;
-            }
-            int version = stream->getBe32();
-            (void)version;
-            renderer->load(stream, Snapshotter::get().loader().textureLoader());
-#ifdef SNAPSHOT_PROFILE
-            printf("OpenglEs preload time: %lld ms\n",
-                   (long long)(mLoadMeter.elapsedUs() / 1000));
-#endif
+// #ifdef SNAPSHOT_PROFILE
+//             mLoadMeter.restartUs();
+// #endif
+//             const bool hasRenderer = stream->getByte();
+//             const auto& renderer = android_getOpenglesRenderer();
+//             if (hasRenderer != (bool)renderer) {
+//                 // die?
+//                 return;
+//             }
+//             if (!hasRenderer) {
+//                 return;
+//             }
+//             int version = stream->getBe32();
+//             (void)version;
+//             renderer->load(stream, Snapshotter::get().loader().textureLoader());
+// #ifdef SNAPSHOT_PROFILE
+//             printf("OpenglEs preload time: %lld ms\n",
+//                    (long long)(mLoadMeter.elapsedUs() / 1000));
+// #endif
         }
 
         void postLoad(android::base::Stream* stream) override {
@@ -120,20 +119,20 @@
         }
 
         void preSave(android::base::Stream* stream) override {
-#ifdef SNAPSHOT_PROFILE
-            mSaveMeter.restartUs();
-#endif
-            if (const auto& renderer = android_getOpenglesRenderer()) {
-                renderer->pauseAllPreSave();
-                stream->putByte(1);
-                stream->putBe32(OPENGL_SAVE_VERSION);
-                renderer->save(stream,
-                               Snapshotter::get().saver().textureSaver());
-
-                writeScreenshot(*renderer);
-            } else {
-                stream->putByte(0);
-            }
+// #ifdef SNAPSHOT_PROFILE
+//             mSaveMeter.restartUs();
+// #endif
+//             if (const auto& renderer = android_getOpenglesRenderer()) {
+//                 renderer->pauseAllPreSave();
+//                 stream->putByte(1);
+//                 stream->putBe32(OPENGL_SAVE_VERSION);
+//                 renderer->save(stream,
+//                                Snapshotter::get().saver().textureSaver());
+// 
+//                 writeScreenshot(*renderer);
+//             } else {
+//                 stream->putByte(0);
+//             }
         }
 
         void postSave(android::base::Stream* stream) override {
@@ -176,59 +175,59 @@
         }
 
         void writeScreenshot(emugl::Renderer& renderer) {
-#if SNAPSHOT_PROFILE > 1
-            Stopwatch sw;
-#endif
-            if (!mSnapshotCallbackRegistered) {
-                // We have to wait for the screenshot saving thread, but
-                // there's no need to join it too soon: it is ok to only
-                // block when the rest of snapshot saving is complete.
-                Snapshotter::get().addOperationCallback(
-                        [this](Snapshotter::Operation op,
-                               Snapshotter::Stage stage) {
-                            if (op == Snapshotter::Operation::Save &&
-                                stage == Snapshotter::Stage::End) {
-                                if (mScreenshotSaver) {
-                                    mScreenshotSaver->wait();
-                                    mScreenshotSaver.clear();
-                                }
-                            }
-                        });
-                mSnapshotCallbackRegistered = true;
-            }
-            // always do 4 channel screenshot because swiftshader_indirect
-            // has issues with 3 channels
-            const unsigned int nChannels = 4;
-            unsigned int width;
-            unsigned int height;
-            std::vector<unsigned char> pixels;
-            renderer.getScreenshot(nChannels, &width, &height, pixels);
-#if SNAPSHOT_PROFILE > 1
-            printf("Screenshot load texture time %lld ms\n",
-                   (long long)(sw.elapsedUs() / 1000));
-#endif
-            if (width > 0 && height > 0) {
-                std::string dataDir =
-                        Snapshotter::get().saver().snapshot().dataDir();
-                mScreenshotSaver.emplace([nChannels, width, height,
-                                          dataDir = std::move(dataDir),
-                                          pixels = std::move(pixels)] {
-#if SNAPSHOT_PROFILE > 1
-                    Stopwatch sw;
-#endif
-                    std::string fileName = android::base::PathUtils::join(
-                            dataDir, "screenshot.png");
-                    // TODO: fix the screenshot rotation?
-                    savepng(fileName.c_str(), nChannels, width, height,
-                            SKIN_ROTATION_0,
-                            const_cast<unsigned char*>(pixels.data()));
-#if SNAPSHOT_PROFILE > 1
-                    printf("Screenshot image write time %lld ms\n",
-                           (long long)(sw.elapsedUs() / 1000));
-#endif
-                });
-                mScreenshotSaver->start();
-            }
+// #if SNAPSHOT_PROFILE > 1
+//             Stopwatch sw;
+// #endif
+//             if (!mSnapshotCallbackRegistered) {
+//                 // We have to wait for the screenshot saving thread, but
+//                 // there's no need to join it too soon: it is ok to only
+//                 // block when the rest of snapshot saving is complete.
+//                 // Snapshotter::get().addOperationCallback(
+//                 //         [this](Snapshotter::Operation op,
+//                 //                Snapshotter::Stage stage) {
+//                 //             if (op == Snapshotter::Operation::Save &&
+//                 //                 stage == Snapshotter::Stage::End) {
+//                 //                 if (mScreenshotSaver) {
+//                 //                     mScreenshotSaver->wait();
+//                 //                     mScreenshotSaver.clear();
+//                 //                 }
+//                 //             }
+//                 //         });
+//                 mSnapshotCallbackRegistered = true;
+//             }
+//             // always do 4 channel screenshot because swiftshader_indirect
+//             // has issues with 3 channels
+//             const unsigned int nChannels = 4;
+//             unsigned int width;
+//             unsigned int height;
+//             std::vector<unsigned char> pixels;
+//             renderer.getScreenshot(nChannels, &width, &height, pixels);
+// #if SNAPSHOT_PROFILE > 1
+//             printf("Screenshot load texture time %lld ms\n",
+//                    (long long)(sw.elapsedUs() / 1000));
+// #endif
+//             if (width > 0 && height > 0) {
+//                 std::string dataDir =
+//                         Snapshotter::get().saver().snapshot().dataDir();
+//                 mScreenshotSaver.emplace([nChannels, width, height,
+//                                           dataDir = std::move(dataDir),
+//                                           pixels = std::move(pixels)] {
+// #if SNAPSHOT_PROFILE > 1
+//                     Stopwatch sw;
+// #endif
+//                     std::string fileName = android::base::PathUtils::join(
+//                             dataDir, "screenshot.png");
+//                     // TODO: fix the screenshot rotation?
+//                     savepng(fileName.c_str(), nChannels, width, height,
+//                             SKIN_ROTATION_0,
+//                             const_cast<unsigned char*>(pixels.data()));
+// #if SNAPSHOT_PROFILE > 1
+//                     printf("Screenshot image write time %lld ms\n",
+//                            (long long)(sw.elapsedUs() / 1000));
+// #endif
+//                 });
+//                 mScreenshotSaver->start();
+//             }
         }
 
         bool mSnapshotCallbackRegistered = false;
@@ -320,7 +319,7 @@
         int len = 0;
         size_t buffOffset = 0;
 
-        static constexpr android::base::System::Duration kBlockReportIntervalUs = 1000000ULL;
+        static constexpr uint64_t kBlockReportIntervalUs = 1000000ULL;
         auto buff = buffers;
         const auto buffEnd = buff + numBuffers;
         while (buff != buffEnd) {
@@ -369,10 +368,10 @@
                     // the guest block on work that takes a significant
                     // amount of time.
 
-                    static constexpr android::base::System::Duration kBlockReportIntervalUs = 1000000ULL;
+                    static constexpr uint64_t kBlockReportIntervalUs = 1000000ULL;
 
                     const RenderChannel::Duration kBlockAtMostUs = 100;
-                    auto currTime = android::base::System::get()->getUnixTimeUs();
+                    auto currTime = android::base::getUnixTimeUs();
                     auto result = mChannel->readBefore(&mDataForReading, currTime + kBlockAtMostUs);
 
                     if (result != IoResult::Ok) {
@@ -407,14 +406,14 @@
                     // the guest block on work that takes a significant
                     // amount of time.
 
-                    static constexpr android::base::System::Duration kBlockReportIntervalUs = 1000000ULL;
+                    static constexpr uint64_t kBlockReportIntervalUs = 1000000ULL;
 
-                    auto currUs = android::base::System::get()->getHighResTimeUs();
+                    auto currUs = android::base::getHighResTimeUs();
 
                     const RenderChannel::Duration kBlockAtMostUs = 10000;
-                    auto currTime = android::base::System::get()->getUnixTimeUs();
+                    auto currTime = android::base::getUnixTimeUs();
                     auto result = mChannel->readBefore(&mDataForReading, currTime + kBlockAtMostUs);
-                    auto nextUs = android::base::System::get()->getHighResTimeUs();
+                    auto nextUs = android::base::getHighResTimeUs();
 
                     if (result != IoResult::Ok) {
                         DD("%s: tryRead() failed with %d", __func__, (int)result);
diff --git a/host-common/opengl/OpenglEsPipe.h b/host-common/opengl/OpenglEsPipe.h
index 60cc9b9..f5f298a 100644
--- a/host-common/opengl/OpenglEsPipe.h
+++ b/host-common/opengl/OpenglEsPipe.h
@@ -10,10 +10,10 @@
 // GNU General Public License for more details.
 #pragma once
 
-#include "android/base/Compiler.h"
-#include "android/emulation/AndroidPipe.h"
+#include "base/Compiler.h"
+#include "..//AndroidPipe.h"
 
-#include "OpenglRender/RenderChannel.h"
+#include "../../stream-servers/RenderChannel.h"
 
 namespace android {
 namespace opengl {
diff --git a/host-common/opengl/emugl_config.cpp b/host-common/opengl/emugl_config.cpp
index b012e2d..438442f 100644
--- a/host-common/opengl/emugl_config.cpp
+++ b/host-common/opengl/emugl_config.cpp
@@ -9,15 +9,14 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
 
-#include "android/opengl/emugl_config.h"
-#include "android/opengl/gpuinfo.h"
+#include "emugl_config.h"
+#include "gpuinfo.h"
 
-#include "android/base/StringFormat.h"
+#include "base/StringFormat.h"
 #include "base/System.h"
-#include "android/crashreport/crash-handler.h"
-#include "android/globals.h"
-#include "android/opengl/EmuglBackendList.h"
-#include "android/skin/winsys.h"
+#include "../globals.h"
+#include "../misc.h"
+#include "EmuglBackendList.h"
 
 #include <string>
 
@@ -32,28 +31,22 @@
 #if DEBUG
 #define D(...)  printf(__VA_ARGS__)
 #else
-#define D(...)  crashhandler_append_message_format(__VA_ARGS__)
+// #define D(...)  crashhandler_append_message_format(__VA_ARGS__)
+#define D(...)
 #endif
 
-using android::base::RunOptions;
 using android::base::StringFormat;
-using android::base::System;
 using android::opengl::EmuglBackendList;
 
 static EmuglBackendList* sBackendList = NULL;
 
 static void resetBackendList(int bitness) {
     delete sBackendList;
-    if (System::getEnvironmentVariable("ANDROID_EMUGL_FIXED_BACKEND_LIST") == "1") {
-        std::vector<std::string> fixedBackendNames = {
-            "swiftshader_indirect",
-            "angle_indirect",
-        };
-        sBackendList = new EmuglBackendList(64, fixedBackendNames);
-    } else {
-        sBackendList = new EmuglBackendList(
-                System::get()->getLauncherDirectory().c_str(), bitness);
-    }
+    std::vector<std::string> fixedBackendNames = {
+        "swiftshader_indirect",
+        "angle_indirect",
+    };
+    sBackendList = new EmuglBackendList(64, fixedBackendNames);
 }
 
 static bool stringVectorContains(const std::vector<std::string>& list,
@@ -275,7 +268,7 @@
     }
 
     if (!bitness) {
-        bitness = System::get()->getProgramBitness();
+        bitness = 64;
     }
 
     config->bitness = bitness;
@@ -291,22 +284,7 @@
         // 1. NX or Chrome Remote Desktop is detected, or |no_window| is true.
         // 2. The user's host GPU is on the blacklist.
         std::string sessionType;
-        if (System::get()->isRemoteSession(&sessionType)) {
-            D("%s: %s session detected\n", __FUNCTION__, sessionType.c_str());
-            if (!sBackendList->contains("swiftshader")) {
-                config->enabled = false;
-                gpu_mode = "off";
-                snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
-                snprintf(config->status, sizeof(config->status),
-                        "GPU emulation is disabled under %s without Swiftshader",
-                        sessionType.c_str());
-                setCurrentRenderer(gpu_mode);
-                return true;
-            }
-            D("%s: 'swiftshader_indirect' mode auto-selected\n", __FUNCTION__);
-            gpu_mode = "swiftshader_indirect";
-        }
-        else if (!has_auto_no_window && (no_window || (blacklisted && !hasUiPreference))) {
+        if (!has_auto_no_window && (no_window || (blacklisted && !hasUiPreference))) {
             if (stringVectorContains(sBackendList->names(), "swiftshader")) {
                 D("%s: Headless mode or blacklisted GPU driver, "
                   "using Swiftshader backend\n",
@@ -402,13 +380,11 @@
 }
 
 void emuglConfig_setupEnv(const EmuglConfig* config) {
-    System* system = System::get();
-
     if (config->use_host_vulkan) {
-        system->envSet("ANDROID_EMU_VK_ICD", NULL);
+        android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", NULL);
     } else if (sCurrentRenderer == SELECTED_RENDERER_SWIFTSHADER_INDIRECT) {
         // Use Swiftshader vk icd if using swiftshader_indirect
-        system->envSet("ANDROID_EMU_VK_ICD", "swiftshader");
+        android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", "swiftshader");
     }
 
     if (!config->enabled) {
@@ -417,7 +393,7 @@
         // software SDL renderer is being used. This allows one
         // to run with '-gpu off' under NX and Chrome Remote Desktop
         // properly.
-        system->envSet("SDL_RENDER_DRIVER", "software");
+        android::base::setEnvironmentVariable("SDL_RENDER_DRIVER", "software");
         return;
     }
 
@@ -430,7 +406,9 @@
         std::string dir = sBackendList->getLibDirPath(config->backend);
         if (dir.size()) {
             D("Adding to the library search path: %s\n", dir.c_str());
-            system->addLibrarySearchDir(dir);
+            fprintf(stderr, "%s: non-host backends not supported\n", __func__);
+            abort();
+            // android::base::addLibrarySearchDir(dir);
         }
     }
 
@@ -441,7 +419,7 @@
 
     if (!strcmp(config->backend, "angle_indirect")
             || !strcmp(config->backend, "swiftshader_indirect")) {
-        system->envSet("ANDROID_EGL_ON_EGL", "1");
+        android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1");
         return;
     }
 
@@ -456,11 +434,11 @@
     std::string lib;
     if (sBackendList->getBackendLibPath(
             config->backend, EmuglBackendList::LIBRARY_EGL, &lib)) {
-        system->envSet("ANDROID_EGL_LIB", lib);
+        android::base::setEnvironmentVariable("ANDROID_EGL_LIB", lib);
     }
     if (sBackendList->getBackendLibPath(
             config->backend, EmuglBackendList::LIBRARY_GLESv1, &lib)) {
-        system->envSet("ANDROID_GLESv1_LIB", lib);
+        android::base::setEnvironmentVariable("ANDROID_GLESv1_LIB", lib);
     } else if (strcmp(config->backend, "mesa")) {
         fprintf(stderr, "OpenGL backend '%s' without OpenGL ES 1.x library detected. "
                         "Using GLESv2 only.\n",
@@ -471,13 +449,13 @@
 
     if (sBackendList->getBackendLibPath(
             config->backend, EmuglBackendList::LIBRARY_GLESv2, &lib)) {
-        system->envSet("ANDROID_GLESv2_LIB", lib);
+        android::base::setEnvironmentVariable("ANDROID_GLESv2_LIB", lib);
     }
 
     if (!strcmp(config->backend, "mesa")) {
         fprintf(stderr, "WARNING: The Mesa software renderer is deprecated. "
                         "Use Swiftshader (-gpu swiftshader) for software rendering.\n");
-        system->envSet("ANDROID_GL_LIB", "mesa");
-        system->envSet("ANDROID_GL_SOFTWARE_RENDERER", "1");
+        android::base::setEnvironmentVariable("ANDROID_GL_LIB", "mesa");
+        android::base::setEnvironmentVariable("ANDROID_GL_SOFTWARE_RENDERER", "1");
     }
 }
diff --git a/host-common/opengl/gpuinfo.cpp b/host-common/opengl/gpuinfo.cpp
index 2e88ea6..01f0702 100644
--- a/host-common/opengl/gpuinfo.cpp
+++ b/host-common/opengl/gpuinfo.cpp
@@ -9,14 +9,13 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
 
-#include "android/opengl/gpuinfo.h"
+#include "gpuinfo.h"
 
-#include "android/base/ArraySize.h"
-#include "android/base/memory/LazyInstance.h"
-#include "android/base/system/System.h"
-#include "android/base/threads/FunctorThread.h"
-#include "android/opengl/gpuinfo.h"
-#include "android/opengl/NativeGpuInfo.h"
+#include "base/ArraySize.h"
+#include "base/System.h"
+#include "base/FunctorThread.h"
+#include "gpuinfo.h"
+#include "NativeGpuInfo.h"
 
 #include <assert.h>
 #include <inttypes.h>
@@ -28,8 +27,6 @@
 
 using android::base::arraySize;
 using android::base::FunctorThread;
-using android::base::LazyInstance;
-using android::base::System;
 
 // Try to switch to NVIDIA on Optimus systems,
 // and AMD GPU on AmdPowerXpress.
@@ -52,8 +49,8 @@
 
 #undef FLAG_EXPORT
 
-static const System::Duration kGPUInfoQueryTimeoutMs = 5000;
-static const System::Duration kQueryCheckIntervalMs = 66;
+static const uint64_t kGPUInfoQueryTimeoutMs = 5000;
+static const uint64_t kQueryCheckIntervalMs = 66;
 
 void GpuInfo::addDll(std::string dll_str) {
     dlls.push_back(std::move(dll_str));
@@ -391,14 +388,17 @@
 
 }  // namespace
 
-static LazyInstance<Globals> sGlobals = LAZY_INSTANCE_INIT;
+static Globals* sGlobals() {
+    static Globals* g = new Globals;
+    return g;
+}
 
 void async_query_host_gpu_start() {
-    sGlobals.get();
+    sGlobals();
 }
 
 const GpuInfoList& globalGpuInfoList() {
-    return sGlobals->gpuInfoList();
+    return sGlobals()->gpuInfoList();
 }
 
 bool async_query_host_gpu_blacklisted() {
diff --git a/host-common/opengl/gpuinfo.h b/host-common/opengl/gpuinfo.h
index a73d689..30f784d 100644
--- a/host-common/opengl/gpuinfo.h
+++ b/host-common/opengl/gpuinfo.h
@@ -10,7 +10,7 @@
 // GNU General Public License for more details.
 #pragma once
 
-#include "android/base/Compiler.h"
+#include "base/Compiler.h"
 
 #include <stdbool.h>
 #include <stdio.h>
diff --git a/host-common/opengl/logger.cpp b/host-common/opengl/logger.cpp
index 593e87d..9f42df6 100644
--- a/host-common/opengl/logger.cpp
+++ b/host-common/opengl/logger.cpp
@@ -9,12 +9,10 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
 
-#include "android/opengl/logger.h"
+#include "logger.h"
 
-#include "android/base/files/PathUtils.h"
-#include "android/base/memory/LazyInstance.h"
-#include "android/base/synchronization/Lock.h"
-#include "android/crashreport/CrashReporter.h"
+#include "base/PathUtils.h"
+#include "base/Lock.h"
 
 #include <algorithm>
 #include <fstream>
@@ -30,7 +28,6 @@
 using android::base::AutoLock;
 using android::base::Lock;
 using android::base::PathUtils;
-using android::crashreport::CrashReporter;
 
 // The purpose of the OpenGL logger is to log
 // information about such things as EGL initialization
@@ -79,25 +76,28 @@
     DISALLOW_COPY_ASSIGN_AND_MOVE(OpenGLLogger);
 };
 
-::android::base::LazyInstance<OpenGLLogger> sOpenGLLogger = LAZY_INSTANCE_INIT;
+static OpenGLLogger* sOpenGLLogger() {
+    static OpenGLLogger* g = new OpenGLLogger;
+    return g;
+}
 
 OpenGLLogger* OpenGLLogger::get() {
-    return sOpenGLLogger.ptr();
+    return sOpenGLLogger();
 }
 
 OpenGLLogger::OpenGLLogger() {
-#ifdef AEMU_MIN
+// #ifdef AEMU_MIN
     return;
-#else
-    const std::string& data_dir =
-        CrashReporter::get()->getDataExchangeDir();
-    mFileName = PathUtils::join(data_dir,
-                                "opengl_log.txt");
-    mFileHandle.open(mFileName, std::ios::app);
-    mFineLogFileName = PathUtils::join(data_dir,
-                                       "opengl_cxt_log.txt");
-    mFineLogFileHandle.open(mFineLogFileName, std::ios::app);
-#endif
+// #else
+//     const std::string& data_dir =
+//         CrashReporter::get()->getDataExchangeDir();
+//     mFileName = PathUtils::join(data_dir,
+//                                 "opengl_log.txt");
+//     mFileHandle.open(mFileName, std::ios::app);
+//     mFineLogFileName = PathUtils::join(data_dir,
+//                                        "opengl_cxt_log.txt");
+//     mFineLogFileHandle.open(mFineLogFileName, std::ios::app);
+// #endif
 }
 
 OpenGLLogger::OpenGLLogger(const char* filename) :
diff --git a/host-common/opengl/logger.h b/host-common/opengl/logger.h
index c6334ac..85b3292 100644
--- a/host-common/opengl/logger.h
+++ b/host-common/opengl/logger.h
@@ -11,10 +11,6 @@
 
 #pragma once
 
-#include "android/utils/compiler.h"
-
-ANDROID_BEGIN_HEADER
-
 // The purpose of the OpenGL logger is to log
 // information about such things as EGL initialization
 // and possibly miscellanous OpenGL commands,
@@ -44,5 +40,3 @@
 // contexts (cxts). Only called when emugl is compiled
 // with -DOPENGL_DEBUG_PRINTOUT.
 void android_opengl_cxt_logger_write(const char* fmt, ...);
-
-ANDROID_END_HEADER
diff --git a/host-common/opengles.cpp b/host-common/opengles.cpp
index bc50873..5ba3744 100644
--- a/host-common/opengles.cpp
+++ b/host-common/opengles.cpp
@@ -10,57 +10,54 @@
 ** GNU General Public License for more details.
 */
 
-#include "android/opengles.h"
+#include "opengles.h"
 
-#include "android/base/CpuUsage.h"
-#include "android/base/GLObjectCounter.h"
-#include "android/base/files/PathUtils.h"
-#include "android/base/files/Stream.h"
-#include "android/base/memory/MemoryTracker.h"
-#include "android/base/system/System.h"
-#include "android/crashreport/crash-handler.h"
-#include "android/emulation/address_space_device.h"
-#include "android/emulation/address_space_graphics.h"
-#include "android/emulation/address_space_graphics_types.h"
-#include "android/emulation/GoldfishDma.h"
-#include "android/emulation/RefcountPipe.h"
-#include "android/featurecontrol/FeatureControl.h"
-#include "android/globals.h"
-#include "android/opengl/emugl_config.h"
-#include "android/opengl/logger.h"
-#include "android/snapshot/PathUtils.h"
-#include "android/snapshot/Snapshotter.h"
-#include "android/utils/bufprint.h"
-#include "android/utils/debug.h"
-#include "android/utils/dll.h"
-#include "android/utils/path.h"
-#include "config-host.h"
+#include "base/GLObjectCounter.h"
+#include "base/PathUtils.h"
+#include "base/Stream.h"
+#include "base/MemoryTracker.h"
+#include "base/SharedLibrary.h"
+#include "base/System.h"
+#include "host-common/address_space_device.h"
+#include "host-common/address_space_graphics.h"
+#include "host-common/address_space_graphics_types.h"
+#include "host-common/GoldfishDma.h"
+#include "host-common/RefcountPipe.h"
+#include "host-common/FeatureControl.h"
+#include "host-common/globals.h"
+#include "host-common/opengl/emugl_config.h"
+#include "host-common/opengl/logger.h"
+#include "host-common/opengl/gpuinfo.h"
 
-#include "OpenglRender/render_api_functions.h"
-#include "OpenGLESDispatch/EGLDispatch.h"
-#include "OpenGLESDispatch/GLESv2Dispatch.h"
+#include "../stream-servers/render_api_functions.h"
+#include "../stream-servers/OpenGLESDispatch/EGLDispatch.h"
+#include "../stream-servers/OpenGLESDispatch/GLESv2Dispatch.h"
 
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#define D(...) do { \
-    VERBOSE_PRINT(init,__VA_ARGS__); \
-    android_opengl_logger_write(__VA_ARGS__); \
-} while(0);
+#define D(...)
+#define DD(...)
+#define E(...)
 
-#define DD(...) do { \
-    VERBOSE_PRINT(gles,__VA_ARGS__); \
-    android_opengl_logger_write(__VA_ARGS__); \
-} while(0);
-
-#define E(fmt,...) do { \
-    derror(fmt, ##__VA_ARGS__); \
-    android_opengl_logger_write(fmt "\n", ##__VA_ARGS__); \
-} while(0);
+// #define D(...) do { \
+//     VERBOSE_PRINT(init,__VA_ARGS__); \
+//     android_opengl_logger_write(__VA_ARGS__); \
+// } while(0);
+// 
+// #define DD(...) do { \
+//     VERBOSE_PRINT(gles,__VA_ARGS__); \
+//     android_opengl_logger_write(__VA_ARGS__); \
+// } while(0);
+// 
+// #define E(fmt,...) do { \
+//     derror(fmt, ##__VA_ARGS__); \
+//     android_opengl_logger_write(fmt "\n", ##__VA_ARGS__); \
+// } while(0);
 
 using android::base::pj;
-using android::base::System;
+using android::base::SharedLibrary;
 using android::emulation::asg::AddressSpaceGraphicsContext;
 using android::emulation::asg::ConsumerInterface;
 using android::emulation::asg::ConsumerCallbacks;
@@ -77,42 +74,20 @@
 LIST_RENDER_API_FUNCTIONS(FUNCTION_)
 #undef FUNCTION_
 
-// Define a function that initializes the function pointers by looking up
-// the symbols from the shared library.
-static int initOpenglesEmulationFuncs(ADynamicLibrary* rendererLib) {
-    void*  symbol;
-    char*  error;
-
-#define FUNCTION_(ret, name, sig, params) \
-    symbol = adynamicLibrary_findSymbol(rendererLib, #name, &error); \
-    if (symbol != NULL) { \
-        using type = ret(sig); \
-        name = (type*)symbol; \
-    } else { \
-        E("GLES emulation: Could not find required symbol (%s): %s", #name, error); \
-        free(error); \
-        return -1; \
-    }
-    LIST_RENDER_API_FUNCTIONS(FUNCTION_)
-#undef FUNCTION_
-
-    return 0;
-}
-
 static bool sOpenglLoggerInitialized = false;
 static bool sRendererUsesSubWindow = false;
 static bool sEgl2egl = false;
-static emugl::RenderLibPtr sRenderLib = nullptr;
+static emugl::RenderLib* sRenderLib = nullptr;
 static emugl::RendererPtr sRenderer = nullptr;
 
 static const EGLDispatch* sEgl = nullptr;
 static const GLESv2Dispatch* sGlesv2 = nullptr;
 
-int android_initOpenglesEmulation() {
+int android_prepareOpenglesEmulation() {
     android_init_opengl_logger();
 
-    bool glFineLogging = System::get()->envGet("ANDROID_EMUGL_FINE_LOG") == "1";
-    bool glLogPrinting = System::get()->envGet("ANDROID_EMUGL_LOG_PRINT") == "1";
+    bool glFineLogging = android::base::getEnvironmentVariable("ANDROID_EMUGL_FINE_LOG") == "1";
+    bool glLogPrinting = android::base::getEnvironmentVariable("ANDROID_EMUGL_LOG_PRINT") == "1";
 
     AndroidOpenglLoggerFlags loggerFlags =
         static_cast<AndroidOpenglLoggerFlags>(
@@ -122,74 +97,95 @@
     android_opengl_logger_set_flags(loggerFlags);
 
     sOpenglLoggerInitialized = true;
-
-    char* error = NULL;
-
-    if (sRenderLib != NULL)
-        return 0;
-
-    D("Initializing hardware OpenGLES emulation support");
-
-    ADynamicLibrary* rendererSo =
-            adynamicLibrary_open(RENDERER_LIB_NAME, &error);
-    if (rendererSo == NULL) {
-        E("Could not load OpenGLES emulation library [%s]: %s",
-               RENDERER_LIB_NAME, error);
-
-        E("Retrying in program directory/lib64...");
-
-        auto progDir = System::get()->getProgramDirectory();
-
-        auto retryLibPath =
-            pj(progDir, "lib64", RENDERER_LIB_NAME);
-
-        rendererSo = adynamicLibrary_open(retryLibPath.c_str(), &error);
-
-        if (rendererSo == nullptr) {
-            E("Could not load OpenGLES emulation library [%s]: %s (2nd try)",
-                   retryLibPath.c_str(), error);
-            return -1;
-        }
-    }
-
-    /* Resolve the functions */
-    if (initOpenglesEmulationFuncs(rendererSo) < 0) {
-        E("OpenGLES emulation library mismatch. Be sure to use the correct version!");
-        crashhandler_append_message_format(
-            "OpenGLES emulation library mismatch. Be sure to use the correct version!");
-        goto BAD_EXIT;
-    }
-
-    sRenderLib = initLibrary();
-    if (!sRenderLib) {
-        E("OpenGLES initialization failed!");
-        crashhandler_append_message_format("OpenGLES initialization failed!");
-        goto BAD_EXIT;
-    }
-
     sRendererUsesSubWindow = true;
-    if (const char* env = getenv("ANDROID_GL_SOFTWARE_RENDERER")) {
-        if (env[0] != '\0' && env[0] != '0') {
-            sRendererUsesSubWindow = false;
-        }
-    }
 
     sEgl2egl = false;
-    if (const char* env = getenv("ANDROID_EGL_ON_EGL")) {
-        if (env[0] != '\0' && env[0] == '1') {
-            sEgl2egl = true;
-        }
+    if (android::base::getEnvironmentVariable("ANDROID_EGL_ON_EGL") == "1") {
+        sEgl2egl = true;
     }
 
-    sEgl = (const EGLDispatch *)sRenderLib->getEGLDispatch();
-    sGlesv2 = (const GLESv2Dispatch *)sRenderLib->getGLESv2Dispatch();
-
     return 0;
+}
+// 
+//     char* error = NULL;
+// 
+//     if (sRenderLib != NULL)
+//         return 0;
+// 
+//     D("Initializing hardware OpenGLES emulation support");
+// 
+//     SharedLibrary* rendererSo =
+//         SharedLibrary::open(RENDERER_LIB_NAME);
+//     if (rendererSo == NULL) {
+//         E("Could not load OpenGLES emulation library [%s]: %s",
+//                RENDERER_LIB_NAME, error);
+// 
+//         E("Retrying in program directory/lib64...");
+// 
+//         auto progDir = System::get()->getProgramDirectory();
+// 
+//         auto retryLibPath =
+//             pj(progDir, "lib64", RENDERER_LIB_NAME);
+// 
+//         rendererSo = adynamicLibrary_open(retryLibPath.c_str(), &error);
+// 
+//         if (rendererSo == nullptr) {
+//             E("Could not load OpenGLES emulation library [%s]: %s (2nd try)",
+//                    retryLibPath.c_str(), error);
+//             return -1;
+//         }
+//     }
+// 
+//     /* Resolve the functions */
+//     if (initOpenglesEmulationFuncs(rendererSo) < 0) {
+//         E("OpenGLES emulation library mismatch. Be sure to use the correct version!");
+//         crashhandler_append_message_format(
+//             "OpenGLES emulation library mismatch. Be sure to use the correct version!");
+//         goto BAD_EXIT;
+//     }
+// 
+//     sRenderLib = initLibrary();
+//     if (!sRenderLib) {
+//         E("OpenGLES initialization failed!");
+//         crashhandler_append_message_format("OpenGLES initialization failed!");
+//         goto BAD_EXIT;
+//     }
+// 
+//     sRendererUsesSubWindow = true;
+//     if (const char* env = getenv("ANDROID_GL_SOFTWARE_RENDERER")) {
+//         if (env[0] != '\0' && env[0] != '0') {
+//             sRendererUsesSubWindow = false;
+//         }
+//     }
+// 
+//     sEgl2egl = false;
+//     if (const char* env = getenv("ANDROID_EGL_ON_EGL")) {
+//         if (env[0] != '\0' && env[0] == '1') {
+//             sEgl2egl = true;
+//         }
+//     }
+// 
+//     sEgl = (const EGLDispatch *)sRenderLib->getEGLDispatch();
+//     sGlesv2 = (const GLESv2Dispatch *)sRenderLib->getGLESv2Dispatch();
+// 
+//     return 0;
+// 
+// BAD_EXIT:
+//     E("OpenGLES emulation library could not be initialized!");
+//     adynamicLibrary_close(rendererSo);
+//     return -1;
+//
 
-BAD_EXIT:
-    E("OpenGLES emulation library could not be initialized!");
-    adynamicLibrary_close(rendererSo);
-    return -1;
+int android_setOpenglesEmulation(void* renderLib, void* eglDispatch, void* glesv2Dispatch) {
+    sRenderLib = (emugl::RenderLib*)renderLib;
+    sEgl = (EGLDispatch*)eglDispatch;
+    sGlesv2 = (GLESv2Dispatch*)glesv2Dispatch;
+    return 0;
+}
+
+int android_initOpenglesEmulation() {
+    fprintf(stderr, "%s: Not meant to call android_initOpenglesEmulation in the new build\n", __func__);
+    abort();
 }
 
 int
@@ -226,7 +222,7 @@
 
     sRenderLib->setRenderer(emuglConfig_get_current_renderer());
     sRenderLib->setAvdInfo(guestPhoneApi, guestApiLevel);
-    sRenderLib->setCrashReporter(&crashhandler_die_format);
+    // sRenderLib->setCrashReporter(&crashhandler_die_format);
     sRenderLib->setFeatureController(&android::featurecontrol::isEnabled);
     sRenderLib->setSyncDevice(goldfish_sync_create_timeline,
             goldfish_sync_create_fence,
@@ -247,16 +243,16 @@
     sRenderLib->setVmOps(*vm_operations);
     sRenderLib->setAddressSpaceDeviceControlOps(get_address_space_device_control_ops());
     sRenderLib->setWindowOps(*window_agent, *multi_display_agent);
-    sRenderLib->setUsageTracker(android::base::CpuUsage::get(),
-                                android::base::MemoryTracker::get());
+    // sRenderLib->setUsageTracker(android::base::CpuUsage::get(),
+    //                             android::base::MemoryTracker::get());
 
     sRenderer = sRenderLib->initRenderer(width, height, sRendererUsesSubWindow, sEgl2egl);
 
-    android::snapshot::Snapshotter::get().addOperationCallback(
-            [](android::snapshot::Snapshotter::Operation op,
-               android::snapshot::Snapshotter::Stage stage) {
-                sRenderer->snapshotOperationCallback(op, stage);
-            });
+    // android::snapshot::Snapshotter::get().addOperationCallback(
+    //         [](android::snapshot::Snapshotter::Operation op,
+    //            android::snapshot::Snapshotter::Stage stage) {
+    //             sRenderer->snapshotOperationCallback(op, stage);
+    //         });
 
     android::emulation::registerOnLastRefCallback(
             sRenderLib->getOnLastColorBufferRef());
diff --git a/host-common/opengles.h b/host-common/opengles.h
index 33af88e..764fc32 100644
--- a/host-common/opengles.h
+++ b/host-common/opengles.h
@@ -19,6 +19,12 @@
 #include "host-common/vm_operations.h"
 #include "host-common/window_agent.h"
 #include "host-common/opengl/virtio_gpu_ops.h"
+#include "../stream-servers/RenderLib.h"
+
+/* A version of android_initOpenglesEmulation that is called from a library
+ * that has static access to libOpenglRender. */
+AEMU_EXPORT int android_prepareOpenglesEmulation(void);
+AEMU_EXPORT int android_setOpenglesEmulation(void* renderLib, void* eglDispatch, void* glesv2Dispatch);
 
 /* Call this function to initialize the hardware opengles emulation.
  * This function will abort if we can't find the corresponding host
@@ -127,7 +133,7 @@
     class Renderer;
 }
 
-AEMU_EXPORT const emugl::Renderer* android_getOpenglesRenderer();
+AEMU_EXPORT const emugl::RendererPtr& android_getOpenglesRenderer();
 
 AEMU_EXPORT struct AndroidVirtioGpuOps* android_getVirtioGpuOps(void);
 
diff --git a/stream-servers/GfxStreamBackend.cpp b/stream-servers/GfxStreamBackend.cpp
index 71dd73c..4dc32f6 100644
--- a/stream-servers/GfxStreamBackend.cpp
+++ b/stream-servers/GfxStreamBackend.cpp
@@ -38,6 +38,7 @@
 
 #include "VulkanDispatch.h"
 #include "GfxStreamAgents.h"
+#include "render_api.h"
 
 #define GFXSTREAM_DEBUG_LEVEL 1
 
@@ -423,7 +424,16 @@
 
     emuglConfig_setupEnv(&config);
 
-    android_initOpenglesEmulation();
+    android_prepareOpenglesEmulation();
+
+    {
+        static emugl::RenderLibPtr renderLibPtr = initLibrary();
+        void* egldispatch = renderLibPtr->getEGLDispatch();
+        void* glesv2Dispatch = renderLibPtr->getGLESv2Dispatch();
+        android_setOpenglesEmulation(
+                renderLibPtr.get(), egldispatch, glesv2Dispatch);
+    }
+
     int maj;
     int min;
     android_startOpenglesRenderer(
diff --git a/stream-servers/render_api.h b/stream-servers/render_api.h
index f8e2009..de0561f 100644
--- a/stream-servers/render_api.h
+++ b/stream-servers/render_api.h
@@ -32,3 +32,5 @@
     RENDER_APICALL return_type RENDER_APIENTRY func_name signature;
 
 LIST_RENDER_API_FUNCTIONS(RENDER_API_DECLARE)
+
+RENDER_APICALL emugl::RenderLibPtr RENDER_APIENTRY initLibrary();