Rework AvdInfo processing.

This patch changes the code in android/avd/info.c to prepare
for future patches that will move initialization disk images
to the core (including locking and creating temporary files).

+ Remove AvdInfo structure dependencies on many of the
  functions, to make them more generic/usable.

+ Remove skin-related processing from avdInfo_new() and
  avdInfo_newFromBuild().

+ Remove avdInfo_getSkinName() and avdInfo_getSkinDir(), and
  replace them with a single avdInfo_getSkinInfo().

+ Rename 'qemu-hardware.ini' to 'hardware-qemu.ini' to follow
  the same naming convention than the one used for disk
  images (e.g. "userdata-qemu.img" and "system-qemu.img")

Change-Id: I32cb0a5850f8c0b9df93d2630552941fd2b461c1
diff --git a/android/avd/info.c b/android/avd/info.c
index 81d848d..5f110d3 100644
--- a/android/avd/info.c
+++ b/android/avd/info.c
@@ -84,6 +84,11 @@
  */
 #define  SKIN_PATH       "skin.path"
 
+/* the config.ini key that will be used to indicate the default skin's name.
+ * this is ignored if there is a valid SKIN_PATH entry in the file.
+ */
+#define  SKIN_NAME       "skin.name"
+
 /* default skin name */
 #define  SKIN_DEFAULT    "HVGA"
 
@@ -97,7 +102,7 @@
  * properties for the AVD. This will be used to launch the corresponding
  * core from the UI.
  */
-#define  CORE_HARDWARE_INI   "qemu-hardware.ini"
+#define  CORE_HARDWARE_INI   "hardware-qemu.ini"
 
 /* certain disk image files are mounted read/write by the emulator
  * to ensure that several emulators referencing the same files
@@ -139,8 +144,8 @@
     char*     searchPaths[ MAX_SEARCH_PATHS ];
     int       numSearchPaths;
     char*     contentPath;
-    IniFile*  rootIni;      /* root <foo>.ini file */
-    IniFile*  configIni;    /* virtual device's config.ini */
+    IniFile*  rootIni;      /* root <foo>.ini file, empty if missing */
+    IniFile*  configIni;    /* virtual device's config.ini, NULL if missing */
     IniFile*  skinHardwareIni;  /* skin-specific hardware.ini */
 
     /* for both */
@@ -217,80 +222,99 @@
 /***************************************************************
  ***************************************************************
  *****
- *****    NORMAL VIRTUAL DEVICE SUPPORT
+ *****    UTILITY FUNCTIONS
+ *****
+ *****  The following functions do not depend on the AvdInfo
+ *****  structure and could easily be moved elsewhere.
  *****
  *****/
 
-/* compute path to the root SDK directory
- * assume we are in $SDKROOT/tools/emulator[.exe]
+/* Return the path to the Android SDK root installation.
+ *
+ * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT
+ * environment variable, or 0 otherwise.
+ *
+ * Caller must free() returned string.
  */
