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