• 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/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
avdInfo_free(AvdInfo * i)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
_getSearchPaths(IniFile * configIni,const char * sdkRootPath,int maxSearchPaths,char ** searchPaths)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
_checkAvdName(const char * name)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*
_getFullFilePath(const char * rootPath,const char * fileName)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
_checkSkinPath(const char * skinPath)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*
_checkSkinSkinsDir(const char * skinDirRoot,const char * skinName)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
_getSkinPathFromName(const char * skinName,const char * sdkRootPath,char ** pSkinName,char ** pSkinDir)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
_avdInfo_getSdkRoot(AvdInfo * i)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
_avdInfo_getRootIni(AvdInfo * i)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
_avdInfo_getContentPath(AvdInfo * i)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
_avdInfo_getApiLevel(AvdInfo * i)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*
_avdInfo_getContentFilePath(AvdInfo * i,const char * fileName)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
_avdInfo_getConfigIni(AvdInfo * i)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
_avdInfo_getSearchPaths(AvdInfo * i)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*
_avdInfo_getSdkFilePath(AvdInfo * i,const char * fileName)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*
_avdInfo_getContentOrSdkFilePath(AvdInfo * i,const char * fileName)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
_avdInfo_getCoreHwIniPath(AvdInfo * i,const char * basePath)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*
avdInfo_new(const char * name,AvdInfoParams * params)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
_avdInfo_getBuildSkinHardwareIni(AvdInfo * i)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 
avdInfo_getSkinHardwareIni(AvdInfo * i,char * skinName,char * skinDirPath)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*
avdInfo_newForAndroidBuild(const char * androidBuildRoot,const char * androidOut,AvdInfoParams * params)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*
avdInfo_getName(AvdInfo * i)852 avdInfo_getName( AvdInfo*  i )
853 {
854     return i ? i->deviceName : NULL;
855 }
856 
857 const char*
avdInfo_getImageFile(AvdInfo * i,AvdImageType imageType)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
avdInfo_getImageFileSize(AvdInfo * i,AvdImageType imageType)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
avdInfo_isImageReadOnly(AvdInfo * i,AvdImageType imageType)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*
avdInfo_getKernelPath(AvdInfo * i)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*
avdInfo_getRamdiskPath(AvdInfo * i)927 avdInfo_getRamdiskPath( AvdInfo* i )
928 {
929     const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ];
930     return _avdInfo_getContentOrSdkFilePath(i, imageName);
931 }
932 
avdInfo_getCachePath(AvdInfo * i)933 char*  avdInfo_getCachePath( AvdInfo*  i )
934 {
935     const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
936     return _avdInfo_getContentFilePath(i, imageName);
937 }
938 
avdInfo_getDefaultCachePath(AvdInfo * i)939 char*  avdInfo_getDefaultCachePath( AvdInfo*  i )
940 {
941     const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
942     return _getFullFilePath(i->contentPath, imageName);
943 }
944 
avdInfo_getSdCardPath(AvdInfo * i)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*
avdInfo_getSnapStoragePath(AvdInfo * i)969 avdInfo_getSnapStoragePath( AvdInfo* i )
970 {
971     const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ];
972     return _avdInfo_getContentFilePath(i, imageName);
973 }
974 
975 char*
avdInfo_getSystemImagePath(AvdInfo * i)976 avdInfo_getSystemImagePath( AvdInfo*  i )
977 {
978     const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ];
979     return _avdInfo_getContentFilePath(i, imageName);
980 }
981 
982 char*
avdInfo_getSystemInitImagePath(AvdInfo * i)983 avdInfo_getSystemInitImagePath( AvdInfo*  i )
984 {
985     const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ];
986     return _avdInfo_getContentOrSdkFilePath(i, imageName);
987 }
988 
989 char*
avdInfo_getDataImagePath(AvdInfo * i)990 avdInfo_getDataImagePath( AvdInfo*  i )
991 {
992     const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
993     return _avdInfo_getContentFilePath(i, imageName);
994 }
995 
996 char*
avdInfo_getDefaultDataImagePath(AvdInfo * i)997 avdInfo_getDefaultDataImagePath( AvdInfo*  i )
998 {
999     const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
1000     return _getFullFilePath(i->contentPath, imageName);
1001 }
1002 
1003 char*
avdInfo_getDataInitImagePath(AvdInfo * i)1004 avdInfo_getDataInitImagePath( AvdInfo* i )
1005 {
1006     const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ];
1007     return _avdInfo_getContentOrSdkFilePath(i, imageName);
1008 }
1009 
1010 int
avdInfo_initHwConfig(AvdInfo * i,AndroidHwConfig * hw)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*
avdInfo_getContentPath(AvdInfo * i)1039 avdInfo_getContentPath( AvdInfo*  i )
1040 {
1041     return i->contentPath;
1042 }
1043 
1044 int
avdInfo_inAndroidBuild(AvdInfo * i)1045 avdInfo_inAndroidBuild( AvdInfo*  i )
1046 {
1047     return i->inAndroidBuild;
1048 }
1049 
1050 char*
avdInfo_getTargetAbi(AvdInfo * i)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*
avdInfo_getTracePath(AvdInfo * i,const char * traceName)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*
avdInfo_getCoreHwIniPath(AvdInfo * i)1079 avdInfo_getCoreHwIniPath( AvdInfo* i )
1080 {
1081     return i->coreHardwareIniPath;
1082 }
1083 
1084 
1085 void
avdInfo_getSkinInfo(AvdInfo * i,char ** pSkinName,char ** pSkinDir)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*
avdInfo_getCharmapFile(AvdInfo * i,const char * charmapName)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 
avdInfo_getAdbdCommunicationMode(AvdInfo * i)1219 int avdInfo_getAdbdCommunicationMode( AvdInfo* i )
1220 {
1221     return path_getAdbdCommunicationMode(i->androidOut);
1222 }
1223 
avdInfo_getSnapshotPresent(AvdInfo * i)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