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