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/avd/util.h"
     14 #include "android/avd/keys.h"
     15 #include "android/config/config.h"
     16 #include "android/utils/path.h"
     17 #include "android/utils/bufprint.h"
     18 #include "android/utils/filelock.h"
     19 #include "android/utils/tempfile.h"
     20 #include "android/utils/debug.h"
     21 #include "android/utils/dirscanner.h"
     22 #include <ctype.h>
     23 #include <stddef.h>
     24 #include <string.h>
     25 #include <stdlib.h>
     26 #include <stdio.h>
     27 #include <errno.h>
     28 
     29 /* global variables - see android/globals.h */
     30 AvdInfoParams   android_avdParams[1];
     31 AvdInfo*        android_avdInfo;
     32 
     33 /* for debugging */
     34 #define  D(...)   VERBOSE_PRINT(init,__VA_ARGS__)
     35 #define  DD(...)  VERBOSE_PRINT(avd_config,__VA_ARGS__)
     36 
     37 /* technical note on how all of this is supposed to work:
     38  *
     39  * Each AVD corresponds to a "content directory" that is used to
     40  * store persistent disk images and configuration files. Most remarkable
     41  * are:
     42  *
     43  * - a "config.ini" file used to hold configuration information for the
     44  *   AVD
     45  *
     46  * - mandatory user data image ("userdata-qemu.img") and cache image
     47  *   ("cache.img")
     48  *
     49  * - optional mutable system image ("system-qemu.img"), kernel image
     50  *   ("kernel-qemu") and read-only ramdisk ("ramdisk.img")
     51  *
     52  * When starting up an AVD, the emulator looks for relevant disk images
     53  * in the content directory. If it doesn't find a given image there, it
     54  * will try to search in the list of system directories listed in the
     55  * 'config.ini' file through one of the following (key,value) pairs:
     56  *
     57  *    images.sysdir.1 = <first search path>
     58  *    images.sysdir.2 = <second search path>
     59  *
     60  * The search paths can be absolute, or relative to the root SDK installation
     61  * path (which is determined from the emulator program's location, or from the
     62  * ANDROID_SDK_ROOT environment variable).
     63  *
     64  * Individual image disk search patch can be over-riden on the command-line
     65  * with one of the usual options.
     66  */
     67 
     68 /* the name of the .ini file that will contain the complete hardware
     69  * properties for the AVD. This will be used to launch the corresponding
     70  * core from the UI.
     71  */
     72 #define  CORE_HARDWARE_INI   "hardware-qemu.ini"
     73 
     74 /* certain disk image files are mounted read/write by the emulator
     75  * to ensure that several emulators referencing the same files
     76  * do not corrupt these files, we need to lock them and respond
     77  * to collision depending on the image type.
     78  *
     79  * the enumeration below is used to record information about
     80  * each image file path.
     81  *
     82  * READONLY means that the file will be mounted read-only
     83  * and this doesn't need to be locked. must be first in list
     84  *
     85  * MUSTLOCK means that the file should be locked before
     86  * being mounted by the emulator
     87  *
     88  * TEMPORARY means that the file has been copied to a
     89  * temporary image, which can be mounted read/write
     90  * but doesn't require locking.
     91  */
     92 typedef enum {
     93     IMAGE_STATE_READONLY,     /* unlocked */
     94     IMAGE_STATE_MUSTLOCK,     /* must be locked */
     95     IMAGE_STATE_LOCKED,       /* locked */
     96     IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
     97     IMAGE_STATE_TEMPORARY,    /* copied to temp file (no lock needed) */
     98 } AvdImageState;
     99 
    100 struct AvdInfo {
    101     /* for the Android build system case */
    102     char      inAndroidBuild;
    103     char*     androidOut;
    104     char*     androidBuildRoot;
    105     char*     targetArch;
    106 
    107     /* for the normal virtual device case */
    108     char*     deviceName;
    109     char*     sdkRootPath;
    110     char      sdkRootPathFromEnv;
    111     char*     searchPaths[ MAX_SEARCH_PATHS ];
    112     int       numSearchPaths;
    113     char*     contentPath;
    114     IniFile*  rootIni;      /* root <foo>.ini file, empty if missing */
    115     IniFile*  configIni;    /* virtual device's config.ini, NULL if missing */
    116     IniFile*  skinHardwareIni;  /* skin-specific hardware.ini */
    117 
    118     /* for both */
    119     int       apiLevel;
    120     char*     skinName;     /* skin name */
    121     char*     skinDirPath;  /* skin directory */
    122     char*     coreHardwareIniPath;  /* core hardware.ini path */
    123 
    124     /* image files */
    125     char*     imagePath [ AVD_IMAGE_MAX ];
    126     char      imageState[ AVD_IMAGE_MAX ];
    127 };
    128 
    129 
    130 void
    131 avdInfo_free( AvdInfo*  i )
    132 {
    133     if (i) {
    134         int  nn;
    135 
    136         for (nn = 0; nn < AVD_IMAGE_MAX; nn++)
    137             AFREE(i->imagePath[nn]);
    138 
    139         AFREE(i->skinName);
    140         AFREE(i->skinDirPath);
    141         AFREE(i->coreHardwareIniPath);
    142 
    143         for (nn = 0; nn < i->numSearchPaths; nn++)
    144             AFREE(i->searchPaths[nn]);
    145 
    146         i->numSearchPaths = 0;
    147 
    148         if (i->configIni) {
    149             iniFile_free(i->configIni);
    150             i->configIni = NULL;
    151         }
    152 
    153         if (i->skinHardwareIni) {
    154             iniFile_free(i->skinHardwareIni);
    155             i->skinHardwareIni = NULL;
    156         }
    157 
    158         if (i->rootIni) {
    159             iniFile_free(i->rootIni);
    160             i->rootIni = NULL;
    161         }
    162 
    163         AFREE(i->contentPath);
    164         AFREE(i->sdkRootPath);
    165 
    166         if (i->inAndroidBuild) {
    167             AFREE(i->androidOut);
    168             AFREE(i->androidBuildRoot);
    169         }
    170 
    171         AFREE(i->deviceName);
    172         AFREE(i);
    173     }
    174 }
    175 
    176 /* list of default file names for each supported image file type */
    177 static const char*  const  _imageFileNames[ AVD_IMAGE_MAX ] = {
    178 #define  _AVD_IMG(x,y,z)  y,
    179     AVD_IMAGE_LIST
    180 #undef _AVD_IMG
    181 };
    182 
    183 /* list of short text description for each supported image file type */
    184 static const char*  const _imageFileText[ AVD_IMAGE_MAX ] = {
    185 #define  _AVD_IMG(x,y,z)  z,
    186     AVD_IMAGE_LIST
    187 #undef _AVD_IMG
    188 };
    189 
    190 /***************************************************************
    191  ***************************************************************
    192  *****
    193  *****    UTILITY FUNCTIONS
    194  *****
    195  *****  The following functions do not depend on the AvdInfo
    196  *****  structure and could easily be moved elsewhere.
    197  *****
    198  *****/
    199 
    200 /* Parse a given config.ini file and extract the list of SDK search paths
    201  * from it. Returns the number of valid paths stored in 'searchPaths', or -1
    202  * in case of problem.
    203  *
    204  * Relative search paths in the config.ini will be stored as full pathnames
    205  * relative to 'sdkRootPath'.
    206  *
    207  * 'searchPaths' must be an array of char* pointers of at most 'maxSearchPaths'
    208  * entries.
    209  */
    210 static int
    211 _getSearchPaths( IniFile*    configIni,
    212                  const char* sdkRootPath,
    213                  int         maxSearchPaths,
    214                  char**      searchPaths )
    215 {
    216     char  temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
    217     int   nn, count = 0;
    218 
    219     for (nn = 0; nn < maxSearchPaths; nn++) {
    220         char*  path;
    221 
    222         p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
    223         if (p >= end)
    224             continue;
    225 
    226         path = iniFile_getString(configIni, temp, NULL);
    227         if (path != NULL) {
    228             DD("    found image search path: %s", path);
    229             if (!path_is_absolute(path)) {
    230                 p = bufprint(temp, end, "%s/%s", sdkRootPath, path);
    231                 AFREE(path);
    232                 path = ASTRDUP(temp);
    233             }
    234             searchPaths[count++] = path;
    235         }
    236     }
    237     return count;
    238 }
    239 
    240 /* Check that an AVD name is valid. Returns 1 on success, 0 otherwise.
    241  */
    242 static int
    243 _checkAvdName( const char*  name )
    244 {
    245     int  len  = strlen(name);
    246     int  len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    247                              "abcdefghijklmnopqrstuvwxyz"
    248                              "0123456789_.-");
    249     return (len == len2);
    250 }
    251 
    252 /* Returns the full path of a given file.
    253  *
    254  * If 'fileName' is an absolute path, this returns a simple copy.
    255  * Otherwise, this returns a new string corresponding to <rootPath>/<fileName>
    256  *
    257  * This returns NULL if the paths are too long.
    258  */
    259 static char*
    260 _getFullFilePath( const char* rootPath, const char* fileName )
    261 {
    262     if (path_is_absolute(fileName)) {
    263         return ASTRDUP(fileName);
    264     } else {
    265         char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    266 
    267         p = bufprint(temp, end, "%s/%s", rootPath, fileName);
    268         if (p >= end) {
    269             return NULL;
    270         }
    271         return ASTRDUP(temp);
    272     }
    273 }
    274 
    275 /* check that a given directory contains a valid skin.
    276  * returns 1 on success, 0 on failure.
    277  */
    278 static int
    279 _checkSkinPath( const char*  skinPath )
    280 {
    281     char  temp[MAX_PATH], *p=temp, *end=p+sizeof(temp);
    282 
    283     /* for now, if it has a 'layout' file, it is a valid skin path */
    284     p = bufprint(temp, end, "%s/layout", skinPath);
    285     if (p >= end || !path_exists(temp))
    286         return 0;
    287 
    288     return 1;
    289 }
    290 
    291 /* Check that there is a skin named 'skinName' listed from 'skinDirRoot'
    292  * this returns the full path of the skin directory (after alias expansions),
    293  * including the skin name, or NULL on failure.
    294  */
    295 static char*
    296 _checkSkinSkinsDir( const char*  skinDirRoot,
    297                     const char*  skinName )
    298 {
    299     DirScanner*  scanner;
    300     char*        result;
    301     char         temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
    302 
    303     p = bufprint(temp, end, "%s/skins/%s", skinDirRoot, skinName);
    304     DD("Probing skin directory: %s", temp);
    305     if (p >= end || !path_exists(temp)) {
    306         DD("    ignore bad skin directory %s", temp);
    307         return NULL;
    308     }
    309 
    310     /* first, is this a normal skin directory ? */
    311     if (_checkSkinPath(temp)) {
    312         /* yes */
    313         DD("    found skin directory: %s", temp);
    314         return ASTRDUP(temp);
    315     }
    316 
    317     /* second, is it an alias to another skin ? */
    318     *p      = 0;
    319     result  = NULL;
    320     scanner = dirScanner_new(temp);
    321     if (scanner != NULL) {
    322         for (;;) {
    323             const char*  file = dirScanner_next(scanner);
    324 
    325             if (file == NULL)
    326                 break;
    327 
    328             if (strncmp(file, "alias-", 6) || file[6] == 0)
    329                 continue;
    330 
    331             p = bufprint(temp, end, "%s/skins/%s", skinDirRoot, file+6);
    332             if (p < end && _checkSkinPath(temp)) {
    333                 /* yes, it's an alias */
    334                 DD("    skin alias '%s' points to skin directory: %s",
    335                    file+6, temp);
    336                 result = ASTRDUP(temp);
    337                 break;
    338             }
    339         }
    340         dirScanner_free(scanner);
    341     }
    342     return result;
    343 }
    344 
    345 /* try to see if the skin name leads to a magic skin or skin path directly
    346  * returns 1 on success, 0 on error.
    347  *
    348  * on success, this sets up '*pSkinName' and '*pSkinDir'
    349  */
    350 static int
    351 _getSkinPathFromName( const char*  skinName,
    352                       const char*  sdkRootPath,
    353                       char**       pSkinName,
    354                       char**       pSkinDir )
    355 {
    356     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    357 
    358     /* if the skin name has the format 'NNNNxNNN' where
    359     * NNN is a decimal value, then this is a 'magic' skin
    360     * name that doesn't require a skin directory
    361     */
    362     if (isdigit(skinName[0])) {
    363         int  width, height;
    364         if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
    365             D("'magic' skin format detected: %s", skinName);
    366             *pSkinName = ASTRDUP(skinName);
    367             *pSkinDir  = NULL;
    368             return 1;
    369         }
    370     }
    371 
    372     /* is the skin name a direct path to the skin directory ? */
    373     if (path_is_absolute(skinName) && _checkSkinPath(skinName)) {
    374         goto FOUND_IT;
    375     }
    376 
    377     /* is the skin name a relative path from the SDK root ? */
    378     p = bufprint(temp, end, "%s/%s", sdkRootPath, skinName);
    379     if (p < end && _checkSkinPath(temp)) {
    380         skinName = temp;
    381         goto FOUND_IT;
    382     }
    383 
    384     /* nope */
    385     return 0;
    386 
    387 FOUND_IT:
    388     if (path_split(skinName, pSkinDir, pSkinName) < 0) {
    389         derror("malformed skin name: %s", skinName);
    390         exit(2);
    391     }
    392     D("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
    393     return 1;
    394 }
    395 
    396 /***************************************************************
    397  ***************************************************************
    398  *****
    399  *****    NORMAL VIRTUAL DEVICE SUPPORT
    400  *****
    401  *****/
    402 
    403 /* compute path to the root SDK directory
    404  * assume we are in $SDKROOT/tools/emulator[.exe]
    405  */
    406 static int
    407 _avdInfo_getSdkRoot( AvdInfo*  i )
    408 {
    409 
    410     i->sdkRootPath = path_getSdkRoot(&i->sdkRootPathFromEnv);
    411     if (i->sdkRootPath == NULL)
    412         return -1;
    413 
    414     return 0;
    415 }
    416 
    417 /* parse the root config .ini file. it is located in
    418  * ~/.android/avd/<name>.ini or Windows equivalent
    419  */
    420 static int
    421 _avdInfo_getRootIni( AvdInfo*  i )
    422 {
    423     char*  iniPath = path_getRootIniPath( i->deviceName );
    424 
    425     if (iniPath == NULL) {
    426         derror("unknown virtual device name: '%s'", i->deviceName);
    427         return -1;
    428     }
    429 
    430     D("Android virtual device file at: %s", iniPath);
    431 
    432     i->rootIni = iniFile_newFromFile(iniPath);
    433     AFREE(iniPath);
    434 
    435     if (i->rootIni == NULL) {
    436         derror("Corrupt virtual device config file!");
    437         return -1;
    438     }
    439     return 0;
    440 }
    441 
    442 /* Returns the AVD's content path, i.e. the directory that contains
    443  * the AVD's content files (e.g. data partition, cache, sd card, etc...).
    444  *
    445  * We extract this by parsing the root config .ini file, looking for
    446  * a "path" elements.
    447  */
    448 static int
    449 _avdInfo_getContentPath( AvdInfo*  i )
    450 {
    451     char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    452 
    453     i->contentPath = iniFile_getString(i->rootIni, ROOT_ABS_PATH_KEY, NULL);
    454 
    455     if (i->contentPath == NULL) {
    456         derror("bad config: %s",
    457                "virtual device file lacks a "ROOT_ABS_PATH_KEY" entry");
    458         return -1;
    459     }
    460 
    461     if (!path_is_dir(i->contentPath)) {
    462         // If the absolute path doesn't match an actual directory, try
    463         // the relative path if present.
    464         const char* relPath = iniFile_getString(i->rootIni, ROOT_REL_PATH_KEY, NULL);
    465         if (relPath != NULL) {
    466             p = bufprint_config_path(temp, end);
    467             p = bufprint(p, end, PATH_SEP "%s", relPath);
    468             if (p < end && path_is_dir(temp)) {
    469                 AFREE(i->contentPath);
    470                 i->contentPath = ASTRDUP(temp);
    471             }
    472         }
    473     }
    474 
    475     D("virtual device content at %s", i->contentPath);
    476     return 0;
    477 }
    478 
    479 static int
    480 _avdInfo_getApiLevel( AvdInfo*  i )
    481 {
    482     char*       target;
    483     const char* p;
    484     const int   defaultLevel = 1000;
    485     int         level        = defaultLevel;
    486 
    487 #    define ROOT_TARGET_KEY   "target"
    488 
    489     target = iniFile_getString(i->rootIni, ROOT_TARGET_KEY, NULL);
    490     if (target == NULL) {
    491         D("No target field in root AVD .ini file?");
    492         D("Defaulting to API level %d", level);
    493         return level;
    494     }
    495 
    496     DD("Found target field in root AVD .ini file: '%s'", target);
    497 
    498     /* There are two acceptable formats for the target key.
    499      *
    500      * 1/  android-<level>
    501      * 2/  <vendor-name>:<add-on-name>:<level>
    502      *
    503      * Where <level> can be either a _name_ (for experimental/preview SDK builds)
    504      * or a decimal number. Note that if a _name_, it can start with a digit.
    505      */
    506 
    507     /* First, extract the level */
    508     if (!memcmp(target, "android-", 8))
    509         p = target + 8;
    510     else {
    511         /* skip two columns */
    512         p = strchr(target, ':');
    513         if (p != NULL) {
    514             p = strchr(p+1, ':');
    515             if (p != NULL)
    516                 p += 1;
    517         }
    518     }
    519     if (p == NULL || !isdigit(*p)) {
    520         goto NOT_A_NUMBER;
    521     } else {
    522         char* end;
    523         long  val = strtol(p, &end, 10);
    524         if (end == NULL || *end != '\0' || val != (int)val) {
    525             goto NOT_A_NUMBER;
    526         }
    527         level = (int)val;
    528 
    529         /* Sanity check, we don't support anything prior to Android 1.5 */
    530         if (level < 3)
    531             level = 3;
    532 
    533         D("Found AVD target API level: %d", level);
    534     }
    535 EXIT:
    536     AFREE(target);
    537     return level;
    538 
    539 NOT_A_NUMBER:
    540     if (p == NULL) {
    541         D("Invalid target field in root AVD .ini file");
    542     } else {
    543         D("Target AVD api level is not a number");
    544     }
    545     D("Defaulting to API level %d", level);
    546     goto EXIT;
    547 }
    548 
    549 /* Look for a named file inside the AVD's content directory.
    550  * Returns NULL if it doesn't exist, or a strdup() copy otherwise.
    551  */
    552 static char*
    553 _avdInfo_getContentFilePath(AvdInfo*  i, const char* fileName)
    554 {
    555     char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
    556 
    557     p = bufprint(p, end, "%s/%s", i->contentPath, fileName);
    558     if (p >= end) {
    559         derror("can't access virtual device content directory");
    560         return NULL;
    561     }
    562     if (!path_exists(temp)) {
    563         return NULL;
    564     }
    565     return ASTRDUP(temp);
    566 }
    567 
    568 /* find and parse the config.ini file from the content directory */
    569 static int
    570 _avdInfo_getConfigIni(AvdInfo*  i)
    571 {
    572     char*  iniPath = _avdInfo_getContentFilePath(i, "config.ini");
    573 
    574     /* Allow non-existing config.ini */
    575     if (iniPath == NULL) {
    576         D("virtual device has no config file - no problem");
    577         return 0;
    578     }
    579 
    580     D("virtual device config file: %s", iniPath);
    581     i->configIni = iniFile_newFromFile(iniPath);
    582     AFREE(iniPath);
    583 
    584     if (i->configIni == NULL) {
    585         derror("bad config: %s",
    586                "virtual device has corrupted config.ini");
    587         return -1;
    588     }
    589     return 0;
    590 }
    591 
    592 /* The AVD's config.ini contains a list of search paths (all beginning
    593  * with SEARCH_PREFIX) which are directory locations searched for
    594  * AVD platform files.
    595  */
    596 static void
    597 _avdInfo_getSearchPaths( AvdInfo*  i )
    598 {
    599     if (i->configIni == NULL)
    600         return;
    601 
    602     i->numSearchPaths = _getSearchPaths( i->configIni,
    603                                          i->sdkRootPath,
    604                                          MAX_SEARCH_PATHS,
    605                                          i->searchPaths );
    606     if (i->numSearchPaths == 0) {
    607         derror("no search paths found in this AVD's configuration.\n"
    608                "Weird, the AVD's config.ini file is malformed. Try re-creating it.\n");
    609         exit(2);
    610     }
    611     else
    612         DD("found a total of %d search paths for this AVD", i->numSearchPaths);
    613 }
    614 
    615 /* Search a file in the SDK search directories. Return NULL if not found,
    616  * or a strdup() otherwise.
    617  */
    618 static char*
    619 _avdInfo_getSdkFilePath(AvdInfo*  i, const char*  fileName)
    620 {
    621     char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
    622 
    623     do {
    624         /* try the search paths */
    625         int  nn;
    626 
    627         for (nn = 0; nn < i->numSearchPaths; nn++) {
    628             const char* searchDir = i->searchPaths[nn];
    629 
    630             p = bufprint(temp, end, "%s/%s", searchDir, fileName);
    631             if (p < end && path_exists(temp)) {
    632                 DD("found %s in search dir: %s", fileName, searchDir);
    633                 goto FOUND;
    634             }
    635             DD("    no %s in search dir: %s", fileName, searchDir);
    636         }
    637 
    638         return NULL;
    639 
    640     } while (0);
    641 
    642 FOUND:
    643     return ASTRDUP(temp);
    644 }
    645 
    646 /* Search for a file in the content directory, and if not found, in the
    647  * SDK search directory. Returns NULL if not found.
    648  */
    649 static char*
    650 _avdInfo_getContentOrSdkFilePath(AvdInfo*  i, const char*  fileName)
    651 {
    652     char*  path;
    653 
    654     path = _avdInfo_getContentFilePath(i, fileName);
    655     if (path)
    656         return path;
    657 
    658     path = _avdInfo_getSdkFilePath(i, fileName);
    659     if (path)
    660         return path;
    661 
    662     return NULL;
    663 }
    664 
    665 #if 0
    666 static int
    667 _avdInfo_findContentOrSdkImage(AvdInfo* i, AvdImageType id)
    668 {
    669     const char* fileName = _imageFileNames[id];
    670     char*       path     = _avdInfo_getContentOrSdkFilePath(i, fileName);
    671 
    672     i->imagePath[id]  = path;
    673     i->imageState[id] = IMAGE_STATE_READONLY;
    674 
    675     if (path == NULL)
    676         return -1;
    677     else
    678         return 0;
    679 }
    680 #endif
    681 
    682 /* Returns path to the core hardware .ini file. This contains the
    683  * hardware configuration that is read by the core. The content of this
    684  * file is auto-generated before launching a core, but we need to know
    685  * its path before that.
    686  */
    687 static int
    688 _avdInfo_getCoreHwIniPath( AvdInfo* i, const char* basePath )
    689 {
    690     i->coreHardwareIniPath = _getFullFilePath(basePath, CORE_HARDWARE_INI);
    691     if (i->coreHardwareIniPath == NULL) {
    692         DD("Path too long for %s: %s", CORE_HARDWARE_INI, basePath);
    693         return -1;
    694     }
    695     D("using core hw config path: %s", i->coreHardwareIniPath);
    696     return 0;
    697 }
    698 
    699 AvdInfo*
    700 avdInfo_new( const char*  name, AvdInfoParams*  params )
    701 {
    702     AvdInfo*  i;
    703 
    704     if (name == NULL)
    705         return NULL;
    706 
    707     if (!_checkAvdName(name)) {
    708         derror("virtual device name contains invalid characters");
    709         exit(1);
    710     }
    711 
    712     ANEW0(i);
    713     i->deviceName = ASTRDUP(name);
    714 
    715     if ( _avdInfo_getSdkRoot(i) < 0     ||
    716          _avdInfo_getRootIni(i) < 0     ||
    717          _avdInfo_getContentPath(i) < 0 ||
    718          _avdInfo_getConfigIni(i)   < 0 ||
    719          _avdInfo_getCoreHwIniPath(i, i->contentPath) < 0 )
    720         goto FAIL;
    721 
    722     i->apiLevel = _avdInfo_getApiLevel(i);
    723 
    724     /* look for image search paths. handle post 1.1/pre cupcake
    725      * obsolete SDKs.
    726      */
    727     _avdInfo_getSearchPaths(i);
    728 
    729     /* don't need this anymore */
    730     iniFile_free(i->rootIni);
    731     i->rootIni = NULL;
    732 
    733     return i;
    734 
    735 FAIL:
    736     avdInfo_free(i);
    737     return NULL;
    738 }
    739 
    740 /***************************************************************
    741  ***************************************************************
    742  *****
    743  *****    ANDROID BUILD SUPPORT
    744  *****
    745  *****    The code below corresponds to the case where we're
    746  *****    starting the emulator inside the Android build
    747  *****    system. The main differences are that:
    748  *****
    749  *****    - the $ANDROID_PRODUCT_OUT directory is used as the
    750  *****      content file.
    751  *****
    752  *****    - built images must not be modified by the emulator,
    753  *****      so system.img must be copied to a temporary file
    754  *****      and userdata.img must be copied to userdata-qemu.img
    755  *****      if the latter doesn't exist.
    756  *****
    757  *****    - the kernel and default skin directory are taken from
    758  *****      prebuilt
    759  *****
    760  *****    - there is no root .ini file, or any config.ini in
    761  *****      the content directory, no SDK images search path.
    762  *****/
    763 
    764 /* Read a hardware.ini if it is located in the skin directory */
    765 static int
    766 _avdInfo_getBuildSkinHardwareIni( AvdInfo*  i )
    767 {
    768     char* skinName;
    769     char* skinDirPath;
    770 
    771     avdInfo_getSkinInfo(i, &skinName, &skinDirPath);
    772     if (skinDirPath == NULL)
    773         return 0;
    774 
    775     int result = avdInfo_getSkinHardwareIni(i, skinName, skinDirPath);
    776 
    777     AFREE(skinName);
    778     AFREE(skinDirPath);
    779 
    780     return result;
    781 }
    782 
    783 int avdInfo_getSkinHardwareIni( AvdInfo* i, char* skinName, char* skinDirPath)
    784 {
    785     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    786 
    787     p = bufprint(temp, end, "%s/%s/hardware.ini", skinDirPath, skinName);
    788     if (p >= end || !path_exists(temp)) {
    789         DD("no skin-specific hardware.ini in %s", skinDirPath);
    790         return 0;
    791     }
    792 
    793     D("found skin-specific hardware.ini: %s", temp);
    794     if (i->skinHardwareIni != NULL)
    795         iniFile_free(i->skinHardwareIni);
    796     i->skinHardwareIni = iniFile_newFromFile(temp);
    797     if (i->skinHardwareIni == NULL)
    798         return -1;
    799 
    800     return 0;
    801 }
    802 
    803 AvdInfo*
    804 avdInfo_newForAndroidBuild( const char*     androidBuildRoot,
    805                             const char*     androidOut,
    806                             AvdInfoParams*  params )
    807 {
    808     AvdInfo*  i;
    809 
    810     ANEW0(i);
    811 
    812     i->inAndroidBuild   = 1;
    813     i->androidBuildRoot = ASTRDUP(androidBuildRoot);
    814     i->androidOut       = ASTRDUP(androidOut);
    815     i->contentPath      = ASTRDUP(androidOut);
    816     i->targetArch       = path_getBuildTargetArch(i->androidOut);
    817     i->apiLevel         = path_getBuildTargetApiLevel(i->androidOut);
    818 
    819     /* TODO: find a way to provide better information from the build files */
    820     i->deviceName = ASTRDUP("<build>");
    821 
    822     /* There is no config.ini in the build */
    823     i->configIni = NULL;
    824 
    825     if (_avdInfo_getCoreHwIniPath(i, i->androidOut) < 0 )
    826         goto FAIL;
    827 
    828     /* Read the build skin's hardware.ini, if any */
    829     _avdInfo_getBuildSkinHardwareIni(i);
    830 
    831     return i;
    832 
    833 FAIL:
    834     avdInfo_free(i);
    835     return NULL;
    836 }
    837 
    838 const char*
    839 avdInfo_getName( AvdInfo*  i )
    840 {
    841     return i ? i->deviceName : NULL;
    842 }
    843 
    844 const char*
    845 avdInfo_getImageFile( AvdInfo*  i, AvdImageType  imageType )
    846 {
    847     if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
    848         return NULL;
    849 
    850     return i->imagePath[imageType];
    851 }
    852 
    853 uint64_t
    854 avdInfo_getImageFileSize( AvdInfo*  i, AvdImageType  imageType )
    855 {
    856     const char* file = avdInfo_getImageFile(i, imageType);
    857     uint64_t    size;
    858 
    859     if (file == NULL)
    860         return 0ULL;
    861 
    862     if (path_get_size(file, &size) < 0)
    863         return 0ULL;
    864 
    865     return size;
    866 }
    867 
    868 int
    869 avdInfo_isImageReadOnly( AvdInfo*  i, AvdImageType  imageType )
    870 {
    871     if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
    872         return 1;
    873 
    874     return (i->imageState[imageType] == IMAGE_STATE_READONLY);
    875 }
    876 
    877 char*
    878 avdInfo_getKernelPath( AvdInfo*  i )
    879 {
    880     const char* imageName = _imageFileNames[ AVD_IMAGE_KERNEL ];
    881 
    882     char*  kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
    883 
    884     if (kernelPath == NULL && i->inAndroidBuild) {
    885         /* When in the Android build, look into the prebuilt directory
    886          * for our target architecture.
    887          */
    888         char temp[PATH_MAX], *p = temp, *end = p + sizeof(temp);
    889         const char* suffix = "";
    890         char* abi;
    891 
    892         /* If the target ABI is armeabi-v7a, then look for
    893          * kernel-qemu-armv7 instead of kernel-qemu in the prebuilt
    894          * directory. */
    895         abi = path_getBuildTargetAbi(i->androidOut);
    896         if (!strcmp(abi,"armeabi-v7a")) {
    897             suffix = "-armv7";
    898         }
    899         AFREE(abi);
    900 
    901         p = bufprint(temp, end, "%s/prebuilts/qemu-kernel/%s/kernel-qemu%s",
    902                      i->androidBuildRoot, i->targetArch, suffix);
    903         if (p >= end || !path_exists(temp)) {
    904             derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
    905             exit(1);
    906         }
    907         kernelPath = ASTRDUP(temp);
    908     }
    909     return kernelPath;
    910 }
    911 
    912 
    913 char*
    914 avdInfo_getRamdiskPath( AvdInfo* i )
    915 {
    916     const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ];
    917     return _avdInfo_getContentOrSdkFilePath(i, imageName);
    918 }
    919 
    920 char*  avdInfo_getCachePath( AvdInfo*  i )
    921 {
    922     const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
    923     return _avdInfo_getContentFilePath(i, imageName);
    924 }
    925 
    926 char*  avdInfo_getDefaultCachePath( AvdInfo*  i )
    927 {
    928     const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
    929     return _getFullFilePath(i->contentPath, imageName);
    930 }
    931 
    932 char*  avdInfo_getSdCardPath( AvdInfo* i )
    933 {
    934     const char* imageName = _imageFileNames[ AVD_IMAGE_SDCARD ];
    935     char*       path;
    936 
    937     /* Special case, the config.ini can have a SDCARD_PATH entry
    938      * that gives the full path to the SD Card.
    939      */
    940     if (i->configIni != NULL) {
    941         path = iniFile_getString(i->configIni, SDCARD_PATH, NULL);
    942         if (path != NULL) {
    943             if (path_exists(path))
    944                 return path;
    945 
    946             dwarning("Ignoring invalid SDCard path: %s", path);
    947             AFREE(path);
    948         }
    949     }
    950 
    951     /* Otherwise, simply look into the content directory */
    952     return _avdInfo_getContentFilePath(i, imageName);
    953 }
    954 
    955 char*
    956 avdInfo_getSnapStoragePath( AvdInfo* i )
    957 {
    958     const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ];
    959     return _avdInfo_getContentFilePath(i, imageName);
    960 }
    961 
    962 char*
    963 avdInfo_getSystemImagePath( AvdInfo*  i )
    964 {
    965     const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ];
    966     return _avdInfo_getContentFilePath(i, imageName);
    967 }
    968 
    969 char*
    970 avdInfo_getSystemInitImagePath( AvdInfo*  i )
    971 {
    972     const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ];
    973     return _avdInfo_getContentOrSdkFilePath(i, imageName);
    974 }
    975 
    976 char*
    977 avdInfo_getDataImagePath( AvdInfo*  i )
    978 {
    979     const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
    980     return _avdInfo_getContentFilePath(i, imageName);
    981 }
    982 
    983 char*
    984 avdInfo_getDefaultDataImagePath( AvdInfo*  i )
    985 {
    986     const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
    987     return _getFullFilePath(i->contentPath, imageName);
    988 }
    989 
    990 char*
    991 avdInfo_getDataInitImagePath( AvdInfo* i )
    992 {
    993     const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ];
    994     return _avdInfo_getContentOrSdkFilePath(i, imageName);
    995 }
    996 
    997 int
    998 avdInfo_initHwConfig( AvdInfo*  i, AndroidHwConfig*  hw )
    999 {
   1000     int  ret = 0;
   1001 
   1002     androidHwConfig_init(hw, i->apiLevel);
   1003 
   1004     /* First read the config.ini, if any */
   1005     if (i->configIni != NULL) {
   1006         ret = androidHwConfig_read(hw, i->configIni);
   1007     }
   1008 
   1009     /* The skin's hardware.ini can override values */
   1010     if (ret == 0 && i->skinHardwareIni != NULL) {
   1011         ret = androidHwConfig_read(hw, i->skinHardwareIni);
   1012     }
   1013 
   1014     /* Auto-disable keyboard emulation on sapphire platform builds */
   1015     if (i->androidOut != NULL) {
   1016         char*  p = strrchr(i->androidOut, '/');
   1017         if (p != NULL && !strcmp(p,"sapphire")) {
   1018             hw->hw_keyboard = 0;
   1019         }
   1020     }
   1021 
   1022     return ret;
   1023 }
   1024 
   1025 const char*
   1026 avdInfo_getContentPath( AvdInfo*  i )
   1027 {
   1028     return i->contentPath;
   1029 }
   1030 
   1031 int
   1032 avdInfo_inAndroidBuild( AvdInfo*  i )
   1033 {
   1034     return i->inAndroidBuild;
   1035 }
   1036 
   1037 char*
   1038 avdInfo_getTargetAbi( AvdInfo* i )
   1039 {
   1040     /* For now, we can't get the ABI from SDK AVDs */
   1041     if (!i->inAndroidBuild)
   1042         return NULL;
   1043 
   1044     return path_getBuildTargetAbi(i->androidOut);
   1045 }
   1046 
   1047 char*
   1048 avdInfo_getTracePath( AvdInfo*  i, const char*  traceName )
   1049 {
   1050     char   tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
   1051 
   1052     if (i == NULL || traceName == NULL || traceName[0] == 0)
   1053         return NULL;
   1054 
   1055     if (i->inAndroidBuild) {
   1056         p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
   1057                       i->androidOut, traceName );
   1058     } else {
   1059         p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
   1060                       i->contentPath, traceName );
   1061     }
   1062     return ASTRDUP(tmp);
   1063 }
   1064 
   1065 const char*
   1066 avdInfo_getCoreHwIniPath( AvdInfo* i )
   1067 {
   1068     return i->coreHardwareIniPath;
   1069 }
   1070 
   1071 
   1072 void
   1073 avdInfo_getSkinInfo( AvdInfo*  i, char** pSkinName, char** pSkinDir )
   1074 {
   1075     char*  skinName = NULL;
   1076     char*  skinPath;
   1077     char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
   1078 
   1079     *pSkinName = NULL;
   1080     *pSkinDir  = NULL;
   1081 
   1082     /* First, see if the config.ini contains a SKIN_PATH entry that
   1083      * names the full directory path for the skin.
   1084      */
   1085     if (i->configIni != NULL ) {
   1086         skinPath = iniFile_getString( i->configIni, SKIN_PATH, NULL );
   1087         if (skinPath != NULL) {
   1088             /* If this skin name is magic or a direct directory path
   1089             * we have our result right here.
   1090             */
   1091             if (_getSkinPathFromName(skinPath, i->sdkRootPath,
   1092                                      pSkinName, pSkinDir )) {
   1093                 AFREE(skinPath);
   1094                 return;
   1095             }
   1096         }
   1097 
   1098         /* The SKIN_PATH entry was not valid, so look at SKIN_NAME */
   1099         D("Warning: config.ini contains invalid %s entry: %s", SKIN_PATH, skinPath);
   1100         AFREE(skinPath);
   1101 
   1102         skinName = iniFile_getString( i->configIni, SKIN_NAME, NULL );
   1103     }
   1104 
   1105     if (skinName == NULL) {
   1106         /* If there is no skin listed in the config.ini, try to see if
   1107          * there is one single 'skin' directory in the content directory.
   1108          */
   1109         p = bufprint(temp, end, "%s/skin", i->contentPath);
   1110         if (p < end && _checkSkinPath(temp)) {
   1111             D("using skin content from %s", temp);
   1112             AFREE(i->skinName);
   1113             *pSkinName = ASTRDUP("skin");
   1114             *pSkinDir  = ASTRDUP(i->contentPath);
   1115             return;
   1116         }
   1117 
   1118         /* otherwise, use the default name */
   1119         skinName = ASTRDUP(SKIN_DEFAULT);
   1120     }
   1121 
   1122     /* now try to find the skin directory for that name -
   1123      */
   1124     do {
   1125         /* first try the content directory, i.e. $CONTENT/skins/<name> */
   1126         skinPath = _checkSkinSkinsDir(i->contentPath, skinName);
   1127         if (skinPath != NULL)
   1128             break;
   1129 
   1130 #define  PREBUILT_SKINS_ROOT "development/tools/emulator"
   1131 
   1132         /* if we are in the Android build, try the prebuilt directory */
   1133         if (i->inAndroidBuild) {
   1134             p = bufprint( temp, end, "%s/%s",
   1135                         i->androidBuildRoot, PREBUILT_SKINS_ROOT );
   1136             if (p < end) {
   1137                 skinPath = _checkSkinSkinsDir(temp, skinName);
   1138                 if (skinPath != NULL)
   1139                     break;
   1140             }
   1141 
   1142             /* or in the parent directory of the system dir */
   1143             {
   1144                 char* parentDir = path_parent(i->androidOut, 1);
   1145                 if (parentDir != NULL) {
   1146                     skinPath = _checkSkinSkinsDir(parentDir, skinName);
   1147                     AFREE(parentDir);
   1148                     if (skinPath != NULL)
   1149                         break;
   1150                 }
   1151             }
   1152         }
   1153 
   1154         /* look in the search paths. For each <dir> in the list,
   1155          * look into <dir>/../skins/<name>/ */
   1156         {
   1157             int  nn;
   1158             for (nn = 0; nn < i->numSearchPaths; nn++) {
   1159                 char*  parentDir = path_parent(i->searchPaths[nn], 1);
   1160                 if (parentDir == NULL)
   1161                     continue;
   1162                 skinPath = _checkSkinSkinsDir(parentDir, skinName);
   1163                 AFREE(parentDir);
   1164                 if (skinPath != NULL)
   1165                   break;
   1166             }
   1167             if (nn < i->numSearchPaths)
   1168                 break;
   1169         }
   1170 
   1171         /* We didn't find anything ! */
   1172         *pSkinName = skinName;
   1173         return;
   1174 
   1175     } while (0);
   1176 
   1177     if (path_split(skinPath, pSkinDir, pSkinName) < 0) {
   1178         derror("weird skin path: %s", skinPath);
   1179         AFREE(skinPath);
   1180         return;
   1181     }
   1182     DD("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
   1183     AFREE(skinPath);
   1184     return;
   1185 }
   1186 
   1187 int
   1188 avdInfo_shouldUseDynamicSkin( AvdInfo* i)
   1189 {
   1190     if (i == NULL || i->configIni == NULL)
   1191         return 0;
   1192     return iniFile_getBoolean( i->configIni, SKIN_DYNAMIC, "no" );
   1193 }
   1194 
   1195 char*
   1196 avdInfo_getCharmapFile( AvdInfo* i, const char* charmapName )
   1197 {
   1198     char        fileNameBuff[PATH_MAX];
   1199     const char* fileName;
   1200 
   1201     if (charmapName == NULL || charmapName[0] == '\0')
   1202         return NULL;
   1203 
   1204     if (strstr(charmapName, ".kcm") == NULL) {
   1205         snprintf(fileNameBuff, sizeof fileNameBuff, "%s.kcm", charmapName);
   1206         fileName = fileNameBuff;
   1207     } else {
   1208         fileName = charmapName;
   1209     }
   1210 
   1211     return _avdInfo_getContentOrSdkFilePath(i, fileName);
   1212 }
   1213 
   1214 int avdInfo_getAdbdCommunicationMode( AvdInfo* i )
   1215 {
   1216     return path_getAdbdCommunicationMode(i->androidOut);
   1217 }
   1218 
   1219 int avdInfo_getSnapshotPresent(AvdInfo* i)
   1220 {
   1221     if (i->configIni == NULL) {
   1222         return 0;
   1223     } else {
   1224         return iniFile_getBoolean(i->configIni, "snapshot.present", "no");
   1225     }
   1226 }
   1227