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