-static int
-_getSdkRoot( AvdInfo*  i )
+static char*
+_getSdkRoot( char *pFromEnv )
 {
     const char*  env;
+    char*        sdkPath;
     char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
 
+    /* If ANDROID_SDK_ROOT is defined is must point to a directory
+     * containing a valid SDK installation.
+     */
 #define  SDK_ROOT_ENV  "ANDROID_SDK_ROOT"
 
     env = getenv(SDK_ROOT_ENV);
     if (env != NULL && env[0] != 0) {
         if (path_exists(env)) {
             D("found " SDK_ROOT_ENV ": %s", env);
-            i->sdkRootPath = ASTRDUP(env);
-            i->sdkRootPathFromEnv = 1;
-            return 0;
+            *pFromEnv = 1;
+            return ASTRDUP(env);
         }
         D(SDK_ROOT_ENV " points to unknown directory: %s", env);
     }
 
-    (void) bufprint_app_dir(temp, end);
+    *pFromEnv = 0;
 
-    i->sdkRootPath = path_parent(temp, 1);
-    if (i->sdkRootPath == NULL) {
+    /* We assume the emulator binary is under tools/ so use its
+     * parent as the Android SDK root.
+     */
+    (void) bufprint_app_dir(temp, end);
+    sdkPath = path_parent(temp, 1);
+    if (sdkPath == NULL) {
         derror("can't find root of SDK directory");
-        return -1;
+        return NULL;
     }
-    D("found SDK root at %s", i->sdkRootPath);
-    return 0;
+    D("found SDK root at %s", sdkPath);
+    return sdkPath;
 }
 
-static void
-_getSearchPaths( AvdInfo*  i )
+/* 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( IniFile*    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 < MAX_SEARCH_PATHS; nn++) {
+    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( i->configIni, temp, NULL );
+        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/%s", i->sdkRootPath, path);
+                p = bufprint(temp, end, "%s/%s", sdkRootPath, path);
                 AFREE(path);
                 path = ASTRDUP(temp);
             }
-            i->searchPaths[count++] = path;
+            searchPaths[count++] = path;
         }
     }
-
-    i->numSearchPaths = count;
-    if (count == 0) {
-        derror("no search paths found in this AVD's configuration.\n"
-               "Weird, the AVD's config.ini file is malformed. Try re-creating it.\n");
-        exit(2);
-    }
-    else
-        DD("found a total of %d search paths for this AVD", count);
+    return count;
 }
 
+/* Check that an AVD name is valid. Returns 1 on success, 0 otherwise.
+ */
 static int
 _checkAvdName( const char*  name )
 {
@@ -301,37 +325,299 @@
     return (len == len2);
 }
 
+/* Return the path to the AVD's root configuration .ini file. it is located in
+ * ~/.android/avd/<name>.ini or Windows equivalent
+ *
+ * This file contains the path to the AVD's content directory, which
+ * includes its own config.ini.
+ */
+static char*
+_getRootIniPath( const char*  avdName )
+{
+    char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+    p = bufprint_config_path(temp, end);
+    p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", avdName);
+    if (p >= end) {
+        return NULL;
+    }
+    if (!path_exists(temp)) {
+        return NULL;
+    }
+    return ASTRDUP(temp);
+}
+
+
+/* Retrieves a string corresponding to the target architecture
+ * when in the Android platform tree. The only way to do that
+ * properly for now is to look at $OUT/system/build.prop:
+ *
+ *   ro.product.cpu-abi=<abi>
+ *
+ * Where <abi> can be 'armeabi', 'armeabi-v7a' or 'x86'.
+ */
+static const char*
+_getBuildTargetArch( const char* androidOut )
+{
+    const char* arch = "arm";
+    char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+    FILE*  file;
+
+#define ABI_PREFIX       "ro.product.cpu.abi="
+#define ABI_PREFIX_LEN   (sizeof(ABI_PREFIX)-1)
+
+    p = bufprint(temp, end, "%s/system/build.prop", androidOut);
+    if (p >= end) {
+        D("%s: ANDROID_PRODUCT_OUT too long: %s", __FUNCTION__, androidOut);
+        goto EXIT;
+    }
+    file = fopen(temp, "rb");
+    if (file == NULL) {
+        D("Could not open file: %s: %s", temp, strerror(errno));
+        D("Default target architecture=%s", arch);
+        goto EXIT;
+    }
+
+    while (fgets(temp, sizeof temp, file) != NULL) {
+        /* Trim trailing newlines, if any */
+        p = memchr(temp, '\0', sizeof temp);
+        if (p == NULL)
+            p = end;
+        if (p > temp && p[-1] == '\n') {
+            *--p = '\0';
+        }
+        if (p > temp && p[-1] == '\r') {
+            *--p = '\0';
+        }
+        /* force zero-termination in case of full-buffer */
+        if (p == end)
+            *--p = '\0';
+
+        if (memcmp(temp, ABI_PREFIX, ABI_PREFIX_LEN) != 0) {
+            continue;
+        }
+        p = temp + ABI_PREFIX_LEN;
+        if (p >= end || !*p)
+            goto EXIT2;
+
+        if (!strcmp("armeabi",p))
+            arch = "arm";
+        else if (!strcmp("armeabi-v7a",p))
+            arch = "arm";
+        else
+            arch = p;
+
+        D("Found target ABI=%s, architecture=%s", p, arch);
+        goto EXIT2;
+    }
+
+    D("Could not find target architecture, defaulting to %s", arch);
+EXIT2:
+    fclose(file);
+EXIT:
+    return arch;
+}
+
+/* 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/%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/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/skins/%s", skinDirRoot, skinName);
+    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/skins/%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/%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);
+        exit(2);
+    }
+    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 = _getSdkRoot(&i->sdkRootPathFromEnv);
+    if (i->sdkRootPath == NULL)
+        return -1;
+
+    return 0;
+}
+
 /* parse the root config .ini file. it is located in
  * ~/.android/avd/<name>.ini or Windows equivalent
  */
 static int
-_getRootIni( AvdInfo*  i )
+_avdInfo_getRootIni( AvdInfo*  i )
 {
-    char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+    char*  iniPath = _getRootIniPath( i->deviceName );
 
-    p = bufprint_config_path(temp, end);
-    p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", i->deviceName);
-    if (p >= end) {
-        derror("device name too long");
-        return -1;
-    }
-
-    i->rootIni = iniFile_newFromFile(temp);
-    if (i->rootIni == NULL) {
+    if (iniPath == NULL) {
         derror("unknown virtual device name: '%s'", i->deviceName);
         return -1;
     }
-    D("root virtual device file at %s", temp);
+
+    D("Android virtual device file at: %s", iniPath);
+
+    i->rootIni = iniFile_newFromFile(iniPath);
+    AFREE(iniPath);
+
+    if (i->rootIni == NULL) {
+        derror("Corrupt virtual device config file!");
+        return -1;
+    }
     return 0;
 }
 
-/* the .ini variable name that points to the content directory
- * in a root AVD ini file. This is required */
+/* 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 )
+{
 #   define  ROOT_PATH_KEY    "path"
 
-static int
-_getContentPath( AvdInfo*  i )
-{
     i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY, NULL);
 
     if (i->contentPath == NULL) {
@@ -343,36 +629,157 @@
     return 0;
 }
 
-/* find and parse the config.ini file from the content directory */
-static int
-_getConfigIni(AvdInfo*  i)
+/* 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(AvdInfo*  i, const char* fileName)
 {
-    char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+    char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
 
-    p = bufprint(p, end, "%s/config.ini", i->contentPath);
+    p = bufprint(p, end, "%s/%s", i->contentPath, fileName);
     if (p >= end) {
         derror("can't access virtual device content directory");
-        return -1;
+        return NULL;
     }
-
-#if 1   /* XXX: TODO: remove this in the future */
-    /* for now, allow a non-existing config.ini */
     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, "config.ini");
+
+    /* Allow non-existing config.ini */
+    if (iniPath == NULL) {
         D("virtual device has no config file - no problem");
         return 0;
     }
-#endif
 
-    i->configIni = iniFile_newFromFile(temp);
+    D("virtual device config file: %s", iniPath);
+    i->configIni = iniFile_newFromFile(iniPath);
+    AFREE(iniPath);
+
     if (i->configIni == NULL) {
         derror("bad config: %s",
-               "virtual device directory lacks config.ini");
+               "virtual device has corrupted config.ini");
         return -1;
     }
