• 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/utils/path.h"
14 #include "android/utils/bufprint.h"
15 #include "android/utils/filelock.h"
16 #include "android/utils/tempfile.h"
17 #include "android/utils/debug.h"
18 #include "android/utils/dirscanner.h"
19 #include <ctype.h>
20 #include <stddef.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <errno.h>
25 
26 /* global variables - see android/globals.h */
27 AvdInfoParams   android_avdParams[1];
28 AvdInfo*        android_avdInfo;
29 
30 /* for debugging */
31 #define  D(...)   VERBOSE_PRINT(init,__VA_ARGS__)
32 #define  DD(...)  VERBOSE_PRINT(avd_config,__VA_ARGS__)
33 
34 /* technical note on how all of this is supposed to work:
35  *
36  * Each AVD corresponds to a "content directory" that is used to
37  * store persistent disk images and configuration files. Most remarkable
38  * are:
39  *
40  * - a "config.ini" file used to hold configuration information for the
41  *   AVD
42  *
43  * - mandatory user data image ("userdata-qemu.img") and cache image
44  *   ("cache.img")
45  *
46  * - optional mutable system image ("system-qemu.img"), kernel image
47  *   ("kernel-qemu") and read-only ramdisk ("ramdisk.img")
48  *
49  * When starting up an AVD, the emulator looks for relevant disk images
50  * in the content directory. If it doesn't find a given image there, it
51  * will try to search in the list of system directories listed in the
52  * 'config.ini' file through one of the following (key,value) pairs:
53  *
54  *    images.sysdir.1 = <first search path>
55  *    images.sysdir.2 = <second search path>
56  *
57  * The search paths can be absolute, or relative to the root SDK installation
58  * path (which is determined from the emulator program's location, or from the
59  * ANDROID_SDK_ROOT environment variable).
60  *
61  * Individual image disk search patch can be over-riden on the command-line
62  * with one of the usual options.
63  */
64 
65 /* this is the subdirectory of $HOME/.android where all
66  * root configuration files (and default content directories)
67  * are located.
68  */
69 #define  ANDROID_AVD_DIR    "avd"
70 
71 /* the prefix of config.ini keys that will be used for search directories
72  * of system images.
73  */
74 #define  SEARCH_PREFIX   "image.sysdir."
75 
76 /* the maximum number of search path keys we're going to read from the
77  * config.ini file
78  */
79 #define  MAX_SEARCH_PATHS  2
80 
81 /* the config.ini key that will be used to indicate the full relative
82  * path to the skin directory (including the skin name).
83  */
84 #define  SKIN_PATH       "skin.path"
85 
86 /* default skin name */
87 #define  SKIN_DEFAULT    "HVGA"
88 
89 /* the config.ini key that is used to indicate the absolute path
90  * to the SD Card image file, if you don't want to place it in
91  * the content directory.
92  */
93 #define  SDCARD_PATH     "sdcard.path"
94 
95 /* certain disk image files are mounted read/write by the emulator
96  * to ensure that several emulators referencing the same files
97  * do not corrupt these files, we need to lock them and respond
98  * to collision depending on the image type.
99  *
100  * the enumeration below is used to record information about
101  * each image file path.
102  *
103  * READONLY means that the file will be mounted read-only
104  * and this doesn't need to be locked. must be first in list
105  *
106  * MUSTLOCK means that the file should be locked before
107  * being mounted by the emulator
108  *
109  * TEMPORARY means that the file has been copied to a
110  * temporary image, which can be mounted read/write
111  * but doesn't require locking.
112  */
113 typedef enum {
114     IMAGE_STATE_READONLY,     /* unlocked */
115     IMAGE_STATE_MUSTLOCK,     /* must be locked */
116     IMAGE_STATE_LOCKED,       /* locked */
117     IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
118     IMAGE_STATE_TEMPORARY,    /* copied to temp file (no lock needed) */
119 } AvdImageState;
120 
121 struct AvdInfo {
122     /* for the Android build system case */
123     char      inAndroidBuild;
124     char*     androidOut;
125     char*     androidBuildRoot;
126 
127     /* for the normal virtual device case */
128     char*     deviceName;
129     char*     sdkRootPath;
130     char      sdkRootPathFromEnv;
131     char*     searchPaths[ MAX_SEARCH_PATHS ];
132     int       numSearchPaths;
133     char*     contentPath;
134     IniFile*  rootIni;      /* root <foo>.ini file */
135     IniFile*  configIni;    /* virtual device's config.ini */
136     IniFile*  hardwareIni;  /* skin-specific hardware.ini */
137 
138     /* for both */
139     char*     skinName;     /* skin name */
140     char*     skinDirPath;  /* skin directory */
141 
142     /* image files */
143     char*     imagePath [ AVD_IMAGE_MAX ];
144     char      imageState[ AVD_IMAGE_MAX ];
145 };
146 
147 
148 void
avdInfo_free(AvdInfo * i)149 avdInfo_free( AvdInfo*  i )
150 {
151     if (i) {
152         int  nn;
153 
154         for (nn = 0; nn < AVD_IMAGE_MAX; nn++)
155             AFREE(i->imagePath[nn]);
156 
157         AFREE(i->skinName);
158         AFREE(i->skinDirPath);
159 
160         for (nn = 0; nn < i->numSearchPaths; nn++)
161             AFREE(i->searchPaths[nn]);
162 
163         i->numSearchPaths = 0;
164 
165         if (i->configIni) {
166             iniFile_free(i->configIni);
167             i->configIni = NULL;
168         }
169 
170         if (i->hardwareIni) {
171             iniFile_free(i->hardwareIni);
172             i->hardwareIni = NULL;
173         }
174 
175         if (i->rootIni) {
176             iniFile_free(i->rootIni);
177             i->rootIni = NULL;
178         }
179 
180         AFREE(i->contentPath);
181         AFREE(i->sdkRootPath);
182 
183         if (i->inAndroidBuild) {
184             AFREE(i->androidOut);
185             AFREE(i->androidBuildRoot);
186         }
187 
188         AFREE(i->deviceName);
189         AFREE(i);
190     }
191 }
192 
193 /* list of default file names for each supported image file type */
194 static const char*  const  _imageFileNames[ AVD_IMAGE_MAX ] = {
195 #define  _AVD_IMG(x,y,z)  y,
196     AVD_IMAGE_LIST
197 #undef _AVD_IMG
198 };
199 
200 /* list of short text description for each supported image file type */
201 static const char*  const _imageFileText[ AVD_IMAGE_MAX ] = {
202 #define  _AVD_IMG(x,y,z)  z,
203     AVD_IMAGE_LIST
204 #undef _AVD_IMG
205 };
206 
207 /***************************************************************
208  ***************************************************************
209  *****
210  *****    NORMAL VIRTUAL DEVICE SUPPORT
211  *****
212  *****/
213 
214 /* compute path to the root SDK directory
215  * assume we are in $SDKROOT/tools/emulator[.exe]
216  */
217 static int
_getSdkRoot(AvdInfo * i)218 _getSdkRoot( AvdInfo*  i )
219 {
220     const char*  env;
221     char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
222 
223 #define  SDK_ROOT_ENV  "ANDROID_SDK_ROOT"
224 
225     env = getenv(SDK_ROOT_ENV);
226     if (env != NULL && env[0] != 0) {
227         if (path_exists(env)) {
228             D("found " SDK_ROOT_ENV ": %s", env);
229             i->sdkRootPath = ASTRDUP(env);
230             i->sdkRootPathFromEnv = 1;
231             return 0;
232         }
233         D(SDK_ROOT_ENV " points to unknown directory: %s", env);
234     }
235 
236     (void) bufprint_app_dir(temp, end);
237 
238     i->sdkRootPath = path_parent(temp, 1);
239     if (i->sdkRootPath == NULL) {
240         derror("can't find root of SDK directory");
241         return -1;
242     }
243     D("found SDK root at %s", i->sdkRootPath);
244     return 0;
245 }
246 
247 static void
_getSearchPaths(AvdInfo * i)248 _getSearchPaths( AvdInfo*  i )
249 {
250     char  temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
251     int   nn, count = 0;
252 
253 
254 
255     for (nn = 0; nn < MAX_SEARCH_PATHS; nn++) {
256         char*  path;
257 
258         p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
259         if (p >= end)
260             continue;
261 
262         path = iniFile_getString( i->configIni, temp );
263         if (path != NULL) {
264             DD("    found image search path: %s", path);
265             if (!path_is_absolute(path)) {
266                 p = bufprint(temp, end, "%s/%s", i->sdkRootPath, path);
267                 AFREE(path);
268                 path = ASTRDUP(temp);
269             }
270             i->searchPaths[count++] = path;
271         }
272     }
273 
274     i->numSearchPaths = count;
275     if (count == 0) {
276         derror("no search paths found in this AVD's configuration.\n"
277                "Weird, the AVD's config.ini file is malformed. Try re-creating it.\n");
278         exit(2);
279     }
280     else
281         DD("found a total of %d search paths for this AVD", count);
282 }
283 
284 static int
_checkAvdName(const char * name)285 _checkAvdName( const char*  name )
286 {
287     int  len  = strlen(name);
288     int  len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
289                              "abcdefghijklmnopqrstuvwxyz"
290                              "0123456789_.-");
291     return (len == len2);
292 }
293 
294 /* parse the root config .ini file. it is located in
295  * ~/.android/avd/<name>.ini or Windows equivalent
296  */
297 static int
_getRootIni(AvdInfo * i)298 _getRootIni( AvdInfo*  i )
299 {
300     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
301 
302     p = bufprint_config_path(temp, end);
303     p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", i->deviceName);
304     if (p >= end) {
305         derror("device name too long");
306         return -1;
307     }
308 
309     i->rootIni = iniFile_newFromFile(temp);
310     if (i->rootIni == NULL) {
311         derror("unknown virtual device name: '%s'", i->deviceName);
312         return -1;
313     }
314     D("root virtual device file at %s", temp);
315     return 0;
316 }
317 
318 /* the .ini variable name that points to the content directory
319  * in a root AVD ini file. This is required */
320 #   define  ROOT_PATH_KEY    "path"
321 
322 static int
_getContentPath(AvdInfo * i)323 _getContentPath( AvdInfo*  i )
324 {
325     i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY);
326 
327     if (i->contentPath == NULL) {
328         derror("bad config: %s",
329                "virtual device file lacks a "ROOT_PATH_KEY" entry");
330         return -1;
331     }
332     D("virtual device content at %s", i->contentPath);
333     return 0;
334 }
335 
336 /* find and parse the config.ini file from the content directory */
337 static int
_getConfigIni(AvdInfo * i)338 _getConfigIni(AvdInfo*  i)
339 {
340     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
341 
342     p = bufprint(p, end, "%s/config.ini", i->contentPath);
343     if (p >= end) {
344         derror("can't access virtual device content directory");
345         return -1;
346     }
347 
348 #if 1   /* XXX: TODO: remove this in the future */
349     /* for now, allow a non-existing config.ini */
350     if (!path_exists(temp)) {
351         D("virtual device has no config file - no problem");
352         return 0;
353     }
354 #endif
355 
356     i->configIni = iniFile_newFromFile(temp);
357     if (i->configIni == NULL) {
358         derror("bad config: %s",
359                "virtual device directory lacks config.ini");
360         return -1;
361     }
362     D("virtual device config file: %s", temp);
363     return 0;
364 }
365 
366 /***************************************************************
367  ***************************************************************
368  *****
369  *****    KERNEL/DISK IMAGE LOADER
370  *****
371  *****/
372 
373 /* a structure used to handle the loading of
374  * kernel/disk images.
375  */
376 typedef struct {
377     AvdInfo*        info;
378     AvdInfoParams*  params;
379     AvdImageType    id;
380     const char*     imageFile;
381     const char*     imageText;
382     char**          pPath;
383     char*           pState;
384     char            temp[PATH_MAX];
385 } ImageLoader;
386 
387 static void
imageLoader_init(ImageLoader * l,AvdInfo * info,AvdInfoParams * params)388 imageLoader_init( ImageLoader*  l, AvdInfo*  info, AvdInfoParams*  params )
389 {
390     memset(l, 0, sizeof(*l));
391     l->info    = info;
392     l->params  = params;
393 }
394 
395 /* set the type of the image to load */
396 static void
imageLoader_set(ImageLoader * l,AvdImageType id)397 imageLoader_set( ImageLoader*  l, AvdImageType  id )
398 {
399     l->id        = id;
400     l->imageFile = _imageFileNames[id];
401     l->imageText = _imageFileText[id];
402     l->pPath     = &l->info->imagePath[id];
403     l->pState    = &l->info->imageState[id];
404 
405     l->pState[0] = IMAGE_STATE_READONLY;
406 }
407 
408 /* change the image path */
409 static char*
imageLoader_setPath(ImageLoader * l,const char * path)410 imageLoader_setPath( ImageLoader*  l, const char*  path )
411 {
412     path = path ? ASTRDUP(path) : NULL;
413 
414     AFREE(l->pPath[0]);
415     l->pPath[0] = (char*) path;
416 
417     return (char*) path;
418 }
419 
420 static char*
imageLoader_extractPath(ImageLoader * l)421 imageLoader_extractPath( ImageLoader*  l )
422 {
423     char*  result = l->pPath[0];
424     l->pPath[0] = NULL;
425     return result;
426 }
427 
428 /* flags used when loading images */
429 enum {
430     IMAGE_REQUIRED          = (1<<0),  /* image is required */
431     IMAGE_SEARCH_SDK        = (1<<1),  /* search image in SDK */
432     IMAGE_EMPTY_IF_MISSING  = (1<<2),  /* create empty file if missing */
433     IMAGE_DONT_LOCK         = (1<<4),  /* don't try to lock image */
434     IMAGE_IGNORE_IF_LOCKED  = (1<<5),  /* ignore file if it's locked */
435 };
436 
437 #define  IMAGE_OPTIONAL  0
438 
439 /* find an image from the SDK search directories.
440  * returns the full path or NULL if the file could not be found.
441  *
442  * note: this stores the result in the image's path as well
443  */
444 static char*
imageLoader_lookupSdk(ImageLoader * l)445 imageLoader_lookupSdk( ImageLoader*  l  )
446 {
447     AvdInfo*     i     = l->info;
448     const char*  image = l->imageFile;
449     char*        temp  = l->temp, *p = temp, *end = p + sizeof(l->temp);
450 
451     do {
452         /* try the search paths */
453         int  nn;
454 
455         for (nn = 0; nn < i->numSearchPaths; nn++) {
456             const char* searchDir = i->searchPaths[nn];
457 
458             p = bufprint(temp, end, "%s/%s", searchDir, image);
459             if (p < end && path_exists(temp)) {
460                 DD("found %s in search dir: %s", image, searchDir);
461                 goto FOUND;
462             }
463             DD("    no %s in search dir: %s", image, searchDir);
464         }
465 
466         return NULL;
467 
468     } while (0);
469 
470 FOUND:
471     l->pState[0] = IMAGE_STATE_READONLY;
472 
473     return imageLoader_setPath(l, temp);
474 }
475 
476 /* search for a file in the content directory.
477  * returns NULL if the file cannot be found.
478  *
479  * note that this formats l->temp with the file's path
480  * allowing you to retrieve it if the function returns NULL
481  */
482 static char*
imageLoader_lookupContent(ImageLoader * l)483 imageLoader_lookupContent( ImageLoader*  l )
484 {
485     AvdInfo*  i     = l->info;
486     char*     temp  = l->temp, *p = temp, *end = p + sizeof(l->temp);
487 
488     p = bufprint(temp, end, "%s/%s", i->contentPath, l->imageFile);
489     if (p >= end) {
490         derror("content directory path too long");
491         exit(2);
492     }
493     if (!path_exists(temp)) {
494         DD("    no %s in content directory", l->imageFile);
495         return NULL;
496     }
497     DD("found %s in content directory", l->imageFile);
498 
499     /* assume content image files must be locked */
500     l->pState[0] = IMAGE_STATE_MUSTLOCK;
501 
502     return imageLoader_setPath(l, temp);
503 }
504 
505 /* lock a file image depending on its state and user flags
506  * note that this clears l->pPath[0] if the lock could not
507  * be acquired and that IMAGE_IGNORE_IF_LOCKED is used.
508  */
509 static void
imageLoader_lock(ImageLoader * l,unsigned flags)510 imageLoader_lock( ImageLoader*  l, unsigned  flags )
511 {
512     const char*  path = l->pPath[0];
513 
514     if (flags & IMAGE_DONT_LOCK)
515         return;
516 
517     if (l->pState[0] != IMAGE_STATE_MUSTLOCK)
518         return;
519 
520     D("    locking %s image at %s", l->imageText, path);
521 
522     if (filelock_create(path) != NULL) {
523         /* succesful lock */
524         l->pState[0] = IMAGE_STATE_LOCKED;
525         return;
526     }
527 
528     if (flags & IMAGE_IGNORE_IF_LOCKED) {
529         dwarning("ignoring locked %s image at %s", l->imageText, path);
530         imageLoader_setPath(l, NULL);
531         return;
532     }
533 
534     derror("the %s image is used by another emulator. aborting",
535             l->imageText);
536     exit(2);
537 }
538 
539 /* make a file image empty, this may require locking */
540 static void
imageLoader_empty(ImageLoader * l,unsigned flags)541 imageLoader_empty( ImageLoader*  l, unsigned  flags )
542 {
543     const char*  path;
544 
545     imageLoader_lock(l, flags);
546 
547     path = l->pPath[0];
548     if (path == NULL)  /* failed to lock, caller will handle it */
549         return;
550 
551     if (path_empty_file(path) < 0) {
552         derror("could not create %s image at %s: %s",
553                 l->imageText, path, strerror(errno));
554         exit(2);
555     }
556     l->pState[0] = IMAGE_STATE_LOCKED_EMPTY;
557 }
558 
559 
560 /* copy image file from a given source
561  * assumes locking is needed.
562  */
563 static void
imageLoader_copyFrom(ImageLoader * l,const char * srcPath)564 imageLoader_copyFrom( ImageLoader*  l, const char*  srcPath )
565 {
566     const char*  dstPath = NULL;
567 
568     /* find destination file */
569     if (l->params) {
570         dstPath = l->params->forcePaths[l->id];
571     }
572     if (!dstPath) {
573         imageLoader_lookupContent(l);
574         dstPath = l->temp;
575     }
576 
577     /* lock destination */
578     imageLoader_setPath(l, dstPath);
579     l->pState[0] = IMAGE_STATE_MUSTLOCK;
580     imageLoader_lock(l, 0);
581 
582     /* make the copy */
583     if (path_copy_file(dstPath, srcPath) < 0) {
584         derror("can't initialize %s image from SDK: %s: %s",
585                l->imageText, dstPath, strerror(errno));
586         exit(2);
587     }
588 }
589 
590 /* this will load and eventually lock and image file, depending
591  * on the flags being used. on exit, this function udpates
592  * l->pState[0] and l->pPath[0]
593  *
594  * returns the path to the file. Note that it returns NULL
595  * only if the file was optional and could not be found.
596  *
597  * if the file is required and missing, the function aborts
598  * the program.
599  */
600 static char*
imageLoader_load(ImageLoader * l,unsigned flags)601 imageLoader_load( ImageLoader*    l,
602                   unsigned        flags )
603 {
604     const char*  path = NULL;
605 
606     /* set image state */
607     l->pState[0] = (flags & IMAGE_DONT_LOCK) == 0
608                  ? IMAGE_STATE_MUSTLOCK
609                  : IMAGE_STATE_READONLY;
610 
611     /* check user-provided path */
612     path = l->params->forcePaths[l->id];
613     if (path != NULL) {
614         imageLoader_setPath(l, path);
615         if (path_exists(path)) {
616             DD("found user-provided %s image: %s", l->imageText, l->imageFile);
617             goto EXIT;
618         }
619         D("user-provided %s image does not exist: %s",
620           l->imageText, path);
621 
622         /* if the file is required, abort */
623         if (flags & IMAGE_REQUIRED) {
624             derror("user-provided %s image at %s doesn't exist",
625                     l->imageText, path);
626             exit(2);
627         }
628     }
629     else {
630         const char*  contentFile;
631 
632         /* second, look in the content directory */
633         path = imageLoader_lookupContent(l);
634         if (path) goto EXIT;
635 
636         contentFile = ASTRDUP(l->temp);
637 
638         /* it's not there */
639         if (flags & IMAGE_SEARCH_SDK) {
640             /* third, look in the SDK directory */
641             path = imageLoader_lookupSdk(l);
642             if (path) {
643                 AFREE((char*)contentFile);
644                 goto EXIT;
645             }
646         }
647         DD("found no %s image (%s)", l->imageText, l->imageFile);
648 
649         /* if the file is required, abort */
650         if (flags & IMAGE_REQUIRED) {
651             AvdInfo*  i = l->info;
652 
653             derror("could not find required %s image (%s).",
654                    l->imageText, l->imageFile);
655 
656             if (i->inAndroidBuild) {
657                 dprint( "Did you build everything ?" );
658             } else if (!i->sdkRootPathFromEnv) {
659                 dprint( "Maybe defining %s to point to a valid SDK "
660                         "installation path might help ?", SDK_ROOT_ENV );
661             } else {
662                 dprint( "Your %s is probably wrong: %s", SDK_ROOT_ENV,
663                         i->sdkRootPath );
664             }
665             exit(2);
666         }
667 
668         path = imageLoader_setPath(l, contentFile);
669         AFREE((char*)contentFile);
670     }
671 
672     /* otherwise, do we need to create it ? */
673     if (flags & IMAGE_EMPTY_IF_MISSING) {
674         imageLoader_empty(l, flags);
675         return l->pPath[0];
676     }
677     return NULL;
678 
679 EXIT:
680     imageLoader_lock(l, flags);
681     return l->pPath[0];
682 }
683 
684 
685 
686 /* find the correct path of all image files we're going to need
687  * and lock the files that need it.
688  */
689 static int
_getImagePaths(AvdInfo * i,AvdInfoParams * params)690 _getImagePaths(AvdInfo*  i, AvdInfoParams*  params )
691 {
692     int   wipeData  = (params->flags & AVDINFO_WIPE_DATA) != 0;
693     int   wipeCache = (params->flags & AVDINFO_WIPE_CACHE) != 0;
694     int   noCache   = (params->flags & AVDINFO_NO_CACHE) != 0;
695     int   noSdCard  = (params->flags & AVDINFO_NO_SDCARD) != 0;
696 
697     ImageLoader  l[1];
698 
699     imageLoader_init(l, i, params);
700 
701     /* pick up the kernel and ramdisk image files - these don't
702      * need a specific handling.
703      */
704     imageLoader_set ( l, AVD_IMAGE_KERNEL );
705     imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
706 
707     imageLoader_set ( l, AVD_IMAGE_RAMDISK );
708     imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
709 
710     /* the system image
711      *
712      * if there is one in the content directory just lock
713      * and use it.
714      */
715     imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
716     imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
717 
718     /* the data partition - this one is special because if it
719      * is missing, we need to copy the initial image file into it.
720      *
721      * first, try to see if it is in the content directory
722      * (or the user-provided path)
723      */
724     imageLoader_set( l, AVD_IMAGE_USERDATA );
725     if ( !imageLoader_load( l, IMAGE_OPTIONAL |
726                                IMAGE_EMPTY_IF_MISSING |
727                                IMAGE_DONT_LOCK ) )
728     {
729         /* it's not, we're going to initialize it. simply
730          * forcing a data wipe should be enough */
731         D("initializing new data partition image: %s", l->pPath[0]);
732         wipeData = 1;
733     }
734 
735     if (wipeData) {
736         /* find SDK source file */
737         const char*  srcPath;
738 
739         imageLoader_set( l, AVD_IMAGE_INITDATA );
740         if (imageLoader_lookupSdk(l) == NULL) {
741             derror("can't locate initial %s image in SDK",
742                 l->imageText);
743             exit(2);
744         }
745         srcPath = imageLoader_extractPath(l);
746 
747         imageLoader_set( l, AVD_IMAGE_USERDATA );
748         imageLoader_copyFrom( l, srcPath );
749         AFREE((char*) srcPath);
750     }
751     else
752     {
753         /* lock the data partition image */
754         l->pState[0] = IMAGE_STATE_MUSTLOCK;
755         imageLoader_lock( l, 0 );
756     }
757 
758     /* the cache partition: unless the user doesn't want one,
759      * we're going to create it in the content directory
760      */
761     if (!noCache) {
762         imageLoader_set (l, AVD_IMAGE_CACHE);
763         imageLoader_load(l, IMAGE_OPTIONAL |
764                             IMAGE_EMPTY_IF_MISSING );
765 
766         if (wipeCache) {
767             if (path_empty_file(l->pPath[0]) < 0) {
768                 derror("cannot wipe %s image at %s: %s",
769                        l->imageText, l->pPath[0],
770                        strerror(errno));
771                 exit(2);
772             }
773         }
774     }
775 
776     /* the SD Card image. unless the user doesn't want to, we're
777      * going to mount it if available. Note that if the image is
778      * already used, we must ignore it.
779      */
780     if (!noSdCard) {
781         imageLoader_set (l, AVD_IMAGE_SDCARD);
782         imageLoader_load(l, IMAGE_OPTIONAL |
783                             IMAGE_IGNORE_IF_LOCKED);
784 
785         /* if the file was not found, ignore it */
786         if (l->pPath[0] && !path_exists(l->pPath[0]))
787         {
788             D("ignoring non-existing %s at %s: %s",
789               l->imageText, l->pPath[0], strerror(errno));
790 
791             /* if the user provided the SD Card path by hand,
792              * warn him. */
793             if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL)
794                 dwarning("ignoring non-existing SD Card image");
795 
796             imageLoader_setPath(l, NULL);
797         }
798     }
799 
800     return 0;
801 }
802 
803 /* check that a given directory contains a valid skin.
804  * returns 1 on success, 0 on failure.
805  */
806 static int
_checkSkinPath(const char * skinPath)807 _checkSkinPath( const char*  skinPath )
808 {
809     char  temp[MAX_PATH], *p=temp, *end=p+sizeof(temp);
810 
811     /* for now, if it has a 'layout' file, it is a valid skin path */
812     p = bufprint(temp, end, "%s/layout", skinPath);
813     if (p >= end || !path_exists(temp))
814         return 0;
815 
816     return 1;
817 }
818 
819 /* check that there is a skin named 'skinName' listed from 'skinDirRoot'
820  * this returns 1 on success, 0 on failure
821  * on success, the 'temp' buffer will get the path containing the real
822  * skin directory (after alias expansion), including the skin name.
823  */
824 static int
_checkSkinDir(char * temp,char * end,const char * skinDirRoot,const char * skinName)825 _checkSkinDir( char*        temp,
826                char*        end,
827                const char*  skinDirRoot,
828                const char*  skinName )
829 {
830     DirScanner*  scanner;
831     char        *p;
832     int          result;
833 
834     p = bufprint(temp, end, "%s/skins/%s",
835                  skinDirRoot, skinName);
836 
837     if (p >= end || !path_exists(temp)) {
838         DD("    ignore bad skin directory %s", temp);
839         return 0;
840     }
841 
842     /* first, is this a normal skin directory ? */
843     if (_checkSkinPath(temp)) {
844         /* yes */
845         DD("    found skin directory: %s", temp);
846         return 1;
847     }
848 
849     /* second, is it an alias to another skin ? */
850     *p      = 0;
851     result  = 0;
852     scanner = dirScanner_new(temp);
853     if (scanner != NULL) {
854         for (;;) {
855             const char*  file = dirScanner_next(scanner);
856 
857             if (file == NULL)
858                 break;
859 
860             if (strncmp(file, "alias-", 6) || file[6] == 0)
861                 continue;
862 
863             p = bufprint(temp, end, "%s/skins/%s",
864                             skinDirRoot, file+6);
865 
866             if (p < end && _checkSkinPath(temp)) {
867                 /* yes, it's an alias */
868                 DD("    skin alias '%s' points to skin directory: %s",
869                    file+6, temp);
870                 result = 1;
871                 break;
872             }
873         }
874         dirScanner_free(scanner);
875     }
876     return result;
877 }
878 
879 /* try to see if the skin name leads to a magic skin or skin path directly
880  * returns 1 on success, 0 on error.
881  * on success, this sets up 'skinDirPath' and 'skinName' in the AvdInfo.
882  */
883 static int
_getSkinPathFromName(AvdInfo * i,const char * skinName)884 _getSkinPathFromName( AvdInfo*  i, const char*  skinName )
885 {
886     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
887 
888     /* if the skin name has the format 'NNNNxNNN' where
889     * NNN is a decimal value, then this is a 'magic' skin
890     * name that doesn't require a skin directory
891     */
892     if (isdigit(skinName[0])) {
893         int  width, height;
894         if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
895             D("'magic' skin format detected: %s", skinName);
896             i->skinName    = ASTRDUP(skinName);
897             i->skinDirPath = NULL;
898             return 1;
899         }
900     }
901 
902     /* is the skin name a direct path to the skin directory ? */
903     if (_checkSkinPath(skinName)) {
904         goto FOUND_IT;
905     }
906 
907     /* is the skin name a relative path from the SDK root ? */
908     p = bufprint(temp, end, "%s/%s", i->sdkRootPath, skinName);
909     if (p < end && _checkSkinPath(temp)) {
910         skinName = temp;
911         goto FOUND_IT;
912     }
913 
914     /* nope */
915     return 0;
916 
917 FOUND_IT:
918     if (path_split(skinName, &i->skinDirPath, &i->skinName) < 0) {
919         derror("malformed skin name: %s", skinName);
920         exit(2);
921     }
922     D("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
923     return 1;
924 }
925 
926 /* return 0 on success, -1 on error */
927 static int
_getSkin(AvdInfo * i,AvdInfoParams * params)928 _getSkin( AvdInfo*  i, AvdInfoParams*  params )
929 {
930     char*  skinName;
931     char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
932     char   explicitSkin = 1;
933 
934     /* this function is used to compute the 'skinName' and 'skinDirPath'
935      * fields of the AvdInfo.
936      */
937 
938     /* processing here is a bit tricky, so here's how it happens
939      *
940      * - command-line option '-skin <name>' can be used to specify the
941      *   name of a skin, to override the AVD settings.
942      *
943      * - skins are searched from <dir>/../skins for each <dir> in the
944      *   images search list, unless a '-skindir <path>' option has been
945      *   provided on the command-line
946      *
947      * - otherwise, the config.ini can also contain a SKIN_PATH key that
948      *   shall  give the full path to the skin directory, either relative
949      *   to the SDK root, or an absolute path.
950      *
951      * - skin names like '320x480' corresponds to "magic skins" that
952      *   simply display a framebuffer, without any ornaments of the
953      *   corresponding size. They do not correspond to any real skin
954      *   directory / files and are handled later. But they must be
955      *   recognized here and report a NULL skindir.
956      */
957     if (params->skinName) {
958         skinName = ASTRDUP(params->skinName);
959     } else {
960         skinName = iniFile_getString( i->configIni, SKIN_PATH );
961         explicitSkin = 0;
962     }
963 
964     /* first, check that the skin name is not magic or a direct
965      * directory path
966      */
967     if (skinName != NULL && _getSkinPathFromName(i, skinName)) {
968         AFREE(skinName);
969         return 0;
970     }
971 
972     /* if not, the default skinName is "HVGA" */
973     if (skinName == NULL) {
974         skinName = ASTRDUP(SKIN_DEFAULT);
975         explicitSkin = 0;
976     }
977 
978     i->skinName = skinName;
979 
980     /* now try to find the skin directory for that name -
981      * first try the content directory */
982     do {
983         /* if there is a single 'skin' directory in
984          * the content directory, assume that's what the
985          * user wants,  unless an explicit name was given
986          */
987         if (!explicitSkin) {
988             p = bufprint(temp, end, "%s/skin", i->contentPath);
989             if (p < end && _checkSkinPath(temp)) {
990                 D("using skin content from %s", temp);
991                 AFREE(i->skinName);
992                 i->skinName    = ASTRDUP("skin");
993                 i->skinDirPath = ASTRDUP(i->contentPath);
994                 return 0;
995             }
996         }
997 
998         /* look in content directory */
999         if (_checkSkinDir(temp, end, i->contentPath, skinName))
1000             break;
1001 
1002         /* look in the search paths. For each <dir> in the list,
1003          * look the skins in <dir>/.. */
1004         {
1005             int  nn;
1006             for (nn = 0; nn < i->numSearchPaths; nn++) {
1007                 char*  parentDir = path_parent(i->searchPaths[nn], 1);
1008                 int    ret;
1009                 if (parentDir == NULL)
1010                     continue;
1011                 ret=_checkSkinDir(temp, end, parentDir, skinName);
1012                 AFREE(parentDir);
1013                 if (ret)
1014                   break;
1015             }
1016             if (nn < i->numSearchPaths)
1017                 break;
1018         }
1019 
1020         /* didn't find it */
1021         if (explicitSkin) {
1022             derror("could not find directory for skin '%s',"
1023                    " please use a different name", skinName);
1024             exit(2);
1025         } else {
1026             dwarning("no skin directory matched '%s', so reverted to default",
1027                      skinName);
1028             AFREE(i->skinName);
1029             params->skinName = SKIN_DEFAULT;
1030             return _getSkin(i, params);
1031         }
1032 
1033         return -1;
1034 
1035     } while (0);
1036 
1037     /* separate skin name from parent directory. the skin name
1038      * returned in 'temp' might be different from the original
1039      * one due to alias expansion so strip it.
1040      */
1041     AFREE(i->skinName);
1042 
1043     if (path_split(temp, &i->skinDirPath, &i->skinName) < 0) {
1044         derror("weird skin path: %s", temp);
1045         return -1;
1046     }
1047     DD("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
1048     return 0;
1049 }
1050 
1051 /* If the user didn't explicitely provide an SD Card path,
1052  * check the SDCARD_PATH key in config.ini and use that if
1053  * available.
1054  */
1055 static void
_getSDCardPath(AvdInfo * i,AvdInfoParams * params)1056 _getSDCardPath( AvdInfo*  i, AvdInfoParams*  params )
1057 {
1058     const char*  path;
1059 
1060     if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL)
1061         return;
1062 
1063     path = iniFile_getString(i->configIni, SDCARD_PATH);
1064     if (path == NULL)
1065         return;
1066 
1067     params->forcePaths[AVD_IMAGE_SDCARD] = path;
1068 }
1069 
1070 AvdInfo*
avdInfo_new(const char * name,AvdInfoParams * params)1071 avdInfo_new( const char*  name, AvdInfoParams*  params )
1072 {
1073     AvdInfo*  i;
1074 
1075     if (name == NULL)
1076         return NULL;
1077 
1078     if (!_checkAvdName(name)) {
1079         derror("virtual device name contains invalid characters");
1080         exit(1);
1081     }
1082 
1083     ANEW0(i);
1084     i->deviceName = ASTRDUP(name);
1085 
1086     if ( _getSdkRoot(i)     < 0 ||
1087          _getRootIni(i)     < 0 ||
1088          _getContentPath(i) < 0 ||
1089          _getConfigIni(i)   < 0 )
1090         goto FAIL;
1091 
1092     /* look for image search paths. handle post 1.1/pre cupcake
1093      * obsolete SDKs.
1094      */
1095     _getSearchPaths(i);
1096     _getSDCardPath(i, params);
1097 
1098     /* don't need this anymore */
1099     iniFile_free(i->rootIni);
1100     i->rootIni = NULL;
1101 
1102     if ( _getImagePaths(i, params) < 0 ||
1103          _getSkin      (i, params) < 0 )
1104         goto FAIL;
1105 
1106     return i;
1107 
1108 FAIL:
1109     avdInfo_free(i);
1110     return NULL;
1111 }
1112 
1113 /***************************************************************
1114  ***************************************************************
1115  *****
1116  *****    ANDROID BUILD SUPPORT
1117  *****
1118  *****    The code below corresponds to the case where we're
1119  *****    starting the emulator inside the Android build
1120  *****    system. The main differences are that:
1121  *****
1122  *****    - the $ANDROID_PRODUCT_OUT directory is used as the
1123  *****      content file.
1124  *****
1125  *****    - built images must not be modified by the emulator,
1126  *****      so system.img must be copied to a temporary file
1127  *****      and userdata.img must be copied to userdata-qemu.img
1128  *****      if the latter doesn't exist.
1129  *****
1130  *****    - the kernel and default skin directory are taken from
1131  *****      prebuilt
1132  *****
1133  *****    - there is no root .ini file, or any config.ini in
1134  *****      the content directory, no SDK images search path.
1135  *****/
1136 
1137 /* used to fake a config.ini located in the content directory */
1138 static int
_getBuildConfigIni(AvdInfo * i)1139 _getBuildConfigIni( AvdInfo*  i )
1140 {
1141     /* a blank file is ok at the moment */
1142     i->configIni = iniFile_newFromMemory( "", 0 );
1143     return 0;
1144 }
1145 
1146 static int
_getBuildImagePaths(AvdInfo * i,AvdInfoParams * params)1147 _getBuildImagePaths( AvdInfo*  i, AvdInfoParams*  params )
1148 {
1149     int   wipeData  = (params->flags & AVDINFO_WIPE_DATA) != 0;
1150     int   noCache   = (params->flags & AVDINFO_NO_CACHE) != 0;
1151     int   noSdCard  = (params->flags & AVDINFO_NO_SDCARD) != 0;
1152 
1153     char         temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
1154     char*        srcData;
1155     ImageLoader  l[1];
1156 
1157     imageLoader_init(l, i, params);
1158 
1159     /** load the kernel image
1160      **/
1161 
1162     /* if it is not in the out directory, get it from prebuilt
1163      */
1164     imageLoader_set ( l, AVD_IMAGE_KERNEL );
1165 
1166     if ( !imageLoader_load( l, IMAGE_OPTIONAL |
1167                                IMAGE_DONT_LOCK ) )
1168     {
1169 #define  PREBUILT_KERNEL_PATH   "prebuilt/android-arm/kernel/kernel-qemu"
1170         p = bufprint(temp, end, "%s/%s", i->androidBuildRoot,
1171                         PREBUILT_KERNEL_PATH);
1172         if (p >= end || !path_exists(temp)) {
1173             derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
1174             exit(1);
1175         }
1176         imageLoader_setPath(l, temp);
1177     }
1178 
1179     /** load the data partition. note that we use userdata-qemu.img
1180      ** since we don't want to modify userdata.img at all
1181      **/
1182     imageLoader_set ( l, AVD_IMAGE_USERDATA );
1183     imageLoader_load( l, IMAGE_OPTIONAL | IMAGE_DONT_LOCK );
1184 
1185     /* get the path of the source file, and check that it actually exists
1186      * if the user didn't provide an explicit data file
1187      */
1188     srcData = imageLoader_extractPath(l);
1189     if (srcData == NULL && params->forcePaths[AVD_IMAGE_USERDATA] == NULL) {
1190         derror("There is no %s image in your build directory. Please make a full build",
1191                 l->imageText, l->imageFile);
1192         exit(2);
1193     }
1194 
1195     /* get the path of the target file */
1196     l->imageFile = "userdata-qemu.img";
1197     imageLoader_load( l, IMAGE_OPTIONAL |
1198                          IMAGE_EMPTY_IF_MISSING |
1199                          IMAGE_IGNORE_IF_LOCKED );
1200 
1201     /* force a data wipe if we just created the image */
1202     if (l->pState[0] == IMAGE_STATE_LOCKED_EMPTY)
1203         wipeData = 1;
1204 
1205     /* if the image was already locked, create a temp file
1206      * then force a data wipe.
1207      */
1208     if (l->pPath[0] == NULL) {
1209         TempFile*  temp = tempfile_create();
1210         imageLoader_setPath(l, tempfile_path(temp));
1211         dwarning( "Another emulator is running. user data changes will *NOT* be saved");
1212         wipeData = 1;
1213     }
1214 
1215     /* in the case of a data wipe, copy userdata.img into
1216      * the destination */
1217     if (wipeData) {
1218         if (srcData == NULL || !path_exists(srcData)) {
1219             derror("There is no %s image in your build directory. Please make a full build",
1220                    l->imageText, _imageFileNames[l->id]);
1221             exit(2);
1222         }
1223         if (path_copy_file( l->pPath[0], srcData ) < 0) {
1224             derror("could not initialize %s image from %s: %s",
1225                    l->imageText, temp, strerror(errno));
1226             exit(2);
1227         }
1228     }
1229 
1230     AFREE(srcData);
1231 
1232     /** load the ramdisk image
1233      **/
1234     imageLoader_set ( l, AVD_IMAGE_RAMDISK );
1235     imageLoader_load( l, IMAGE_REQUIRED |
1236                          IMAGE_DONT_LOCK );
1237 
1238     /** load the system image. read-only. the caller must
1239      ** take care of checking the state
1240      **/
1241     imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
1242     imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK );
1243 
1244     /* force the system image to read-only status */
1245     l->pState[0] = IMAGE_STATE_READONLY;
1246 
1247     /** cache partition handling
1248      **/
1249     if (!noCache) {
1250         imageLoader_set (l, AVD_IMAGE_CACHE);
1251 
1252         /* if the user provided one cache image, lock & use it */
1253         if ( params->forcePaths[l->id] != NULL ) {
1254             imageLoader_load(l, IMAGE_REQUIRED |
1255                                 IMAGE_IGNORE_IF_LOCKED);
1256         }
1257     }
1258 
1259     /** SD Card image
1260      **/
1261     if (!noSdCard) {
1262         imageLoader_set (l, AVD_IMAGE_SDCARD);
1263         imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED);
1264     }
1265 
1266     return 0;
1267 }
1268 
1269 static int
_getBuildSkin(AvdInfo * i,AvdInfoParams * params)1270 _getBuildSkin( AvdInfo*  i, AvdInfoParams*  params )
1271 {
1272     /* the (current) default skin name for our build system */
1273     const char*  skinName = params->skinName;
1274     const char*  skinDir  = params->skinRootPath;
1275     char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
1276     char*        q;
1277 
1278     if (!skinName) {
1279         /* the (current) default skin name for the build system */
1280         skinName = SKIN_DEFAULT;
1281         D("selecting default skin name '%s'", skinName);
1282     }
1283 
1284     if (!skinDir) {
1285 
1286 #define  PREBUILT_SKINS_DIR  "sdk/emulator/skins"
1287 #define  PRODUCT_SKIN_DIR "skin"
1288 
1289         do {
1290             /* look for the product skin in $ANDROID_PRODUCT_OUT/skin if no skin name is defined */
1291             if (!params->skinName) {
1292                 /* look for <product_out>/skin first */
1293                 p = bufprint( temp, end, "%s/skin",
1294                               i->androidOut );
1295                 if (path_exists(temp)) {
1296                     p = bufprint( temp, end, "%s",
1297                                   i->androidOut );
1298                     skinName = PRODUCT_SKIN_DIR;
1299                     D("selecting default product skin at '%s/%s'", temp, skinName);
1300                     break;
1301                 }
1302             }
1303 
1304             /* next try in <sysdir>/../skins */
1305             p = bufprint( temp, end, "%s/../skins",
1306                           i->androidBuildRoot );
1307             if (path_exists(temp))
1308                 break;
1309 
1310             /* the (current) default skin directory */
1311             p = bufprint( temp, end, "%s/%s",
1312                         i->androidBuildRoot, PREBUILT_SKINS_DIR );
1313         } while (0);
1314 
1315     } else {
1316         p = bufprint( temp, end, "%s", skinDir );
1317     }
1318 
1319     i->skinName = ASTRDUP(skinName);
1320 
1321     q  = bufprint(p, end, "/%s/layout", skinName);
1322     if (q >= end || !path_exists(temp)) {
1323         DD("skin content directory does not exist: %s", temp);
1324         if (skinDir)
1325             dwarning("could not find valid skin '%s' in %s:\n",
1326                      skinName, temp);
1327         return -1;
1328     }
1329     *p = 0;
1330     DD("found skin path: %s", temp);
1331     i->skinDirPath = ASTRDUP(temp);
1332 
1333     return 0;
1334 }
1335 
1336 /* Read a hardware.ini if it is located in the skin directory */
1337 static int
_getBuildHardwareIni(AvdInfo * i)1338 _getBuildHardwareIni( AvdInfo*  i )
1339 {
1340     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
1341 
1342     if (i->skinDirPath == NULL || i->skinName == NULL)
1343         return 0;
1344 
1345     p = bufprint(temp, end, "%s/%s/hardware.ini", i->skinDirPath, i->skinName);
1346     if (p >= end || !path_exists(temp)) {
1347         DD("no skin-specific hardware.ini in %s", i->skinDirPath);
1348         return 0;
1349     }
1350 
1351     D("found skin-specific hardware.ini: %s", temp);
1352     i->hardwareIni = iniFile_newFromFile(temp);
1353     if (i->hardwareIni == NULL)
1354         return -1;
1355 
1356     return 0;
1357 }
1358 
1359 
1360 AvdInfo*
avdInfo_newForAndroidBuild(const char * androidBuildRoot,const char * androidOut,AvdInfoParams * params)1361 avdInfo_newForAndroidBuild( const char*     androidBuildRoot,
1362                             const char*     androidOut,
1363                             AvdInfoParams*  params )
1364 {
1365     AvdInfo*  i;
1366 
1367     ANEW0(i);
1368 
1369     i->inAndroidBuild   = 1;
1370     i->androidBuildRoot = ASTRDUP(androidBuildRoot);
1371     i->androidOut       = ASTRDUP(androidOut);
1372     i->contentPath      = ASTRDUP(androidOut);
1373 
1374     /* TODO: find a way to provide better information from the build files */
1375     i->deviceName = ASTRDUP("<build>");
1376 
1377     if (_getBuildConfigIni(i)          < 0 ||
1378         _getBuildImagePaths(i, params) < 0 )
1379         goto FAIL;
1380 
1381     /* we don't need to fail if there is no valid skin */
1382     _getBuildSkin(i, params);
1383     _getBuildHardwareIni(i);
1384 
1385     return i;
1386 
1387 FAIL:
1388     avdInfo_free(i);
1389     return NULL;
1390 }
1391 
1392 const char*
avdInfo_getName(AvdInfo * i)1393 avdInfo_getName( AvdInfo*  i )
1394 {
1395     return i ? i->deviceName : NULL;
1396 }
1397 
1398 const char*
avdInfo_getImageFile(AvdInfo * i,AvdImageType imageType)1399 avdInfo_getImageFile( AvdInfo*  i, AvdImageType  imageType )
1400 {
1401     if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
1402         return NULL;
1403 
1404     return i->imagePath[imageType];
1405 }
1406 
1407 uint64_t
avdInfo_getImageFileSize(AvdInfo * i,AvdImageType imageType)1408 avdInfo_getImageFileSize( AvdInfo*  i, AvdImageType  imageType )
1409 {
1410     const char* file = avdInfo_getImageFile(i, imageType);
1411     uint64_t    size;
1412 
1413     if (file == NULL)
1414         return 0ULL;
1415 
1416     if (path_get_size(file, &size) < 0)
1417         return 0ULL;
1418 
1419     return size;
1420 }
1421 
1422 int
avdInfo_isImageReadOnly(AvdInfo * i,AvdImageType imageType)1423 avdInfo_isImageReadOnly( AvdInfo*  i, AvdImageType  imageType )
1424 {
1425     if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
1426         return 1;
1427 
1428     return (i->imageState[imageType] == IMAGE_STATE_READONLY);
1429 }
1430 
1431 const char*
avdInfo_getSkinName(AvdInfo * i)1432 avdInfo_getSkinName( AvdInfo*  i )
1433 {
1434     return i->skinName;
1435 }
1436 
1437 const char*
avdInfo_getSkinDir(AvdInfo * i)1438 avdInfo_getSkinDir ( AvdInfo*  i )
1439 {
1440     return i->skinDirPath;
1441 }
1442 
1443 int
avdInfo_getHwConfig(AvdInfo * i,AndroidHwConfig * hw)1444 avdInfo_getHwConfig( AvdInfo*  i, AndroidHwConfig*  hw )
1445 {
1446     IniFile*   ini = i->configIni;
1447     int        ret;
1448 
1449     if (ini == NULL)
1450         ini = iniFile_newFromMemory("", 0);
1451 
1452     ret = androidHwConfig_read(hw, ini);
1453 
1454     if (ini != i->configIni)
1455         iniFile_free(ini);
1456 
1457     if (ret == 0 && i->hardwareIni != NULL) {
1458         ret = androidHwConfig_read(hw, i->hardwareIni);
1459     }
1460 
1461     /* special product-specific hardware configuration */
1462     if (i->androidOut != NULL)
1463     {
1464         char*  p = strrchr(i->androidOut, '/');
1465         if (p != NULL && p[0] != 0) {
1466             if (p[1] == 's') {
1467                 hw->hw_keyboard = 0;
1468             }
1469         }
1470     }
1471 
1472     return ret;
1473 }
1474 
1475 const char*
avdInfo_getContentPath(AvdInfo * i)1476 avdInfo_getContentPath( AvdInfo*  i )
1477 {
1478     return i->contentPath;
1479 }
1480 
1481 int
avdInfo_inAndroidBuild(AvdInfo * i)1482 avdInfo_inAndroidBuild( AvdInfo*  i )
1483 {
1484     return i->inAndroidBuild;
1485 }
1486 
1487 char*
avdInfo_getTracePath(AvdInfo * i,const char * traceName)1488 avdInfo_getTracePath( AvdInfo*  i, const char*  traceName )
1489 {
1490     char   tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
1491 
1492     if (i == NULL || traceName == NULL || traceName[0] == 0)
1493         return NULL;
1494 
1495     if (i->inAndroidBuild) {
1496         p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
1497                       i->androidOut, traceName );
1498     } else {
1499         p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
1500                       i->contentPath, traceName );
1501     }
1502     return ASTRDUP(tmp);
1503 }
1504