• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
avdInfo_free(AvdInfo * i)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
_getSearchPaths(IniFile * configIni,const char * sdkRootPath,int maxSearchPaths,char ** searchPaths)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
_checkAvdName(const char * name)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*
_getFullFilePath(const char * rootPath,const char * fileName)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
_checkSkinPath(const char * skinPath)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*
_checkSkinSkinsDir(const char * skinDirRoot,const char * skinName)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
_getSkinPathFromName(const char * skinName,const char * sdkRootPath,char ** pSkinName,char ** pSkinDir)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
_avdInfo_getSdkRoot(AvdInfo * i)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
_avdInfo_getRootIni(AvdInfo * i)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
_avdInfo_getContentPath(AvdInfo * i)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
_avdInfo_getApiLevel(AvdInfo * i)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*
_avdInfo_getContentFilePath(AvdInfo * i,const char * fileName)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
_avdInfo_getConfigIni(AvdInfo * i)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
_avdInfo_getSearchPaths(AvdInfo * i)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*
_avdInfo_getSdkFilePath(AvdInfo * i,const char * fileName)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*
_avdInfo_getContentOrSdkFilePath(AvdInfo * i,const char * fileName)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
_avdInfo_getCoreHwIniPath(AvdInfo * i,const char * basePath)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*
avdInfo_new(const char * name,AvdInfoParams * params)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
_avdInfo_getBuildSkinHardwareIni(AvdInfo * i)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 
avdInfo_getSkinHardwareIni(AvdInfo * i,char * skinName,char * skinDirPath)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*
avdInfo_newForAndroidBuild(const char * androidBuildRoot,const char * androidOut,AvdInfoParams * params)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*
avdInfo_getName(AvdInfo * i)839 avdInfo_getName( AvdInfo*  i )
840 {
841     return i ? i->deviceName : NULL;
842 }
843 
844 const char*
avdInfo_getImageFile(AvdInfo * i,AvdImageType imageType)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
avdInfo_getImageFileSize(AvdInfo * i,AvdImageType imageType)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
avdInfo_isImageReadOnly(AvdInfo * i,AvdImageType imageType)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*
avdInfo_getKernelPath(AvdInfo * i)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*
avdInfo_getRamdiskPath(AvdInfo * i)914 avdInfo_getRamdiskPath( AvdInfo* i )
915 {
916     const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ];
917     return _avdInfo_getContentOrSdkFilePath(i, imageName);
918 }
919 
avdInfo_getCachePath(AvdInfo * i)920 char*  avdInfo_getCachePath( AvdInfo*  i )
921 {
922     const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
923     return _avdInfo_getContentFilePath(i, imageName);
924 }
925 
avdInfo_getDefaultCachePath(AvdInfo * i)926 char*  avdInfo_getDefaultCachePath( AvdInfo*  i )
927 {
928     const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
929     return _getFullFilePath(i->contentPath, imageName);
930 }
931 
avdInfo_getSdCardPath(AvdInfo * i)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*
avdInfo_getSnapStoragePath(AvdInfo * i)956 avdInfo_getSnapStoragePath( AvdInfo* i )
957 {
958     const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ];
959     return _avdInfo_getContentFilePath(i, imageName);
960 }
961 
962 char*
avdInfo_getSystemImagePath(AvdInfo * i)963 avdInfo_getSystemImagePath( AvdInfo*  i )
964 {
965     const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ];
966     return _avdInfo_getContentFilePath(i, imageName);
967 }
968 
969 char*
avdInfo_getSystemInitImagePath(AvdInfo * i)970 avdInfo_getSystemInitImagePath( AvdInfo*  i )
971 {
972     const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ];
973     return _avdInfo_getContentOrSdkFilePath(i, imageName);
974 }
975 
976 char*
avdInfo_getDataImagePath(AvdInfo * i)977 avdInfo_getDataImagePath( AvdInfo*  i )
978 {
979     const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
980     return _avdInfo_getContentFilePath(i, imageName);
981 }
982 
983 char*
avdInfo_getDefaultDataImagePath(AvdInfo * i)984 avdInfo_getDefaultDataImagePath( AvdInfo*  i )
985 {
986     const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
987     return _getFullFilePath(i->contentPath, imageName);
988 }
989 
990 char*
avdInfo_getDataInitImagePath(AvdInfo * i)991 avdInfo_getDataInitImagePath( AvdInfo* i )
992 {
993     const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ];
994     return _avdInfo_getContentOrSdkFilePath(i, imageName);
995 }
996 
997 int
avdInfo_initHwConfig(AvdInfo * i,AndroidHwConfig * hw)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*
avdInfo_getContentPath(AvdInfo * i)1026 avdInfo_getContentPath( AvdInfo*  i )
1027 {
1028     return i->contentPath;
1029 }
1030 
1031 int
avdInfo_inAndroidBuild(AvdInfo * i)1032 avdInfo_inAndroidBuild( AvdInfo*  i )
1033 {
1034     return i->inAndroidBuild;
1035 }
1036 
1037 char*
avdInfo_getTargetAbi(AvdInfo * i)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*
avdInfo_getTracePath(AvdInfo * i,const char * traceName)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*
avdInfo_getCoreHwIniPath(AvdInfo * i)1066 avdInfo_getCoreHwIniPath( AvdInfo* i )
1067 {
1068     return i->coreHardwareIniPath;
1069 }
1070 
1071 
1072 void
avdInfo_getSkinInfo(AvdInfo * i,char ** pSkinName,char ** pSkinDir)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
avdInfo_shouldUseDynamicSkin(AvdInfo * i)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*
avdInfo_getCharmapFile(AvdInfo * i,const char * charmapName)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 
avdInfo_getAdbdCommunicationMode(AvdInfo * i)1214 int avdInfo_getAdbdCommunicationMode( AvdInfo* i )
1215 {
1216     return path_getAdbdCommunicationMode(i->androidOut);
1217 }
1218 
avdInfo_getSnapshotPresent(AvdInfo * i)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