blob: 5634ef67a495f32230e1f50431dbfc2601feede8 [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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080095/* 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 */
113typedef 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
121struct 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;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800133 char* contentPath;
134 IniFile* rootIni; /* root <foo>.ini file */
135 IniFile* configIni; /* virtual device's config.ini */
David 'Digit' Turnerfbcab322010-04-06 18:35:54 -0700136 IniFile* hardwareIni; /* skin-specific hardware.ini */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800137
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
148void
149avdInfo_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
David 'Digit' Turnerfbcab322010-04-06 18:35:54 -0700170 if (i->hardwareIni) {
171 iniFile_free(i->hardwareIni);
172 i->hardwareIni = NULL;
173 }
174
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800175 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);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800186 }
187
188 AFREE(i->deviceName);
189 AFREE(i);
190 }
191}
192
193/* list of default file names for each supported image file type */
194static 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 */
201static 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 */
217static int
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
247static void
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;
The Android Open Source Project92c73112009-03-05 14:34:31 -0800275 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 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800280 else
281 DD("found a total of %d search paths for this AVD", count);
282}
283
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800284static int
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 */
297static int
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
322static int
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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800336/* find and parse the config.ini file from the content directory */
337static int
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 */
376typedef 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
387static void
388imageLoader_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 */
396static void
397imageLoader_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 */
409static char*
410imageLoader_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
420static char*
421imageLoader_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 */
429enum {
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 */
444static char*
445imageLoader_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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800466 return NULL;
467
468 } while (0);
469
470FOUND:
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 */
482static char*
483imageLoader_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 */
509static void
510imageLoader_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 */
540static void
541imageLoader_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 */
563static void
564imageLoader_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 */
600static char*
601imageLoader_load( ImageLoader* l,
602 unsigned flags )
603{
604 const char* path = NULL;
605
David Turner47356942009-04-05 14:23:06 -0700606 /* 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 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800612 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
679EXIT:
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 */
689static int
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 );
David Turner47356942009-04-05 14:23:06 -0700716 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800717
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
The Android Open Source Project92c73112009-03-05 14:34:31 -0800739 imageLoader_set( l, AVD_IMAGE_INITDATA );
740 if (imageLoader_lookupSdk(l) == NULL) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800741 derror("can't locate initial %s image in SDK",
742 l->imageText);
743 exit(2);
744 }
745 srcPath = imageLoader_extractPath(l);
746
The Android Open Source Project92c73112009-03-05 14:34:31 -0800747 imageLoader_set( l, AVD_IMAGE_USERDATA );
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800748 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) {
David 'Digit' Turner92568952010-04-15 15:04:16 -0700781 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 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800798 }
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 */
806static int
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 */
824static int
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 */
883static int
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
917FOUND_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 */
927static int
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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001020 /* 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
David Turner47356942009-04-05 14:23:06 -07001051/* If the user didn't explicitely provide an SD Card path,
David 'Digit' Turner92568952010-04-15 15:04:16 -07001052 * check the SDCARD_PATH key in config.ini and use that if
David Turner47356942009-04-05 14:23:06 -07001053 * available.
1054 */
1055static void
David 'Digit' Turner92568952010-04-15 15:04:16 -07001056_getSDCardPath( AvdInfo* i, AvdInfoParams* params )
David Turner47356942009-04-05 14:23:06 -07001057{
1058 const char* path;
1059
David 'Digit' Turner92568952010-04-15 15:04:16 -07001060 if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL)
David Turner47356942009-04-05 14:23:06 -07001061 return;
1062
David 'Digit' Turner92568952010-04-15 15:04:16 -07001063 path = iniFile_getString(i->configIni, SDCARD_PATH);
David Turner47356942009-04-05 14:23:06 -07001064 if (path == NULL)
1065 return;
1066
David 'Digit' Turner92568952010-04-15 15:04:16 -07001067 params->forcePaths[AVD_IMAGE_SDCARD] = path;
David Turner47356942009-04-05 14:23:06 -07001068}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001069
1070AvdInfo*
1071avdInfo_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);
David 'Digit' Turner92568952010-04-15 15:04:16 -07001096 _getSDCardPath(i, params);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001097
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001098 /* 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
1108FAIL:
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
The Android Open Source Project92c73112009-03-05 14:34:31 -08001134 ***** the content directory, no SDK images search path.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001135 *****/
1136
1137/* used to fake a config.ini located in the content directory */
1138static int
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
1146static int
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
1269static int
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;
David Turner2f7bb382009-03-25 15:30:56 -07001281 D("selecting default skin name '%s'", skinName);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001282 }
1283
1284 i->skinName = ASTRDUP(skinName);
1285
1286 if (!skinDir) {
1287
Xavier Ducrohet5bc61822009-11-20 12:24:17 -08001288#define PREBUILT_SKINS_DIR "sdk/emulator/skins"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001289
David Turner94088e22009-04-14 14:46:08 -07001290 do {
1291 /* try in <sysdir>/../skins first */
1292 p = bufprint( temp, end, "%s/../skins",
1293 i->androidBuildRoot );
1294 if (path_exists(temp))
1295 break;
1296
1297 /* the (current) default skin directory */
1298 p = bufprint( temp, end, "%s/%s",
1299 i->androidBuildRoot, PREBUILT_SKINS_DIR );
1300 } while (0);
1301
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001302 } else {
1303 p = bufprint( temp, end, "%s", skinDir );
1304 }
1305
1306 q = bufprint(p, end, "/%s/layout", skinName);
1307 if (q >= end || !path_exists(temp)) {
1308 DD("skin content directory does not exist: %s", temp);
1309 if (skinDir)
1310 dwarning("could not find valid skin '%s' in %s:\n",
1311 skinName, temp);
1312 return -1;
1313 }
1314 *p = 0;
1315 DD("found skin path: %s", temp);
1316 i->skinDirPath = ASTRDUP(temp);
1317
1318 return 0;
1319}
1320
David 'Digit' Turnerfbcab322010-04-06 18:35:54 -07001321/* Read a hardware.ini if it is located in the skin directory */
1322static int
1323_getBuildHardwareIni( AvdInfo* i )
1324{
1325 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
1326
1327 if (i->skinDirPath == NULL || i->skinName == NULL)
1328 return 0;
1329
1330 p = bufprint(temp, end, "%s/%s/hardware.ini", i->skinDirPath, i->skinName);
1331 if (p >= end || !path_exists(temp)) {
1332 DD("no skin-specific hardware.ini in %s", i->skinDirPath);
1333 return 0;
1334 }
1335
1336 D("found skin-specific hardware.ini: %s", temp);
1337 i->hardwareIni = iniFile_newFromFile(temp);
1338 if (i->hardwareIni == NULL)
1339 return -1;
1340
1341 return 0;
1342}
1343
1344
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001345AvdInfo*
1346avdInfo_newForAndroidBuild( const char* androidBuildRoot,
1347 const char* androidOut,
1348 AvdInfoParams* params )
1349{
1350 AvdInfo* i;
1351
1352 ANEW0(i);
1353
1354 i->inAndroidBuild = 1;
1355 i->androidBuildRoot = ASTRDUP(androidBuildRoot);
1356 i->androidOut = ASTRDUP(androidOut);
1357 i->contentPath = ASTRDUP(androidOut);
1358
1359 /* TODO: find a way to provide better information from the build files */
1360 i->deviceName = ASTRDUP("<build>");
1361
1362 if (_getBuildConfigIni(i) < 0 ||
1363 _getBuildImagePaths(i, params) < 0 )
1364 goto FAIL;
1365
1366 /* we don't need to fail if there is no valid skin */
1367 _getBuildSkin(i, params);
David 'Digit' Turnerfbcab322010-04-06 18:35:54 -07001368 _getBuildHardwareIni(i);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001369
1370 return i;
1371
1372FAIL:
1373 avdInfo_free(i);
1374 return NULL;
1375}
1376
1377const char*
1378avdInfo_getName( AvdInfo* i )
1379{
1380 return i ? i->deviceName : NULL;
1381}
1382
1383const char*
1384avdInfo_getImageFile( AvdInfo* i, AvdImageType imageType )
1385{
1386 if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
1387 return NULL;
1388
1389 return i->imagePath[imageType];
1390}
1391
David 'Digit' Turnercd059b12009-08-28 19:36:27 +02001392uint64_t
1393avdInfo_getImageFileSize( AvdInfo* i, AvdImageType imageType )
1394{
1395 const char* file = avdInfo_getImageFile(i, imageType);
1396 uint64_t size;
1397
1398 if (file == NULL)
1399 return 0ULL;
1400
1401 if (path_get_size(file, &size) < 0)
1402 return 0ULL;
1403
1404 return size;
1405}
1406
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001407int
1408avdInfo_isImageReadOnly( AvdInfo* i, AvdImageType imageType )
1409{
1410 if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
1411 return 1;
1412
1413 return (i->imageState[imageType] == IMAGE_STATE_READONLY);
1414}
1415
1416const char*
1417avdInfo_getSkinName( AvdInfo* i )
1418{
1419 return i->skinName;
1420}
1421
1422const char*
1423avdInfo_getSkinDir ( AvdInfo* i )
1424{
1425 return i->skinDirPath;
1426}
1427
1428int
1429avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw )
1430{
1431 IniFile* ini = i->configIni;
1432 int ret;
1433
1434 if (ini == NULL)
1435 ini = iniFile_newFromMemory("", 0);
1436
1437 ret = androidHwConfig_read(hw, ini);
1438
1439 if (ini != i->configIni)
1440 iniFile_free(ini);
1441
David 'Digit' Turnerfbcab322010-04-06 18:35:54 -07001442 if (ret == 0 && i->hardwareIni != NULL) {
1443 ret = androidHwConfig_read(hw, i->hardwareIni);
1444 }
1445
David Turner2f7bb382009-03-25 15:30:56 -07001446 /* special product-specific hardware configuration */
David Turnere8b10bc2009-03-27 18:21:13 -07001447 if (i->androidOut != NULL)
David Turner2f7bb382009-03-25 15:30:56 -07001448 {
1449 char* p = strrchr(i->androidOut, '/');
1450 if (p != NULL && p[0] != 0) {
1451 if (p[1] == 's') {
1452 hw->hw_keyboard = 0;
1453 }
1454 }
1455 }
1456
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001457 return ret;
1458}
1459
1460const char*
1461avdInfo_getContentPath( AvdInfo* i )
1462{
1463 return i->contentPath;
1464}
1465
1466int
1467avdInfo_inAndroidBuild( AvdInfo* i )
1468{
1469 return i->inAndroidBuild;
1470}
1471
1472char*
1473avdInfo_getTracePath( AvdInfo* i, const char* traceName )
1474{
1475 char tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
1476
1477 if (i == NULL || traceName == NULL || traceName[0] == 0)
1478 return NULL;
1479
1480 if (i->inAndroidBuild) {
1481 p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
1482 i->androidOut, traceName );
1483 } else {
1484 p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
1485 i->contentPath, traceName );
1486 }
1487 return ASTRDUP(tmp);
1488}