Home | History | Annotate | Download | only in avd
      1 /* Copyright (C) 2008 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 #include "android/avd/info.h"
     13 #include "android/utils/path.h"
     14 #include "android/utils/bufprint.h"
     15 #include "android/utils/filelock.h"
     16 #include "android/utils/tempfile.h"
     17 #include "android/utils/debug.h"
     18 #include "android/utils/dirscanner.h"
     19 #include <ctype.h>
     20 #include <stddef.h>
     21 #include <string.h>
     22 #include <stdlib.h>
     23 #include <stdio.h>
     24 #include <errno.h>
     25 
     26 /* global variables - see android/globals.h */
     27 AvdInfoParams   android_avdParams[1];
     28 AvdInfo*        android_avdInfo;
     29 
     30 /* for debugging */
     31 #define  D(...)   VERBOSE_PRINT(init,__VA_ARGS__)
     32 #define  DD(...)  VERBOSE_PRINT(avd_config,__VA_ARGS__)
     33 
     34 /* technical note on how all of this is supposed to work:
     35  *
     36  * Each AVD corresponds to a "content directory" that is used to
     37  * store persistent disk images and configuration files. Most remarkable
     38  * are:
     39  *
     40  * - a "config.ini" file used to hold configuration information for the
     41  *   AVD
     42  *
     43  * - mandatory user data image ("userdata-qemu.img") and cache image
     44  *   ("cache.img")
     45  *
     46  * - optional mutable system image ("system-qemu.img"), kernel image
     47  *   ("kernel-qemu") and read-only ramdisk ("ramdisk.img")
     48  *
     49  * When starting up an AVD, the emulator looks for relevant disk images
     50  * in the content directory. If it doesn't find a given image there, it
     51  * will try to search in the list of system directories listed in the
     52  * 'config.ini' file through one of the following (key,value) pairs:
     53  *
     54  *    images.sysdir.1 = <first search path>
     55  *    images.sysdir.2 = <second search path>
     56  *
     57  * The search paths can be absolute, or relative to the root SDK installation
     58  * path (which is determined from the emulator program's location, or from the
     59  * ANDROID_SDK_ROOT environment variable).
     60  *
     61  * Individual image disk search patch can be over-riden on the command-line
     62  * with one of the usual options.
     63  */
     64 
     65 /* this is the subdirectory of $HOME/.android where all
     66  * root configuration files (and default content directories)
     67  * are located.
     68  */
     69 #define  ANDROID_AVD_DIR    "avd"
     70 
     71 /* the prefix of config.ini keys that will be used for search directories
     72  * of system images.
     73  */
     74 #define  SEARCH_PREFIX   "image.sysdir."
     75 
     76 /* the maximum number of search path keys we're going to read from the
     77  * config.ini file
     78  */
     79 #define  MAX_SEARCH_PATHS  2
     80 
     81 /* the config.ini key that will be used to indicate the full relative
     82  * path to the skin directory (including the skin name).
     83  */
     84 #define  SKIN_PATH       "skin.path"
     85 
     86 /* default skin name */
     87 #define  SKIN_DEFAULT    "HVGA"
     88 
     89 /* the config.ini key that is used to indicate the absolute path
     90  * to the SD Card image file, if you don't want to place it in
     91  * the content directory.
     92  */
     93 #define  SDCARD_PATH     "sdcard.path"
     94 
     95 /* certain disk image files are mounted read/write by the emulator
     96  * to ensure that several emulators referencing the same files
     97  * do not corrupt these files, we need to lock them and respond
     98  * to collision depending on the image type.
     99  *
    100  * the enumeration below is used to record information about
    101  * each image file path.
    102  *
    103  * READONLY means that the file will be mounted read-only
    104  * and this doesn't need to be locked. must be first in list
    105  *
    106  * MUSTLOCK means that the file should be locked before
    107  * being mounted by the emulator
    108  *
    109  * TEMPORARY means that the file has been copied to a
    110  * temporary image, which can be mounted read/write
    111  * but doesn't require locking.
    112  */
    113 typedef enum {
    114     IMAGE_STATE_READONLY,     /* unlocked */
    115     IMAGE_STATE_MUSTLOCK,     /* must be locked */
    116     IMAGE_STATE_LOCKED,       /* locked */
    117     IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
    118     IMAGE_STATE_TEMPORARY,    /* copied to temp file (no lock needed) */
    119 } AvdImageState;
    120 
    121 struct AvdInfo {
    122     /* for the Android build system case */
    123     char      inAndroidBuild;
    124     char*     androidOut;
    125     char*     androidBuildRoot;
    126 
    127     /* for the normal virtual device case */
    128     char*     deviceName;
    129     char*     sdkRootPath;
    130     char      sdkRootPathFromEnv;
    131     char*     searchPaths[ MAX_SEARCH_PATHS ];
    132     int       numSearchPaths;
    133     char*     contentPath;
    134     IniFile*  rootIni;      /* root <foo>.ini file */
    135     IniFile*  configIni;    /* virtual device's config.ini */
    136     IniFile*  hardwareIni;  /* skin-specific hardware.ini */
    137 
    138     /* for both */
    139     char*     skinName;     /* skin name */
    140     char*     skinDirPath;  /* skin directory */
    141 
    142     /* image files */
    143     char*     imagePath [ AVD_IMAGE_MAX ];
    144     char      imageState[ AVD_IMAGE_MAX ];
    145 };
    146 
    147 
    148 void
    149 avdInfo_free( AvdInfo*  i )
    150 {
    151     if (i) {
    152         int  nn;
    153 
    154         for (nn = 0; nn < AVD_IMAGE_MAX; nn++)
    155             AFREE(i->imagePath[nn]);
    156 
    157         AFREE(i->skinName);
    158         AFREE(i->skinDirPath);
    159 
    160         for (nn = 0; nn < i->numSearchPaths; nn++)
    161             AFREE(i->searchPaths[nn]);
    162 
    163         i->numSearchPaths = 0;
    164 
    165         if (i->configIni) {
    166             iniFile_free(i->configIni);
    167             i->configIni = NULL;
    168         }
    169 
    170         if (i->hardwareIni) {
    171             iniFile_free(i->hardwareIni);
    172             i->hardwareIni = NULL;
    173         }
    174 
    175         if (i->rootIni) {
    176             iniFile_free(i->rootIni);
    177             i->rootIni = NULL;
    178         }
    179 
    180         AFREE(i->contentPath);
    181         AFREE(i->sdkRootPath);
    182 
    183         if (i->inAndroidBuild) {
    184             AFREE(i->androidOut);
    185             AFREE(i->androidBuildRoot);
    186         }
    187 
    188         AFREE(i->deviceName);
    189         AFREE(i);
    190     }
    191 }
    192 
    193 /* list of default file names for each supported image file type */
    194 static const char*  const  _imageFileNames[ AVD_IMAGE_MAX ] = {
    195 #define  _AVD_IMG(x,y,z)  y,
    196     AVD_IMAGE_LIST
    197 #undef _AVD_IMG
    198 };
    199 
    200 /* list of short text description for each supported image file type */
    201 static const char*  const _imageFileText[ AVD_IMAGE_MAX ] = {
    202 #define  _AVD_IMG(x,y,z)  z,
    203     AVD_IMAGE_LIST
    204 #undef _AVD_IMG
    205 };
    206 
    207 /***************************************************************
    208  ***************************************************************
    209  *****
    210  *****    NORMAL VIRTUAL DEVICE SUPPORT
    211  *****
    212  *****/
    213 
    214 /* compute path to the root SDK directory
    215  * assume we are in $SDKROOT/tools/emulator[.exe]
    216  */
    217 static int
    218 _getSdkRoot( AvdInfo*  i )
    219 {
    220     const char*  env;
    221     char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    222 
    223 #define  SDK_ROOT_ENV  "ANDROID_SDK_ROOT"
    224 
    225     env = getenv(SDK_ROOT_ENV);
    226     if (env != NULL && env[0] != 0) {
    227         if (path_exists(env)) {
    228             D("found " SDK_ROOT_ENV ": %s", env);
    229             i->sdkRootPath = ASTRDUP(env);
    230             i->sdkRootPathFromEnv = 1;
    231             return 0;
    232         }
    233         D(SDK_ROOT_ENV " points to unknown directory: %s", env);
    234     }
    235 
    236     (void) bufprint_app_dir(temp, end);
    237 
    238     i->sdkRootPath = path_parent(temp, 1);
    239     if (i->sdkRootPath == NULL) {
    240         derror("can't find root of SDK directory");
    241         return -1;
    242     }
    243     D("found SDK root at %s", i->sdkRootPath);
    244     return 0;
    245 }
    246 
    247 static void
    248 _getSearchPaths( AvdInfo*  i )
    249 {
    250     char  temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
    251     int   nn, count = 0;
    252 
    253 
    254 
    255     for (nn = 0; nn < MAX_SEARCH_PATHS; nn++) {
    256         char*  path;
    257 
    258         p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
    259         if (p >= end)
    260             continue;
    261 
    262         path = iniFile_getString( i->configIni, temp );
    263         if (path != NULL) {
    264             DD("    found image search path: %s", path);
    265             if (!path_is_absolute(path)) {
    266                 p = bufprint(temp, end, "%s/%s", i->sdkRootPath, path);
    267                 AFREE(path);
    268                 path = ASTRDUP(temp);
    269             }
    270             i->searchPaths[count++] = path;
    271         }
    272     }
    273 
    274     i->numSearchPaths = count;
    275     if (count == 0) {
    276         derror("no search paths found in this AVD's configuration.\n"
    277                "Weird, the AVD's config.ini file is malformed. Try re-creating it.\n");
    278         exit(2);
    279     }
    280     else
    281         DD("found a total of %d search paths for this AVD", count);
    282 }
    283 
    284 static int
    285 _checkAvdName( const char*  name )
    286 {
    287     int  len  = strlen(name);
    288     int  len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    289                              "abcdefghijklmnopqrstuvwxyz"
    290                              "0123456789_.-");
    291     return (len == len2);
    292 }
    293 
    294 /* parse the root config .ini file. it is located in
    295  * ~/.android/avd/<name>.ini or Windows equivalent
    296  */
    297 static int
    298 _getRootIni( AvdInfo*  i )
    299 {
    300     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    301 
    302     p = bufprint_config_path(temp, end);
    303     p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", i->deviceName);
    304     if (p >= end) {
    305         derror("device name too long");
    306         return -1;
    307     }
    308 
    309     i->rootIni = iniFile_newFromFile(temp);
    310     if (i->rootIni == NULL) {
    311         derror("unknown virtual device name: '%s'", i->deviceName);
    312         return -1;
    313     }
    314     D("root virtual device file at %s", temp);
    315     return 0;
    316 }
    317 
    318 /* the .ini variable name that points to the content directory
    319  * in a root AVD ini file. This is required */
    320 #   define  ROOT_PATH_KEY    "path"
    321 
    322 static int
    323 _getContentPath( AvdInfo*  i )
    324 {
    325     i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY);
    326 
    327     if (i->contentPath == NULL) {
    328         derror("bad config: %s",
    329                "virtual device file lacks a "ROOT_PATH_KEY" entry");
    330         return -1;
    331     }
    332     D("virtual device content at %s", i->contentPath);
    333     return 0;
    334 }
    335 
    336 /* find and parse the config.ini file from the content directory */
    337 static int
    338 _getConfigIni(AvdInfo*  i)
    339 {
    340     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    341 
    342     p = bufprint(p, end, "%s/config.ini", i->contentPath);
    343     if (p >= end) {
    344         derror("can't access virtual device content directory");
    345         return -1;
    346     }
    347 
    348 #if 1   /* XXX: TODO: remove this in the future */
    349     /* for now, allow a non-existing config.ini */
    350     if (!path_exists(temp)) {
    351         D("virtual device has no config file - no problem");
    352         return 0;
    353     }
    354 #endif
    355 
    356     i->configIni = iniFile_newFromFile(temp);
    357     if (i->configIni == NULL) {
    358         derror("bad config: %s",
    359                "virtual device directory lacks config.ini");
    360         return -1;
    361     }
    362     D("virtual device config file: %s", temp);
    363     return 0;
    364 }
    365 
    366 /***************************************************************
    367  ***************************************************************
    368  *****
    369  *****    KERNEL/DISK IMAGE LOADER
    370  *****
    371  *****/
    372 
    373 /* a structure used to handle the loading of
    374  * kernel/disk images.
    375  */
    376 typedef struct {
    377     AvdInfo*        info;
    378     AvdInfoParams*  params;
    379     AvdImageType    id;
    380     const char*     imageFile;
    381     const char*     imageText;
    382     char**          pPath;
    383     char*           pState;
    384     char            temp[PATH_MAX];
    385 } ImageLoader;
    386 
    387 static void
    388 imageLoader_init( ImageLoader*  l, AvdInfo*  info, AvdInfoParams*  params )
    389 {
    390     memset(l, 0, sizeof(*l));
    391     l->info    = info;
    392     l->params  = params;
    393 }
    394 
    395 /* set the type of the image to load */
    396 static void
    397 imageLoader_set( ImageLoader*  l, AvdImageType  id )
    398 {
    399     l->id        = id;
    400     l->imageFile = _imageFileNames[id];
    401     l->imageText = _imageFileText[id];
    402     l->pPath     = &l->info->imagePath[id];
    403     l->pState    = &l->info->imageState[id];
    404 
    405     l->pState[0] = IMAGE_STATE_READONLY;
    406 }
    407 
    408 /* change the image path */
    409 static char*
    410 imageLoader_setPath( ImageLoader*  l, const char*  path )
    411 {
    412     path = path ? ASTRDUP(path) : NULL;
    413 
    414     AFREE(l->pPath[0]);
    415     l->pPath[0] = (char*) path;
    416 
    417     return (char*) path;
    418 }
    419 
    420 static char*
    421 imageLoader_extractPath( ImageLoader*  l )
    422 {
    423     char*  result = l->pPath[0];
    424     l->pPath[0] = NULL;
    425     return result;
    426 }
    427 
    428 /* flags used when loading images */
    429 enum {
    430     IMAGE_REQUIRED          = (1<<0),  /* image is required */
    431     IMAGE_SEARCH_SDK        = (1<<1),  /* search image in SDK */
    432     IMAGE_EMPTY_IF_MISSING  = (1<<2),  /* create empty file if missing */
    433     IMAGE_DONT_LOCK         = (1<<4),  /* don't try to lock image */
    434     IMAGE_IGNORE_IF_LOCKED  = (1<<5),  /* ignore file if it's locked */
    435 };
    436 
    437 #define  IMAGE_OPTIONAL  0
    438 
    439 /* find an image from the SDK search directories.
    440  * returns the full path or NULL if the file could not be found.
    441  *
    442  * note: this stores the result in the image's path as well
    443  */
    444 static char*
    445 imageLoader_lookupSdk( ImageLoader*  l  )
    446 {
    447     AvdInfo*     i     = l->info;
    448     const char*  image = l->imageFile;
    449     char*        temp  = l->temp, *p = temp, *end = p + sizeof(l->temp);
    450 
    451     do {
    452         /* try the search paths */
    453         int  nn;
    454 
    455         for (nn = 0; nn < i->numSearchPaths; nn++) {
    456             const char* searchDir = i->searchPaths[nn];
    457 
    458             p = bufprint(temp, end, "%s/%s", searchDir, image);
    459             if (p < end && path_exists(temp)) {
    460                 DD("found %s in search dir: %s", image, searchDir);
    461                 goto FOUND;
    462             }
    463             DD("    no %s in search dir: %s", image, searchDir);
    464         }
    465 
    466         return NULL;
    467 
    468     } while (0);
    469 
    470 FOUND:
    471     l->pState[0] = IMAGE_STATE_READONLY;
    472 
    473     return imageLoader_setPath(l, temp);
    474 }
    475 
    476 /* search for a file in the content directory.
    477  * returns NULL if the file cannot be found.
    478  *
    479  * note that this formats l->temp with the file's path
    480  * allowing you to retrieve it if the function returns NULL
    481  */
    482 static char*
    483 imageLoader_lookupContent( ImageLoader*  l )
    484 {
    485     AvdInfo*  i     = l->info;
    486     char*     temp  = l->temp, *p = temp, *end = p + sizeof(l->temp);
    487 
    488     p = bufprint(temp, end, "%s/%s", i->contentPath, l->imageFile);
    489     if (p >= end) {
    490         derror("content directory path too long");
    491         exit(2);
    492     }
    493     if (!path_exists(temp)) {
    494         DD("    no %s in content directory", l->imageFile);
    495         return NULL;
    496     }
    497     DD("found %s in content directory", l->imageFile);
    498 
    499     /* assume content image files must be locked */
    500     l->pState[0] = IMAGE_STATE_MUSTLOCK;
    501 
    502     return imageLoader_setPath(l, temp);
    503 }
    504 
    505 /* lock a file image depending on its state and user flags
    506  * note that this clears l->pPath[0] if the lock could not
    507  * be acquired and that IMAGE_IGNORE_IF_LOCKED is used.
    508  */
    509 static void
    510 imageLoader_lock( ImageLoader*  l, unsigned  flags )
    511 {
    512     const char*  path = l->pPath[0];
    513 
    514     if (flags & IMAGE_DONT_LOCK)
    515         return;
    516 
    517     if (l->pState[0] != IMAGE_STATE_MUSTLOCK)
    518         return;
    519 
    520     D("    locking %s image at %s", l->imageText, path);
    521 
    522     if (filelock_create(path) != NULL) {
    523         /* succesful lock */
    524         l->pState[0] = IMAGE_STATE_LOCKED;
    525         return;
    526     }
    527 
    528     if (flags & IMAGE_IGNORE_IF_LOCKED) {
    529         dwarning("ignoring locked %s image at %s", l->imageText, path);
    530         imageLoader_setPath(l, NULL);
    531         return;
    532     }
    533 
    534     derror("the %s image is used by another emulator. aborting",
    535             l->imageText);
    536     exit(2);
    537 }
    538 
    539 /* make a file image empty, this may require locking */
    540 static void
    541 imageLoader_empty( ImageLoader*  l, unsigned  flags )
    542 {
    543     const char*  path;
    544 
    545     imageLoader_lock(l, flags);
    546 
    547     path = l->pPath[0];
    548     if (path == NULL)  /* failed to lock, caller will handle it */
    549         return;
    550 
    551     if (path_empty_file(path) < 0) {
    552         derror("could not create %s image at %s: %s",
    553                 l->imageText, path, strerror(errno));
    554         exit(2);
    555     }
    556     l->pState[0] = IMAGE_STATE_LOCKED_EMPTY;
    557 }
    558 
    559 
    560 /* copy image file from a given source
    561  * assumes locking is needed.
    562  */
    563 static void
    564 imageLoader_copyFrom( ImageLoader*  l, const char*  srcPath )
    565 {
    566     const char*  dstPath = NULL;
    567 
    568     /* find destination file */
    569     if (l->params) {
    570         dstPath = l->params->forcePaths[l->id];
    571     }
    572     if (!dstPath) {
    573         imageLoader_lookupContent(l);
    574         dstPath = l->temp;
    575     }
    576 
    577     /* lock destination */
    578     imageLoader_setPath(l, dstPath);
    579     l->pState[0] = IMAGE_STATE_MUSTLOCK;
    580     imageLoader_lock(l, 0);
    581 
    582     /* make the copy */
    583     if (path_copy_file(dstPath, srcPath) < 0) {
    584         derror("can't initialize %s image from SDK: %s: %s",
    585                l->imageText, dstPath, strerror(errno));
    586         exit(2);
    587     }
    588 }
    589 
    590 /* this will load and eventually lock and image file, depending
    591  * on the flags being used. on exit, this function udpates
    592  * l->pState[0] and l->pPath[0]
    593  *
    594  * returns the path to the file. Note that it returns NULL
    595  * only if the file was optional and could not be found.
    596  *
    597  * if the file is required and missing, the function aborts
    598  * the program.
    599  */
    600 static char*
    601 imageLoader_load( ImageLoader*    l,
    602                   unsigned        flags )
    603 {
    604     const char*  path = NULL;
    605 
    606     /* set image state */
    607     l->pState[0] = (flags & IMAGE_DONT_LOCK) == 0
    608                  ? IMAGE_STATE_MUSTLOCK
    609                  : IMAGE_STATE_READONLY;
    610 
    611     /* check user-provided path */
    612     path = l->params->forcePaths[l->id];
    613     if (path != NULL) {
    614         imageLoader_setPath(l, path);
    615         if (path_exists(path)) {
    616             DD("found user-provided %s image: %s", l->imageText, l->imageFile);
    617             goto EXIT;
    618         }
    619         D("user-provided %s image does not exist: %s",
    620           l->imageText, path);
    621 
    622         /* if the file is required, abort */
    623         if (flags & IMAGE_REQUIRED) {
    624             derror("user-provided %s image at %s doesn't exist",
    625                     l->imageText, path);
    626             exit(2);
    627         }
    628     }
    629     else {
    630         const char*  contentFile;
    631 
    632         /* second, look in the content directory */
    633         path = imageLoader_lookupContent(l);
    634         if (path) goto EXIT;
    635 
    636         contentFile = ASTRDUP(l->temp);
    637 
    638         /* it's not there */
    639         if (flags & IMAGE_SEARCH_SDK) {
    640             /* third, look in the SDK directory */
    641             path = imageLoader_lookupSdk(l);
    642             if (path) {
    643                 AFREE((char*)contentFile);
    644                 goto EXIT;
    645             }
    646         }
    647         DD("found no %s image (%s)", l->imageText, l->imageFile);
    648 
    649         /* if the file is required, abort */
    650         if (flags & IMAGE_REQUIRED) {
    651             AvdInfo*  i = l->info;
    652 
    653             derror("could not find required %s image (%s).",
    654                    l->imageText, l->imageFile);
    655 
    656             if (i->inAndroidBuild) {
    657                 dprint( "Did you build everything ?" );
    658             } else if (!i->sdkRootPathFromEnv) {
    659                 dprint( "Maybe defining %s to point to a valid SDK "
    660                         "installation path might help ?", SDK_ROOT_ENV );
    661             } else {
    662                 dprint( "Your %s is probably wrong: %s", SDK_ROOT_ENV,
    663                         i->sdkRootPath );
    664             }
    665             exit(2);
    666         }
    667 
    668         path = imageLoader_setPath(l, contentFile);
    669         AFREE((char*)contentFile);
    670     }
    671 
    672     /* otherwise, do we need to create it ? */
    673     if (flags & IMAGE_EMPTY_IF_MISSING) {
    674         imageLoader_empty(l, flags);
    675         return l->pPath[0];
    676     }
    677     return NULL;
    678 
    679 EXIT:
    680     imageLoader_lock(l, flags);
    681     return l->pPath[0];
    682 }
    683 
    684 
    685 
    686 /* find the correct path of all image files we're going to need
    687  * and lock the files that need it.
    688  */
    689 static int
    690 _getImagePaths(AvdInfo*  i, AvdInfoParams*  params )
    691 {
    692     int   wipeData  = (params->flags & AVDINFO_WIPE_DATA) != 0;
    693     int   wipeCache = (params->flags & AVDINFO_WIPE_CACHE) != 0;
    694     int   noCache   = (params->flags & AVDINFO_NO_CACHE) != 0;
    695     int   noSdCard  = (params->flags & AVDINFO_NO_SDCARD) != 0;
    696 
    697     ImageLoader  l[1];
    698 
    699     imageLoader_init(l, i, params);
    700 
    701     /* pick up the kernel and ramdisk image files - these don't
    702      * need a specific handling.
    703      */
    704     imageLoader_set ( l, AVD_IMAGE_KERNEL );
    705     imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
    706 
    707     imageLoader_set ( l, AVD_IMAGE_RAMDISK );
    708     imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
    709 
    710     /* the system image
    711      *
    712      * if there is one in the content directory just lock
    713      * and use it.
    714      */
    715     imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
    716     imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
    717 
    718     /* the data partition - this one is special because if it
    719      * is missing, we need to copy the initial image file into it.
    720      *
    721      * first, try to see if it is in the content directory
    722      * (or the user-provided path)
    723      */
    724     imageLoader_set( l, AVD_IMAGE_USERDATA );
    725     if ( !imageLoader_load( l, IMAGE_OPTIONAL |
    726                                IMAGE_EMPTY_IF_MISSING |
    727                                IMAGE_DONT_LOCK ) )
    728     {
    729         /* it's not, we're going to initialize it. simply
    730          * forcing a data wipe should be enough */
    731         D("initializing new data partition image: %s", l->pPath[0]);
    732         wipeData = 1;
    733     }
    734 
    735     if (wipeData) {
    736         /* find SDK source file */
    737         const char*  srcPath;
    738 
    739         imageLoader_set( l, AVD_IMAGE_INITDATA );
    740         if (imageLoader_lookupSdk(l) == NULL) {
    741             derror("can't locate initial %s image in SDK",
    742                 l->imageText);
    743             exit(2);
    744         }
    745         srcPath = imageLoader_extractPath(l);
    746 
    747         imageLoader_set( l, AVD_IMAGE_USERDATA );
    748         imageLoader_copyFrom( l, srcPath );
    749         AFREE((char*) srcPath);
    750     }
    751     else
    752     {
    753         /* lock the data partition image */
    754         l->pState[0] = IMAGE_STATE_MUSTLOCK;
    755         imageLoader_lock( l, 0 );
    756     }
    757 
    758     /* the cache partition: unless the user doesn't want one,
    759      * we're going to create it in the content directory
    760      */
    761     if (!noCache) {
    762         imageLoader_set (l, AVD_IMAGE_CACHE);
    763         imageLoader_load(l, IMAGE_OPTIONAL |
    764                             IMAGE_EMPTY_IF_MISSING );
    765 
    766         if (wipeCache) {
    767             if (path_empty_file(l->pPath[0]) < 0) {
    768                 derror("cannot wipe %s image at %s: %s",
    769                        l->imageText, l->pPath[0],
    770                        strerror(errno));
    771                 exit(2);
    772             }
    773         }
    774     }
    775 
    776     /* the SD Card image. unless the user doesn't want to, we're
    777      * going to mount it if available. Note that if the image is
    778      * already used, we must ignore it.
    779      */
    780     if (!noSdCard) {
    781         imageLoader_set (l, AVD_IMAGE_SDCARD);
    782         imageLoader_load(l, IMAGE_OPTIONAL |
    783                             IMAGE_IGNORE_IF_LOCKED);
    784 
    785         /* if the file was not found, ignore it */
    786         if (l->pPath[0] && !path_exists(l->pPath[0]))
    787         {
    788             D("ignoring non-existing %s at %s: %s",
    789               l->imageText, l->pPath[0], strerror(errno));
    790 
    791             /* if the user provided the SD Card path by hand,
    792              * warn him. */
    793             if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL)
    794                 dwarning("ignoring non-existing SD Card image");
    795 
    796             imageLoader_setPath(l, NULL);
    797         }
    798     }
    799 
    800     return 0;
    801 }
    802 
    803 /* check that a given directory contains a valid skin.
    804  * returns 1 on success, 0 on failure.
    805  */
    806 static int
    807 _checkSkinPath( const char*  skinPath )
    808 {
    809     char  temp[MAX_PATH], *p=temp, *end=p+sizeof(temp);
    810 
    811     /* for now, if it has a 'layout' file, it is a valid skin path */
    812     p = bufprint(temp, end, "%s/layout", skinPath);
    813     if (p >= end || !path_exists(temp))
    814         return 0;
    815 
    816     return 1;
    817 }
    818 
    819 /* check that there is a skin named 'skinName' listed from 'skinDirRoot'
    820  * this returns 1 on success, 0 on failure
    821  * on success, the 'temp' buffer will get the path containing the real
    822  * skin directory (after alias expansion), including the skin name.
    823  */
    824 static int
    825 _checkSkinDir( char*        temp,
    826                char*        end,
    827                const char*  skinDirRoot,
    828                const char*  skinName )
    829 {
    830     DirScanner*  scanner;
    831     char        *p;
    832     int          result;
    833 
    834     p = bufprint(temp, end, "%s/skins/%s",
    835                  skinDirRoot, skinName);
    836 
    837     if (p >= end || !path_exists(temp)) {
    838         DD("    ignore bad skin directory %s", temp);
    839         return 0;
    840     }
    841 
    842     /* first, is this a normal skin directory ? */
    843     if (_checkSkinPath(temp)) {
    844         /* yes */
    845         DD("    found skin directory: %s", temp);
    846         return 1;
    847     }
    848 
    849     /* second, is it an alias to another skin ? */
    850     *p      = 0;
    851     result  = 0;
    852     scanner = dirScanner_new(temp);
    853     if (scanner != NULL) {
    854         for (;;) {
    855             const char*  file = dirScanner_next(scanner);
    856 
    857             if (file == NULL)
    858                 break;
    859 
    860             if (strncmp(file, "alias-", 6) || file[6] == 0)
    861                 continue;
    862 
    863             p = bufprint(temp, end, "%s/skins/%s",
    864                             skinDirRoot, file+6);
    865 
    866             if (p < end && _checkSkinPath(temp)) {
    867                 /* yes, it's an alias */
    868                 DD("    skin alias '%s' points to skin directory: %s",
    869                    file+6, temp);
    870                 result = 1;
    871                 break;
    872             }
    873         }
    874         dirScanner_free(scanner);
    875     }
    876     return result;
    877 }
    878 
    879 /* try to see if the skin name leads to a magic skin or skin path directly
    880  * returns 1 on success, 0 on error.
    881  * on success, this sets up 'skinDirPath' and 'skinName' in the AvdInfo.
    882  */
    883 static int
    884 _getSkinPathFromName( AvdInfo*  i, const char*  skinName )
    885 {
    886     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    887 
    888     /* if the skin name has the format 'NNNNxNNN' where
    889     * NNN is a decimal value, then this is a 'magic' skin
    890     * name that doesn't require a skin directory
    891     */
    892     if (isdigit(skinName[0])) {
    893         int  width, height;
    894         if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
    895             D("'magic' skin format detected: %s", skinName);
    896             i->skinName    = ASTRDUP(skinName);
    897             i->skinDirPath = NULL;
    898             return 1;
    899         }
    900     }
    901 
    902     /* is the skin name a direct path to the skin directory ? */
    903     if (_checkSkinPath(skinName)) {
    904         goto FOUND_IT;
    905     }
    906 
    907     /* is the skin name a relative path from the SDK root ? */
    908     p = bufprint(temp, end, "%s/%s", i->sdkRootPath, skinName);
    909     if (p < end && _checkSkinPath(temp)) {
    910         skinName = temp;
    911         goto FOUND_IT;
    912     }
    913 
    914     /* nope */
    915     return 0;
    916 
    917 FOUND_IT:
    918     if (path_split(skinName, &i->skinDirPath, &i->skinName) < 0) {
    919         derror("malformed skin name: %s", skinName);
    920         exit(2);
    921     }
    922     D("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
    923     return 1;
    924 }
    925 
    926 /* return 0 on success, -1 on error */
    927 static int
    928 _getSkin( AvdInfo*  i, AvdInfoParams*  params )
    929 {
    930     char*  skinName;
    931     char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    932     char   explicitSkin = 1;
    933 
    934     /* this function is used to compute the 'skinName' and 'skinDirPath'
    935      * fields of the AvdInfo.
    936      */
    937 
    938     /* processing here is a bit tricky, so here's how it happens
    939      *
    940      * - command-line option '-skin <name>' can be used to specify the
    941      *   name of a skin, to override the AVD settings.
    942      *
    943      * - skins are searched from <dir>/../skins for each <dir> in the
    944      *   images search list, unless a '-skindir <path>' option has been
    945      *   provided on the command-line
    946      *
    947      * - otherwise, the config.ini can also contain a SKIN_PATH key that
    948      *   shall  give the full path to the skin directory, either relative
    949      *   to the SDK root, or an absolute path.
    950      *
    951      * - skin names like '320x480' corresponds to "magic skins" that
    952      *   simply display a framebuffer, without any ornaments of the
    953      *   corresponding size. They do not correspond to any real skin
    954      *   directory / files and are handled later. But they must be
    955      *   recognized here and report a NULL skindir.
    956      */
    957     if (params->skinName) {
    958         skinName = ASTRDUP(params->skinName);
    959     } else {
    960         skinName = iniFile_getString( i->configIni, SKIN_PATH );
    961         explicitSkin = 0;
    962     }
    963 
    964     /* first, check that the skin name is not magic or a direct
    965      * directory path
    966      */
    967     if (skinName != NULL && _getSkinPathFromName(i, skinName)) {
    968         AFREE(skinName);
    969         return 0;
    970     }
    971 
    972     /* if not, the default skinName is "HVGA" */
    973     if (skinName == NULL) {
    974         skinName = ASTRDUP(SKIN_DEFAULT);
    975         explicitSkin = 0;
    976     }
    977 
    978     i->skinName = skinName;
    979 
    980     /* now try to find the skin directory for that name -
    981      * first try the content directory */
    982     do {
    983         /* if there is a single 'skin' directory in
    984          * the content directory, assume that's what the
    985          * user wants,  unless an explicit name was given
    986          */
    987         if (!explicitSkin) {
    988             p = bufprint(temp, end, "%s/skin", i->contentPath);
    989             if (p < end && _checkSkinPath(temp)) {
    990                 D("using skin content from %s", temp);
    991                 AFREE(i->skinName);
    992                 i->skinName    = ASTRDUP("skin");
    993                 i->skinDirPath = ASTRDUP(i->contentPath);
    994                 return 0;
    995             }
    996         }
    997 
    998         /* look in content directory */
    999         if (_checkSkinDir(temp, end, i->contentPath, skinName))
   1000             break;
   1001 
   1002         /* look in the search paths. For each <dir> in the list,
   1003          * look the skins in <dir>/.. */
   1004         {
   1005             int  nn;
   1006             for (nn = 0; nn < i->numSearchPaths; nn++) {
   1007                 char*  parentDir = path_parent(i->searchPaths[nn], 1);
   1008                 int    ret;
   1009                 if (parentDir == NULL)
   1010                     continue;
   1011                 ret=_checkSkinDir(temp, end, parentDir, skinName);
   1012                 AFREE(parentDir);
   1013                 if (ret)
   1014                   break;
   1015             }
   1016             if (nn < i->numSearchPaths)
   1017                 break;
   1018         }
   1019 
   1020         /* didn't find it */
   1021         if (explicitSkin) {
   1022             derror("could not find directory for skin '%s',"
   1023                    " please use a different name", skinName);
   1024             exit(2);
   1025         } else {
   1026             dwarning("no skin directory matched '%s', so reverted to default",
   1027                      skinName);
   1028             AFREE(i->skinName);
   1029             params->skinName = SKIN_DEFAULT;
   1030             return _getSkin(i, params);
   1031         }
   1032 
   1033         return -1;
   1034 
   1035     } while (0);
   1036 
   1037     /* separate skin name from parent directory. the skin name
   1038      * returned in 'temp' might be different from the original
   1039      * one due to alias expansion so strip it.
   1040      */
   1041     AFREE(i->skinName);
   1042 
   1043     if (path_split(temp, &i->skinDirPath, &i->skinName) < 0) {
   1044         derror("weird skin path: %s", temp);
   1045         return -1;
   1046     }
   1047     DD("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
   1048     return 0;
   1049 }
   1050 
   1051 /* If the user didn't explicitely provide an SD Card path,
   1052  * check the SDCARD_PATH key in config.ini and use that if
   1053  * available.
   1054  */
   1055 static void
   1056 _getSDCardPath( AvdInfo*  i, AvdInfoParams*  params )
   1057 {
   1058     const char*  path;
   1059 
   1060     if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL)
   1061         return;
   1062 
   1063     path = iniFile_getString(i->configIni, SDCARD_PATH);
   1064     if (path == NULL)
   1065         return;
   1066 
   1067     params->forcePaths[AVD_IMAGE_SDCARD] = path;
   1068 }
   1069 
   1070 AvdInfo*
   1071 avdInfo_new( const char*  name, AvdInfoParams*  params )
   1072 {
   1073     AvdInfo*  i;
   1074 
   1075     if (name == NULL)
   1076         return NULL;
   1077 
   1078     if (!_checkAvdName(name)) {
   1079         derror("virtual device name contains invalid characters");
   1080         exit(1);
   1081     }
   1082 
   1083     ANEW0(i);
   1084     i->deviceName = ASTRDUP(name);
   1085 
   1086     if ( _getSdkRoot(i)     < 0 ||
   1087          _getRootIni(i)     < 0 ||
   1088          _getContentPath(i) < 0 ||
   1089          _getConfigIni(i)   < 0 )
   1090         goto FAIL;
   1091 
   1092     /* look for image search paths. handle post 1.1/pre cupcake
   1093      * obsolete SDKs.
   1094      */
   1095     _getSearchPaths(i);
   1096     _getSDCardPath(i, params);
   1097 
   1098     /* don't need this anymore */
   1099     iniFile_free(i->rootIni);
   1100     i->rootIni = NULL;
   1101 
   1102     if ( _getImagePaths(i, params) < 0 ||
   1103          _getSkin      (i, params) < 0 )
   1104         goto FAIL;
   1105 
   1106     return i;
   1107 
   1108 FAIL:
   1109     avdInfo_free(i);
   1110     return NULL;
   1111 }
   1112 
   1113 /***************************************************************
   1114  ***************************************************************
   1115  *****
   1116  *****    ANDROID BUILD SUPPORT
   1117  *****
   1118  *****    The code below corresponds to the case where we're
   1119  *****    starting the emulator inside the Android build
   1120  *****    system. The main differences are that:
   1121  *****
   1122  *****    - the $ANDROID_PRODUCT_OUT directory is used as the
   1123  *****      content file.
   1124  *****
   1125  *****    - built images must not be modified by the emulator,
   1126  *****      so system.img must be copied to a temporary file
   1127  *****      and userdata.img must be copied to userdata-qemu.img
   1128  *****      if the latter doesn't exist.
   1129  *****
   1130  *****    - the kernel and default skin directory are taken from
   1131  *****      prebuilt
   1132  *****
   1133  *****    - there is no root .ini file, or any config.ini in
   1134  *****      the content directory, no SDK images search path.
   1135  *****/
   1136 
   1137 /* used to fake a config.ini located in the content directory */
   1138 static int
   1139 _getBuildConfigIni( AvdInfo*  i )
   1140 {
   1141     /* a blank file is ok at the moment */
   1142     i->configIni = iniFile_newFromMemory( "", 0 );
   1143     return 0;
   1144 }
   1145 
   1146 static int
   1147 _getBuildImagePaths( AvdInfo*  i, AvdInfoParams*  params )
   1148 {
   1149     int   wipeData  = (params->flags & AVDINFO_WIPE_DATA) != 0;
   1150     int   noCache   = (params->flags & AVDINFO_NO_CACHE) != 0;
   1151     int   noSdCard  = (params->flags & AVDINFO_NO_SDCARD) != 0;
   1152 
   1153     char         temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
   1154     char*        srcData;
   1155     ImageLoader  l[1];
   1156 
   1157     imageLoader_init(l, i, params);
   1158 
   1159     /** load the kernel image
   1160      **/
   1161 
   1162     /* if it is not in the out directory, get it from prebuilt
   1163      */
   1164     imageLoader_set ( l, AVD_IMAGE_KERNEL );
   1165 
   1166     if ( !imageLoader_load( l, IMAGE_OPTIONAL |
   1167                                IMAGE_DONT_LOCK ) )
   1168     {
   1169 #define  PREBUILT_KERNEL_PATH   "prebuilt/android-arm/kernel/kernel-qemu"
   1170         p = bufprint(temp, end, "%s/%s", i->androidBuildRoot,
   1171                         PREBUILT_KERNEL_PATH);
   1172         if (p >= end || !path_exists(temp)) {
   1173             derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
   1174             exit(1);
   1175         }
   1176         imageLoader_setPath(l, temp);
   1177     }
   1178 
   1179     /** load the data partition. note that we use userdata-qemu.img
   1180      ** since we don't want to modify userdata.img at all
   1181      **/
   1182     imageLoader_set ( l, AVD_IMAGE_USERDATA );
   1183     imageLoader_load( l, IMAGE_OPTIONAL | IMAGE_DONT_LOCK );
   1184 
   1185     /* get the path of the source file, and check that it actually exists
   1186      * if the user didn't provide an explicit data file
   1187      */
   1188     srcData = imageLoader_extractPath(l);
   1189     if (srcData == NULL && params->forcePaths[AVD_IMAGE_USERDATA] == NULL) {
   1190         derror("There is no %s image in your build directory. Please make a full build",
   1191                 l->imageText, l->imageFile);
   1192         exit(2);
   1193     }
   1194 
   1195     /* get the path of the target file */
   1196     l->imageFile = "userdata-qemu.img";
   1197     imageLoader_load( l, IMAGE_OPTIONAL |
   1198                          IMAGE_EMPTY_IF_MISSING |
   1199                          IMAGE_IGNORE_IF_LOCKED );
   1200 
   1201     /* force a data wipe if we just created the image */
   1202     if (l->pState[0] == IMAGE_STATE_LOCKED_EMPTY)
   1203         wipeData = 1;
   1204 
   1205     /* if the image was already locked, create a temp file
   1206      * then force a data wipe.
   1207      */
   1208     if (l->pPath[0] == NULL) {
   1209         TempFile*  temp = tempfile_create();
   1210         imageLoader_setPath(l, tempfile_path(temp));
   1211         dwarning( "Another emulator is running. user data changes will *NOT* be saved");
   1212         wipeData = 1;
   1213     }
   1214 
   1215     /* in the case of a data wipe, copy userdata.img into
   1216      * the destination */
   1217     if (wipeData) {
   1218         if (srcData == NULL || !path_exists(srcData)) {
   1219             derror("There is no %s image in your build directory. Please make a full build",
   1220                    l->imageText, _imageFileNames[l->id]);
   1221             exit(2);
   1222         }
   1223         if (path_copy_file( l->pPath[0], srcData ) < 0) {
   1224             derror("could not initialize %s image from %s: %s",
   1225                    l->imageText, temp, strerror(errno));
   1226             exit(2);
   1227         }
   1228     }
   1229 
   1230     AFREE(srcData);
   1231 
   1232     /** load the ramdisk image
   1233      **/
   1234     imageLoader_set ( l, AVD_IMAGE_RAMDISK );
   1235     imageLoader_load( l, IMAGE_REQUIRED |
   1236                          IMAGE_DONT_LOCK );
   1237 
   1238     /** load the system image. read-only. the caller must
   1239      ** take care of checking the state
   1240      **/
   1241     imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
   1242     imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK );
   1243 
   1244     /* force the system image to read-only status */
   1245     l->pState[0] = IMAGE_STATE_READONLY;
   1246 
   1247     /** cache partition handling
   1248      **/
   1249     if (!noCache) {
   1250         imageLoader_set (l, AVD_IMAGE_CACHE);
   1251 
   1252         /* if the user provided one cache image, lock & use it */
   1253         if ( params->forcePaths[l->id] != NULL ) {
   1254             imageLoader_load(l, IMAGE_REQUIRED |
   1255                                 IMAGE_IGNORE_IF_LOCKED);
   1256         }
   1257     }
   1258 
   1259     /** SD Card image
   1260      **/
   1261     if (!noSdCard) {
   1262         imageLoader_set (l, AVD_IMAGE_SDCARD);
   1263         imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED);
   1264     }
   1265 
   1266     return 0;
   1267 }
   1268 
   1269 static int
   1270 _getBuildSkin( AvdInfo*  i, AvdInfoParams*  params )
   1271 {
   1272     /* the (current) default skin name for our build system */
   1273     const char*  skinName = params->skinName;
   1274     const char*  skinDir  = params->skinRootPath;
   1275     char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
   1276     char*        q;
   1277 
   1278     if (!skinName) {
   1279         /* the (current) default skin name for the build system */
   1280         skinName = SKIN_DEFAULT;
   1281         D("selecting default skin name '%s'", skinName);
   1282     }
   1283 
   1284     i->skinName = ASTRDUP(skinName);
   1285 
   1286     if (!skinDir) {
   1287 
   1288 #define  PREBUILT_SKINS_DIR  "sdk/emulator/skins"
   1289 
   1290         do {
   1291             /* try in <sysdir>/../skins first */
   1292             p = bufprint( temp, end, "%s/../skins",
   1293                           i->androidBuildRoot );
   1294             if (path_exists(temp))
   1295                 break;
   1296 
   1297             /* the (current) default skin directory */
   1298             p = bufprint( temp, end, "%s/%s",
   1299                         i->androidBuildRoot, PREBUILT_SKINS_DIR );
   1300         } while (0);
   1301 
   1302     } else {
   1303         p = bufprint( temp, end, "%s", skinDir );
   1304     }
   1305 
   1306     q  = bufprint(p, end, "/%s/layout", skinName);
   1307     if (q >= end || !path_exists(temp)) {
   1308         DD("skin content directory does not exist: %s", temp);
   1309         if (skinDir)
   1310             dwarning("could not find valid skin '%s' in %s:\n",
   1311                      skinName, temp);
   1312         return -1;
   1313     }
   1314     *p = 0;
   1315     DD("found skin path: %s", temp);
   1316     i->skinDirPath = ASTRDUP(temp);
   1317 
   1318     return 0;
   1319 }
   1320 
   1321 /* Read a hardware.ini if it is located in the skin directory */
   1322 static int
   1323 _getBuildHardwareIni( AvdInfo*  i )
   1324 {
   1325     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
   1326 
   1327     if (i->skinDirPath == NULL || i->skinName == NULL)
   1328         return 0;
   1329 
   1330     p = bufprint(temp, end, "%s/%s/hardware.ini", i->skinDirPath, i->skinName);
   1331     if (p >= end || !path_exists(temp)) {
   1332         DD("no skin-specific hardware.ini in %s", i->skinDirPath);
   1333         return 0;
   1334     }
   1335 
   1336     D("found skin-specific hardware.ini: %s", temp);
   1337     i->hardwareIni = iniFile_newFromFile(temp);
   1338     if (i->hardwareIni == NULL)
   1339         return -1;
   1340 
   1341     return 0;
   1342 }
   1343 
   1344 
   1345 AvdInfo*
   1346 avdInfo_newForAndroidBuild( const char*     androidBuildRoot,
   1347                             const char*     androidOut,
   1348                             AvdInfoParams*  params )
   1349 {
   1350     AvdInfo*  i;
   1351 
   1352     ANEW0(i);
   1353 
   1354     i->inAndroidBuild   = 1;
   1355     i->androidBuildRoot = ASTRDUP(androidBuildRoot);
   1356     i->androidOut       = ASTRDUP(androidOut);
   1357     i->contentPath      = ASTRDUP(androidOut);
   1358 
   1359     /* TODO: find a way to provide better information from the build files */
   1360     i->deviceName = ASTRDUP("<build>");
   1361 
   1362     if (_getBuildConfigIni(i)          < 0 ||
   1363         _getBuildImagePaths(i, params) < 0 )
   1364         goto FAIL;
   1365 
   1366     /* we don't need to fail if there is no valid skin */
   1367     _getBuildSkin(i, params);
   1368     _getBuildHardwareIni(i);
   1369 
   1370     return i;
   1371 
   1372 FAIL:
   1373     avdInfo_free(i);
   1374     return NULL;
   1375 }
   1376 
   1377 const char*
   1378 avdInfo_getName( AvdInfo*  i )
   1379 {
   1380     return i ? i->deviceName : NULL;
   1381 }
   1382 
   1383 const char*
   1384 avdInfo_getImageFile( AvdInfo*  i, AvdImageType  imageType )
   1385 {
   1386     if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
   1387         return NULL;
   1388 
   1389     return i->imagePath[imageType];
   1390 }
   1391 
   1392 uint64_t
   1393 avdInfo_getImageFileSize( AvdInfo*  i, AvdImageType  imageType )
   1394 {
   1395     const char* file = avdInfo_getImageFile(i, imageType);
   1396     uint64_t    size;
   1397 
   1398     if (file == NULL)
   1399         return 0ULL;
   1400 
   1401     if (path_get_size(file, &size) < 0)
   1402         return 0ULL;
   1403 
   1404     return size;
   1405 }
   1406 
   1407 int
   1408 avdInfo_isImageReadOnly( AvdInfo*  i, AvdImageType  imageType )
   1409 {
   1410     if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
   1411         return 1;
   1412 
   1413     return (i->imageState[imageType] == IMAGE_STATE_READONLY);
   1414 }
   1415 
   1416 const char*
   1417 avdInfo_getSkinName( AvdInfo*  i )
   1418 {
   1419     return i->skinName;
   1420 }
   1421 
   1422 const char*
   1423 avdInfo_getSkinDir ( AvdInfo*  i )
   1424 {
   1425     return i->skinDirPath;
   1426 }
   1427 
   1428 int
   1429 avdInfo_getHwConfig( AvdInfo*  i, AndroidHwConfig*  hw )
   1430 {
   1431     IniFile*   ini = i->configIni;
   1432     int        ret;
   1433 
   1434     if (ini == NULL)
   1435         ini = iniFile_newFromMemory("", 0);
   1436 
   1437     ret = androidHwConfig_read(hw, ini);
   1438 
   1439     if (ini != i->configIni)
   1440         iniFile_free(ini);
   1441 
   1442     if (ret == 0 && i->hardwareIni != NULL) {
   1443         ret = androidHwConfig_read(hw, i->hardwareIni);
   1444     }
   1445 
   1446     /* special product-specific hardware configuration */
   1447     if (i->androidOut != NULL)
   1448     {
   1449         char*  p = strrchr(i->androidOut, '/');
   1450         if (p != NULL && p[0] != 0) {
   1451             if (p[1] == 's') {
   1452                 hw->hw_keyboard = 0;
   1453             }
   1454         }
   1455     }
   1456 
   1457     return ret;
   1458 }
   1459 
   1460 const char*
   1461 avdInfo_getContentPath( AvdInfo*  i )
   1462 {
   1463     return i->contentPath;
   1464 }
   1465 
   1466 int
   1467 avdInfo_inAndroidBuild( AvdInfo*  i )
   1468 {
   1469     return i->inAndroidBuild;
   1470 }
   1471 
   1472 char*
   1473 avdInfo_getTracePath( AvdInfo*  i, const char*  traceName )
   1474 {
   1475     char   tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
   1476 
   1477     if (i == NULL || traceName == NULL || traceName[0] == 0)
   1478         return NULL;
   1479 
   1480     if (i->inAndroidBuild) {
   1481         p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
   1482                       i->androidOut, traceName );
   1483     } else {
   1484         p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
   1485                       i->contentPath, traceName );
   1486     }
   1487     return ASTRDUP(tmp);
   1488 }
   1489