-    D("virtual device config file: %s", temp);
     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 void
+_avdInfo_getSearchPaths( AvdInfo*  i )
+{
+    if (i->configIni == NULL)
+        return;
+
+    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 config.ini file is malformed. Try re-creating it.\n");
+        exit(2);
+    }
+    else
+        DD("found a total of %d search paths for this AVD", i->numSearchPaths);
+}
+
+/* Search a file in the SDK search directories. Return NULL if not found,
+ * or a strdup() otherwise.
+ */
+static char*
+_avdInfo_getSdkFilePath(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/%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(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(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;
+}
+
+
 /***************************************************************
  ***************************************************************
  *****
@@ -720,7 +1127,7 @@
  * and lock the files that need it.
  */
 static int
-_getImagePaths(AvdInfo*  i, AvdInfoParams*  params )
+_avdInfo_getImagePaths(AvdInfo*  i, AvdInfoParams*  params )
 {
     int   wipeData    = (params->flags & AVDINFO_WIPE_DATA) != 0;
     int   wipeCache   = (params->flags & AVDINFO_WIPE_CACHE) != 0;
@@ -826,260 +1233,12 @@
     return 0;
 }
 
-/* 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/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 1 on success, 0 on failure
- * on success, the 'temp' buffer will get the path containing the real
- * skin directory (after alias expansion), including the skin name.
- */
-static int
-_checkSkinDir( char*        temp,
-               char*        end,
-               const char*  skinDirRoot,
-               const char*  skinName )
-{
-    DirScanner*  scanner;
-    char        *p;
-    int          result;
-
-    p = bufprint(temp, end, "%s/skins/%s",
-                 skinDirRoot, skinName);
-
-    if (p >= end || !path_exists(temp)) {
-        DD("    ignore bad skin directory %s", temp);
-        return 0;
-    }
-
-    /* first, is this a normal skin directory ? */
-    if (_checkSkinPath(temp)) {
-        /* yes */
-        DD("    found skin directory: %s", temp);
-        return 1;
-    }
-
-    /* second, is it an alias to another skin ? */
-    *p      = 0;
-    result  = 0;
-    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/skins/%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 = 1;
-                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 'skinDirPath' and 'skinName' in the AvdInfo.
- */
-static int
-_getSkinPathFromName( AvdInfo*  i, const char*  skinName )
-{
-    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);
-            i->skinName    = ASTRDUP(skinName);
-            i->skinDirPath = NULL;
-            return 1;
-        }
-    }
-
-    /* is the skin name a direct path to the skin directory ? */
-    if (_checkSkinPath(skinName)) {
-        goto FOUND_IT;
-    }
-
-    /* is the skin name a relative path from the SDK root ? */
-    p = bufprint(temp, end, "%s/%s", i->sdkRootPath, skinName);
-    if (p < end && _checkSkinPath(temp)) {
-        skinName = temp;
-        goto FOUND_IT;
-    }
-
-    /* nope */
-    return 0;
-
-FOUND_IT:
-    if (path_split(skinName, &i->skinDirPath, &i->skinName) < 0) {
-        derror("malformed skin name: %s", skinName);
-        exit(2);
-    }
-    D("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
-    return 1;
-}
-
-/* return 0 on success, -1 on error */
-static int
-_getSkin( AvdInfo*  i, AvdInfoParams*  params )
-{
-    char*  skinName;
-    char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-    char   explicitSkin = 1;
-
-    /* this function is used to compute the 'skinName' and 'skinDirPath'
-     * fields of the AvdInfo.
-     */
-
-    /* processing here is a bit tricky, so here's how it happens
-     *
-     * - command-line option '-skin <name>' can be used to specify the
-     *   name of a skin, to override the AVD settings.
-     *
-     * - skins are searched from <dir>/../skins for each <dir> in the
-     *   images search list, unless a '-skindir <path>' option has been
-     *   provided on the command-line
-     *
-     * - otherwise, the config.ini can also contain a SKIN_PATH key that
-     *   shall  give the full path to the skin directory, either relative
-     *   to the SDK root, or an absolute path.
-     *
-     * - skin names like '320x480' corresponds to "magic skins" that
-     *   simply display a framebuffer, without any ornaments of the
-     *   corresponding size. They do not correspond to any real skin
-     *   directory / files and are handled later. But they must be
-     *   recognized here and report a NULL skindir.
-     */
-    if (params->skinName) {
-        skinName = ASTRDUP(params->skinName);
-    } else {
-        skinName = iniFile_getString( i->configIni, SKIN_PATH, NULL );
-        explicitSkin = 0;
-    }
-
-    /* first, check that the skin name is not magic or a direct
-     * directory path
-     */
-    if (skinName != NULL && _getSkinPathFromName(i, skinName)) {
-        AFREE(skinName);
-        return 0;
-    }
-
-    /* if not, the default skinName is "HVGA" */
-    if (skinName == NULL) {
-        skinName = ASTRDUP(SKIN_DEFAULT);
-        explicitSkin = 0;
-    }
-
-    i->skinName = skinName;
-
-    /* now try to find the skin directory for that name -
-     * first try the content directory */
-    do {
-        /* if there is a single 'skin' directory in
-         * the content directory, assume that's what the
-         * user wants,  unless an explicit name was given
-         */
-        if (!explicitSkin) {
-            p = bufprint(temp, end, "%s/skin", i->contentPath);
-            if (p < end && _checkSkinPath(temp)) {
-                D("using skin content from %s", temp);
-                AFREE(i->skinName);
-                i->skinName    = ASTRDUP("skin");
-                i->skinDirPath = ASTRDUP(i->contentPath);
-                return 0;
-            }
-        }
-
-        /* look in content directory */
-        if (_checkSkinDir(temp, end, i->contentPath, skinName))
-            break;
-
-        /* look in the search paths. For each <dir> in the list,
-         * look the skins in <dir>/.. */
-        {
-            int  nn;
-            for (nn = 0; nn < i->numSearchPaths; nn++) {
-                char*  parentDir = path_parent(i->searchPaths[nn], 1);
-                int    ret;
-                if (parentDir == NULL)
-                    continue;
-                ret=_checkSkinDir(temp, end, parentDir, skinName);
-                AFREE(parentDir);
-                if (ret)
-                  break;
-            }
-            if (nn < i->numSearchPaths)
-                break;
-        }
-
-        /* didn't find it */
-        if (explicitSkin) {
-            derror("could not find directory for skin '%s',"
-                   " please use a different name", skinName);
-            exit(2);
-        } else {
-            dwarning("no skin directory matched '%s', so reverted to default",
-                     skinName);
-            AFREE(i->skinName);
-            params->skinName = SKIN_DEFAULT;
-            return _getSkin(i, params);
-        }
-
-        return -1;
-
-    } while (0);
-
-    /* separate skin name from parent directory. the skin name
-     * returned in 'temp' might be different from the original
-     * one due to alias expansion so strip it.
-     */
-    AFREE(i->skinName);
-
-    if (path_split(temp, &i->skinDirPath, &i->skinName) < 0) {
-        derror("weird skin path: %s", temp);
-        return -1;
-    }
-    DD("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
-    return 0;
-}
-
 /* If the user didn't explicitely provide an SD Card path,
  * check the SDCARD_PATH key in config.ini and use that if
  * available.
  */
 static void
-_getSDCardPath( AvdInfo*  i, AvdInfoParams*  params )
+_avdInfo_getSDCardPath( AvdInfo*  i, AvdInfoParams*  params )
 {
     const char*  path;
 
@@ -1093,22 +1252,6 @@
     params->forcePaths[AVD_IMAGE_SDCARD] = path;
 }
 
-static int
-_getCoreHwIniPath( AvdInfo* i, const char* basePath )
-{
-    char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
-    p = bufprint(temp, end, "%s/%s", basePath, CORE_HARDWARE_INI);
-    if (p >= end) {
-        DD("Path too long for %s:", CORE_HARDWARE_INI, basePath);
-        return -1;
-    }
-
-    D("using core hw config path: %s", temp);
-    i->coreHardwareIniPath = ASTRDUP(temp);
-    return 0;
-}
-
 AvdInfo*
 avdInfo_new( const char*  name, AvdInfoParams*  params )
 {
@@ -1125,25 +1268,24 @@
     ANEW0(i);
     i->deviceName = ASTRDUP(name);
 
-    if ( _getSdkRoot(i)     < 0 ||
-         _getRootIni(i)     < 0 ||
-         _getContentPath(i) < 0 ||
-         _getConfigIni(i)   < 0 ||
-         _getCoreHwIniPath(i, i->contentPath) < 0 )
+    if ( _avdInfo_getSdkRoot(i) < 0     ||
+         _avdInfo_getRootIni(i) < 0     ||
+         _avdInfo_getContentPath(i) < 0 ||
+         _avdInfo_getConfigIni(i)   < 0 ||
+         _avdInfo_getCoreHwIniPath(i, i->contentPath) < 0 )
         goto FAIL;
 
     /* look for image search paths. handle post 1.1/pre cupcake
      * obsolete SDKs.
      */
-    _getSearchPaths(i);
-    _getSDCardPath(i, params);
+    _avdInfo_getSearchPaths(i);
+    _avdInfo_getSDCardPath(i, params);
 
     /* don't need this anymore */
     iniFile_free(i->rootIni);
     i->rootIni = NULL;
 
-    if ( _getImagePaths(i, params) < 0 ||
-         _getSkin      (i, params) < 0 )
+    if ( _avdInfo_getImagePaths(i, params) < 0 )
         goto FAIL;
 
     return i;
@@ -1177,17 +1319,8 @@
  *****      the content directory, no SDK images search path.
  *****/
 
-/* used to fake a config.ini located in the content directory */
 static int
-_getBuildConfigIni( AvdInfo*  i )
-{
-    /* a blank file is ok at the moment */
-    i->configIni = iniFile_newFromMemory( "", 0 );
-    return 0;
-}
-
-static int
-_getBuildImagePaths( AvdInfo*  i, AvdInfoParams*  params )
+_avdInfo_getBuildImagePaths( AvdInfo*  i, AvdInfoParams*  params )
 {
     int   wipeData    = (params->flags & AVDINFO_WIPE_DATA) != 0;
     int   noCache     = (params->flags & AVDINFO_NO_CACHE) != 0;
@@ -1316,85 +1449,21 @@
     return 0;
 }
 
-static int
-_getBuildSkin( AvdInfo*  i, AvdInfoParams*  params )
-{
-    /* the (current) default skin name for our build system */
-    const char*  skinName = params->skinName;
-    const char*  skinDir  = params->skinRootPath;
-    char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-    char*        q;
-
-    if (!skinName) {
-        /* the (current) default skin name for the build system */
-        skinName = SKIN_DEFAULT;
-        D("selecting default skin name '%s'", skinName);
-    }
-
-    if (!skinDir) {
-
-#define  PREBUILT_SKINS_DIR  "development/tools/emulator/skins"
-#define  PRODUCT_SKIN_DIR "skin"
-
-        do {
-            /* look for the product skin in $ANDROID_PRODUCT_OUT/skin if no skin name is defined */
-            if (!params->skinName) {
-                /* look for <product_out>/skin first */
-                p = bufprint( temp, end, "%s/skin",
-                              i->androidOut );
-                if (path_exists(temp)) {
-                    p = bufprint( temp, end, "%s",
-                                  i->androidOut );
-                    skinName = PRODUCT_SKIN_DIR;
-                    D("selecting default product skin at '%s/%s'", temp, skinName);
-                    break;
-                }
-            }
-
-            /* next try in <sysdir>/../skins */
-            p = bufprint( temp, end, "%s/../skins",
-                          i->androidBuildRoot );
-            if (path_exists(temp))
-                break;
-
-            /* the (current) default skin directory */
-            p = bufprint( temp, end, "%s/%s",
-                        i->androidBuildRoot, PREBUILT_SKINS_DIR );
-        } while (0);
-
-    } else {
-        p = bufprint( temp, end, "%s", skinDir );
-    }
-
-    i->skinName = ASTRDUP(skinName);
-
-    q  = bufprint(p, end, "/%s/layout", skinName);
-    if (q >= end || !path_exists(temp)) {
-        DD("skin content directory does not exist: %s", temp);
-        if (skinDir)
-            dwarning("could not find valid skin '%s' in %s:\n",
-                     skinName, temp);
-        return -1;
-    }
-    *p = 0;
-    DD("found skin path: %s", temp);
-    i->skinDirPath = ASTRDUP(temp);
-
-    return 0;
-}
-
 /* Read a hardware.ini if it is located in the skin directory */
 static int
-_getBuildSkinHardwareIni( AvdInfo*  i )
+_avdInfo_getBuildSkinHardwareIni( AvdInfo*  i )
 {
+    char* skinName;
+    char* skinDirPath;
     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
 
-    if (i->skinDirPath == NULL || i->skinName == NULL)
+    avdInfo_getSkinInfo(i, &skinName, &skinDirPath);
+    if (skinDirPath == NULL)
         return 0;
 
-    p = bufprint(temp, end, "%s/%s/hardware.ini", i->skinDirPath, i->skinName);
+    p = bufprint(temp, end, "%s/%s/hardware.ini", skinDirPath, skinName);
     if (p >= end || !path_exists(temp)) {
-        DD("no skin-specific hardware.ini in %s", i->skinDirPath);
+        DD("no skin-specific hardware.ini in %s", skinDirPath);
         return 0;
     }
 
@@ -1406,76 +1475,6 @@
     return 0;
 }
 
-#define ABI_PREFIX       "ro.product.cpu.abi="
-#define ABI_PREFIX_LEN   (sizeof(ABI_PREFIX)-1)
-
-/* Retrieves a string corresponding to the target architecture
- * when in the Android platform tree. The only way to do that
- * properly for now is to look at $OUT/system/build.prop:
- *
- *   ro.product.cpu-abi=<abi>
- *
- * Where <abi> can be 'armeabi', 'armeabi-v7a' or 'x86'.
- */
-static const char*
-_getBuildTargetArch( AvdInfo*  i )
-{
-    const char* arch = "arm";
-    char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-    FILE*  file;
-
-    p = bufprint(temp, end, "%s/system/build.prop", i->androidOut);
-    if (p >= end) {
-        D("%s: ANDROID_PRODUCT_OUT too long: %s", __FUNCTION__, i->androidOut);
-        goto EXIT;
-    }
-    file = fopen(temp, "rb");
-    if (file == NULL) {
-        D("Could not open file: %s: %s", temp, strerror(errno));
-        D("Default target architecture=%s", arch);
-        goto EXIT;
-    }
-
-    while (fgets(temp, sizeof temp, file) != NULL) {
-        /* Trim trailing newlines, if any */
-        p = memchr(temp, '\0', sizeof temp);
-        if (p == NULL)
-            p = end;
-        if (p > temp && p[-1] == '\n') {
-            *--p = '\0';
-        }
-        if (p > temp && p[-1] == '\r') {
-            *--p = '\0';
-        }
-        /* force zero-termination in case of full-buffer */
-        if (p == end)
-            *--p = '\0';
-
-        if (memcmp(temp, ABI_PREFIX, ABI_PREFIX_LEN) != 0) {
-            continue;
-        }
-        p = temp + ABI_PREFIX_LEN;
-        if (p >= end || !*p)
-            goto EXIT2;
-
-        if (!strcmp("armeabi",p))
-            arch = "arm";
-        else if (!strcmp("armeabi-v7a",p))
-            arch = "arm";
-        else
-            arch = p;
-
-        D("Found target ABI=%s, architecture=%s", p, arch);
-        goto EXIT2;
-    }
-
-    D("Could not find target architecture, defaulting to %s", arch);
-EXIT2:
-    fclose(file);
-EXIT:
-    return arch;
-}
-
 AvdInfo*
 avdInfo_newForAndroidBuild( const char*     androidBuildRoot,
                             const char*     androidOut,
@@ -1489,19 +1488,20 @@
     i->androidBuildRoot = ASTRDUP(androidBuildRoot);
     i->androidOut       = ASTRDUP(androidOut);
     i->contentPath      = ASTRDUP(androidOut);
-    i->targetArch       = ASTRDUP(_getBuildTargetArch(i));
+    i->targetArch       = ASTRDUP(_getBuildTargetArch(i->androidOut));
 
     /* TODO: find a way to provide better information from the build files */
     i->deviceName = ASTRDUP("<build>");
 
-    if (_getBuildConfigIni(i)          < 0 ||
-        _getBuildImagePaths(i, params) < 0 ||
-        _getCoreHwIniPath(i, i->androidOut) < 0 )
+    /* There is no config.ini in the build */
+    i->configIni = NULL;
+
+    if (_avdInfo_getBuildImagePaths(i, params) < 0 ||
+        _avdInfo_getCoreHwIniPath(i, i->androidOut) < 0 )
         goto FAIL;
 
-    /* we don't need to fail if there is no valid skin */
-    _getBuildSkin(i, params);
-    _getBuildSkinHardwareIni(i);
+    /* Read the build skin's hardware.ini, if any */
+    _avdInfo_getBuildSkinHardwareIni(i);
 
     return i;
 
@@ -1549,18 +1549,6 @@
     return (i->imageState[imageType] == IMAGE_STATE_READONLY);
 }
 
-const char*
-avdInfo_getSkinName( AvdInfo*  i )
-{
-    return i->skinName;
-}
-
-const char*
-avdInfo_getSkinDir ( AvdInfo*  i )
-{
-    return i->skinDirPath;
-}
-
 int
 avdInfo_getHwConfig( AvdInfo*  i, AndroidHwConfig*  hw )
 {
@@ -1628,3 +1616,107 @@
 {
     return i->coreHardwareIniPath;
 }
+
+
+void
+avdInfo_getSkinInfo( 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;
+
+    /* 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: 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/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;
+        }
+
+        /* otherwise, use the default name */
+        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/tools/emulator"
+
+        /* if we are in the Android build, try the prebuilt directory */
+        if (i->inAndroidBuild) {
+            p = bufprint( temp, end, "%s/%s",
+                        i->androidBuildRoot, PREBUILT_SKINS_ROOT );
+            if (p < end) {
+                skinPath = _checkSkinSkinsDir(temp, skinName);
+                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 ! */
+        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;
+}
diff --git a/android/avd/info.h b/android/avd/info.h
index 2a85964..adcabfd 100644
--- a/android/avd/info.h
+++ b/android/avd/info.h
@@ -130,6 +130,17 @@
  */
 const char*  avdInfo_getName( AvdInfo*  i );
 
+/* Returns the path to a given AVD image file. This will return NULL if
+ * the file cannot be found / does not exist.
+ */
+const char*  avdInfo_getImagePath( AvdInfo*  i, AvdImageType  imageType );
+
+/* Returns the default path of a given AVD image file. This only makes sense
+ * if avdInfo_getImagePath() returned NULL.
+ */
+const char*  avdInfo_getImageDefaultPath( AvdInfo*  i, AvdImageType  imageType );
+
+
 /* Try to find the path of a given image file, returns NULL
  * if the corresponding file could not be found. the string
  * belongs to the AvdInfo object.
@@ -154,19 +165,18 @@
 /* Manually set the path of a given image file. */
 void         avdInfo_setImageFile( AvdInfo*  i, AvdImageType  imageType, const char*  imagePath );
 
-/* Returns the path of the skin directory */
-/* the string belongs to the AvdInfo object */
-const char*  avdInfo_getSkinPath( AvdInfo*  i );
-
-/* Returns the name of the virtual device's skin */
-const char*  avdInfo_getSkinName( AvdInfo*  i );
-
-/* Returns the root skin directory for this device */
-const char*  avdInfo_getSkinDir ( AvdInfo*  i );
-
 /* Returns the content path of the virtual device */
 const char*  avdInfo_getContentPath( AvdInfo*  i );
 
+/* Retrieve the AVD's specific skin information.
+ * On exit:
+ *   '*pSkinName' points to the skin's name.
+ *   '*pSkinDir' points to the skin's directory.
+ *
+ * Note that the skin's content will be under <skinDir>/<skinName>.
+ */
+void         avdInfo_getSkinInfo( AvdInfo*  i, char** pSkinName, char** pSkinDir );
+
 /* Returns TRUE iff in the Android build system */
 int          avdInfo_inAndroidBuild( AvdInfo*  i );
 
diff --git a/android/main-common.c b/android/main-common.c
index 05108a1..3bca6c4 100644
--- a/android/main-common.c
+++ b/android/main-common.c
@@ -710,26 +710,9 @@
     android_avdParams->forcePaths[imageType] = path;
 }
 
-AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild)
+
+void sanitizeOptions( AndroidOptions* opts )
 {
-    AvdInfo* ret = NULL;
-    char   tmp[MAX_PATH];
-    char*  tmpend = tmp + sizeof(tmp);
-    char*       android_build_root = NULL;
-    char*       android_build_out  = NULL;
-
-    /* setup the virtual device parameters from our options
-     */
-    if (opts->no_cache) {
-        android_avdParams->flags |= AVDINFO_NO_CACHE;
-    }
-    if (opts->wipe_data) {
-        android_avdParams->flags |= AVDINFO_WIPE_DATA | AVDINFO_WIPE_CACHE;
-    }
-    if (opts->no_snapstorage) {
-        android_avdParams->flags |= AVDINFO_NO_SNAPSHOTS;
-    }
-
     /* legacy support: we used to use -system <dir> and -image <file>
      * instead of -sysdir <dir> and -system <file>, so handle this by checking
      * whether the options point to directories or files.
@@ -762,6 +745,72 @@
         opts->system = NULL;
     }
 
+    if (opts->nojni) {
+        opts->no_jni = opts->nojni;
+        opts->nojni  = 0;
+    }
+
+    if (opts->nocache) {
+        opts->no_cache = opts->nocache;
+        opts->nocache  = 0;
+    }
+
+    if (opts->noaudio) {
+        opts->no_audio = opts->noaudio;
+        opts->noaudio  = 0;
+    }
+
+    if (opts->noskin) {
+        opts->no_skin = opts->noskin;
+        opts->noskin  = 0;
+    }
+
+    /* If -no-cache is used, ignore any -cache argument */
+    if (opts->no_cache) {
+        opts->cache = 0;
+    }
+
+    /* the purpose of -no-audio is to disable sound output from the emulator,
+     * not to disable Audio emulation. So simply force the 'none' backends */
+    if (opts->no_audio)
+        opts->audio = "none";
+
+    /* we don't accept -skindir without -skin now
+     * to simplify the autoconfig stuff with virtual devices
+     */
+    if (opts->no_skin) {
+        opts->skin    = "320x480";
+        opts->skindir = NULL;
+    }
+
+    if (opts->skindir) {
+        if (!opts->skin) {
+            derror( "the -skindir <path> option requires a -skin <name> option");
+            exit(1);
+        }
+    }
+}
+
+AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild)
+{
+    AvdInfo* ret = NULL;
+    char   tmp[MAX_PATH];
+    char*  tmpend = tmp + sizeof(tmp);
+    char*  android_build_root = NULL;
+    char*  android_build_out  = NULL;
+
+    /* setup the virtual device parameters from our options
+     */
+    if (opts->no_cache) {
+        android_avdParams->flags |= AVDINFO_NO_CACHE;
+    }
+    if (opts->wipe_data) {
+        android_avdParams->flags |= AVDINFO_WIPE_DATA | AVDINFO_WIPE_CACHE;
+    }
+    if (opts->no_snapstorage) {
+        android_avdParams->flags |= AVDINFO_NO_SNAPSHOTS;
+    }
+
     /* If no AVD name was given, try to find the top of the
      * Android build tree
      */
@@ -884,20 +933,6 @@
     _forceAvdImagePath(AVD_IMAGE_SDCARD,     opts->sdcard,      "SD Card", 0);
     _forceAvdImagePath(AVD_IMAGE_SNAPSHOTS,  opts->snapstorage, "snapshots", 0);
 
-    /* we don't accept -skindir without -skin now
-     * to simplify the autoconfig stuff with virtual devices
-     */
-    if (opts->no_skin) {
-        opts->skin    = "320x480";
-        opts->skindir = NULL;
-    }
-
-    if (opts->skindir) {
-        if (!opts->skin) {
-            derror( "the -skindir <path> option requires a -skin <name> option");
-            exit(1);
-        }
-    }
     android_avdParams->skinName     = opts->skin;
     android_avdParams->skinRootPath = opts->skindir;
 
diff --git a/android/main-common.h b/android/main-common.h
index a74bf52..0d184d5 100644
--- a/android/main-common.h
+++ b/android/main-common.h
@@ -60,6 +60,12 @@
                  const char*      skinPath,
                  AndroidOptions*  opts);
 
+/* Sanitize options. This deals with a few legacy options that are now
+ * handled differently. Call before anything else that needs to read
+ * the options list.
+ */
+void sanitizeOptions( AndroidOptions* opts );
+
 /* Creates and initializes AvdInfo instance for the given options.
  * Param:
  *  opts - Options passed to the main()
@@ -70,6 +76,12 @@
  */
 struct AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild);
 
+/* Populate the hwConfig fields corresponding to the kernel/disk images
+ * used by the emulator. This will zero *hwConfig first.
+ */
+void findImagePaths( AndroidHwConfig*  hwConfig,
+                     AndroidOptions*   opts );
+
 /* Updates hardware configuration for the given AVD and options.
  * Param:
  *  hwConfig - Hardware configuration to update.
diff --git a/android/main.c b/android/main.c
index b99097f..ddf8463 100644
--- a/android/main.c
+++ b/android/main.c
@@ -214,6 +214,8 @@
         exit(0);
     }
 
+    sanitizeOptions(opts);
+
     /* Initialization of UI started with -attach-core should work differently
      * than initialization of UI that starts the core. In particular....
      */
@@ -224,29 +226,30 @@
         exit(1);
     }
 
-    if (opts->nojni)
-        opts->no_jni = opts->nojni;
-
-    if (opts->nocache)
-        opts->no_cache = opts->nocache;
-
-    if (opts->noaudio)
-        opts->no_audio = opts->noaudio;
-
-    if (opts->noskin)
-        opts->no_skin = opts->noskin;
-
     /* Parses options and builds an appropriate AVD. */
     avd = android_avdInfo = createAVD(opts, &inAndroidBuild);
 
     /* get the skin from the virtual device configuration */
-    opts->skin    = (char*) avdInfo_getSkinName( avd );
-    opts->skindir = (char*) avdInfo_getSkinDir( avd );
+    if (opts->skindir != NULL) {
+        if (opts->skin == NULL) {
+            /* NOTE: Normally handled by sanitizeOptions(), just be safe */
+            derror("The -skindir <path> option requires a -skin <name> option");
+            exit(2);
+        }
+    } else {
+        char* skinName;
+        char* skinDir;
 
-    if (opts->skin) {
-        D("autoconfig: -skin %s", opts->skin);
-    }
-    if (opts->skindir) {
+        avdInfo_getSkinInfo(avd, &skinName, &skinDir);
+
+        if (opts->skin == NULL) {
+            opts->skin = skinName;
+            D("autoconfig: -skin %s", opts->skin);
+        } else {
+            AFREE(skinName);
+        }
+
+        opts->skindir = skinDir;
         D("autoconfig: -skindir %s", opts->skindir);
     }
 
@@ -328,9 +331,6 @@
         opts->trace = tracePath;
     }
 
-    if (opts->no_cache)
-        opts->cache = 0;
-
     n = 1;
     /* generate arguments for the underlying qemu main() */
     {
@@ -393,11 +393,6 @@
         args[n++] = "-netfast";
     }
 
-    /* the purpose of -no-audio is to disable sound output from the emulator,
-     * not to disable Audio emulation. So simply force the 'none' backends */
-    if (opts->no_audio)
-        opts->audio = "none";
-
     if (opts->audio) {
         args[n++] = "-audio";
         args[n++] = opts->audio;