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