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