blob: 230ddaab3e8998bf19385442a257bde76bdffe07 [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
26/* define this to 1 to support obsolete platform/add-on
27 * specific parsing and path searching as was used temporarily
28 * in post-1.1 / pre-cupcake SDKs.
29 *
30 * the corresponding code should be removed soon.
31 */
32#define SUPPORT_PLATFORM_OR_ADDON 1
33
34/* global variables - see android/globals.h */
35AvdInfoParams android_avdParams[1];
36AvdInfo* android_avdInfo;
37
38/* for debugging */
39#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
40#define DD(...) VERBOSE_PRINT(avd_config,__VA_ARGS__)
41
42/* technical note on how all of this is supposed to work:
43 *
44 * Each AVD corresponds to a "content directory" that is used to
45 * store persistent disk images and configuration files. Most remarkable
46 * are:
47 *
48 * - a "config.ini" file used to hold configuration information for the
49 * AVD
50 *
51 * - mandatory user data image ("userdata-qemu.img") and cache image
52 * ("cache.img")
53 *
54 * - optional mutable system image ("system-qemu.img"), kernel image
55 * ("kernel-qemu") and read-only ramdisk ("ramdisk.img")
56 *
57 * When starting up an AVD, the emulator looks for relevant disk images
58 * in the content directory. If it doesn't find a given image there, it
59 * will try to search in the list of system directories listed in the
60 * 'config.ini' file through one of the following (key,value) pairs:
61 *
62 * images.sysdir.1 = <first search path>
63 * images.sysdir.2 = <second search path>
64 *
65 * The search paths can be absolute, or relative to the root SDK installation
66 * path (which is determined from the emulator program's location, or from the
67 * ANDROID_SDK_ROOT environment variable).
68 *
69 * Individual image disk search patch can be over-riden on the command-line
70 * with one of the usual options.
71 */
72
73#if SUPPORT_PLATFORM_OR_ADDON
74/*
75 * BELOW IS THE DOCUMENTATION FOR AN OBSOLETE SCHEME THAT USED TO BE MORE
76 * COMPLEX TO IMPLEMENT, AND EXPOSED TOO MUCH SDK INTERNALS WITHIN THE
77 * EMULATOR SOURCE CODE.
78 *
79 * THE CORRESPONDING CODE IS STILL THERE FOR LEGACY SUPPORT REASON BUT WILL
80 * SOON BE REMOVED FOR SIMPLIFICATION REASONS.
81 *
82 * we assume the following SDK layout:
83 *
84 * SDK/
85 * tools/
86 * emulator[.exe]
87 * libs/
88 * hardware-properties.ini
89 * ...
90 *
91 * platforms/
92 * <platform1>/
93 * build.prop
94 * images/
95 * <default kernel/disk images>
96 * skins/
97 * default/ --> default skin
98 * layout
99 * <skin bitmaps>
100 * <skin2>/ --> another skin
101 * layout
102 * <skin bitmaps>
103 * <skin3>/ --> skin alias to <skin2>
104 * alias-<skin2>
105 *
106 * <platform2>/
107 * build.prop
108 * images/
109 * <other default kernel/disk images>
110 *
111 * add-ons/
112 * <partner1>/
113 * manifest.ini
114 * images/
115 * <replacement disk images>
116 *
117 * <partner2>/
118 * manifest.ini
119 * <replacement disk images>
120 * hardware.ini
121 * skins/
122 * default/
123 * layout
124 * <skin bitmaps>
125 * <skin2>/
126 * layout
127 * <skin bitmaps>
128 *
129 *
130 * we define a 'platform' as a directory that provides a complete
131 * set of disk/kernel images, some skins, as well as a build.prop
132 * file.
133 *
134 * we define an 'addon' as a directory that provides additionnal
135 * or replacement files related to a given existing platform.
136 * each add-on provides at the minimum a 'manifest.ini' file
137 * that describes it (see below).
138 *
139 * important notes:
140 *
141 * - the build.prop file of a given platform directory contains
142 * a line that reads 'ro.build.version.sdk=<version>' where
143 * <version> is an integer corresponding to the corresponding
144 * official API version number as defined by Android.
145 *
146 * each platform provided with the SDK must have a unique
147 * version number.
148 *
149 * - the manifest.ini of a given addon must contain lines
150 * that include:
151 *
152 * name=<addOnName>
153 * vendor=<vendorName>
154 * api=<version>
155 *
156 * where <version> is used to identify the platform the add-on
157 * refers to. Note that the platform's directory name is
158 * irrelevant to the matching algorithm.
159 *
160 * each addon available must have a unique
161 * <vendor>:<name>:<sdk> triplet
162 *
163 * - an add-on can provide a hardware.ini file. If present, this
164 * is used to force the hardware setting of any virtual device
165 * built from the add-on.
166 *
167 * - the file in SDK/tools/lib/hardware-properties.ini declares which
168 * hardware properties are supported by the emulator binary.
169 * these can appear in the config.ini file of a given virtual
170 * device, or the hardware.ini of a given add-on.
171 *
172 * normally, a virtual device corresponds to:
173 *
174 * - a root configuration file, placed in ~/.android/avd/<foo>.ini
175 * where <foo> is the name of the virtual device.
176 *
177 * - a "content" directory, which contains disk images for the
178 * virtual device (e.g. at a minimum, the userdata.img file)
179 * plus some configuration information.
180 *
181 * - the root config file must have at least two lines like:
182 *
183 * path=<pathToContentDirectory>
184 * target=<targetAddonOrPlatform>
185 *
186 * the 'path' value must point to the location of
187 * the virtual device's content directory. By default, this
188 * should be ~/.android/avd/<foo>/, though the user should be
189 * able to choose an alternative path at creation time.
190 *
191 * the 'target' value can be one of:
192 *
193 * android-<version>
194 * <vendor>:<name>:<version>
195 *
196 * the first form is used to refer to a given platform.
197 * the second form is used to refer to a unique add-on.
198 * in both forms, <version> must be an integer that
199 * matches one of the available platforms.
200 *
201 * <vendor>:<name>:<version> must match the triplet of one
202 * of the available add-ons
203 *
204 * if the target value is incorrect, or if the content path
205 * is invalid, the emulator will abort with an error.
206 *
207 * - the content directory shall contain a 'config.ini' that
208 * contains hardware properties for the virtual device
209 * (as defined by SDK/tools/lib/hardware-properties.ini), as
210 * well as additional lines like:
211 *
212 * sdcard=<pathToDefaultSDCard>
213 * skin=<defaultSkinName>
214 * options=<additionalEmulatorStartupOptions>
215 *
216 *
217 * Finally, to find the skin to be used with a given virtual
218 * device, the following logic is used:
219 *
220 * - if no skin name has been manually specified on
221 * the command line, or in the config.ini file,
222 * look in $CONTENT/skin/layout and use it if available.
223 *
224 * - otherwise, set SKINNAME to 'default' if not manually
225 * specified, and look for $ADDON/skins/$SKINNAME/layout
226 * and use it if available
227 *
228 * - otherwise, look for $PLATFORM/skins/$SKINNAME/layout
229 * and use it if available.
230 *
231 * - otherwise, look for $PLATFORM/skins/$SKINNAME/alias-<other>.
232 * if a file exist by that name, look at $PLATFORM/skins/<other>/layout
233 * and use it if available. Aliases are not recursives :-)
234 */
235
236/* now, things get a little bit more complicated when working
237 * within the Android build system. In this mode, which can be
238 * detected by looking at the definition of the ANDROID_PRODUCT_OUT
239 * environment variable, we're going to simply pick the image files
240 * from the out directory, or from $BUILDROOT/prebuilt
241 */
242
243/* the name of the $SDKROOT subdirectory that contains all platforms */
244# define PLATFORMS_SUBDIR "platforms"
245
246/* the name of the $SDKROOT subdirectory that contains add-ons */
247# define ADDONS_SUBDIR "add-ons"
248
249#endif /* SUPPORT_PLATFORM_OR_ADDON */
250
251/* this is the subdirectory of $HOME/.android where all
252 * root configuration files (and default content directories)
253 * are located.
254 */
255#define ANDROID_AVD_DIR "avd"
256
257/* the prefix of config.ini keys that will be used for search directories
258 * of system images.
259 */
260#define SEARCH_PREFIX "images.sysdir."
261
262/* the maximum number of search path keys we're going to read from the
263 * config.ini file
264 */
265#define MAX_SEARCH_PATHS 2
266
267/* the config.ini key that will be used to indicate the full relative
268 * path to the skin directory (including the skin name).
269 *
270 * If SUPPORT_PLATFORM_OR_ADDON is defined, then this can also be
271 * the name of a skin, without any path, and platform/add-on directories
272 * will be searched for it.
273 */
274#define SKIN_PATH "skin"
275
276/* default skin name */
277#define SKIN_DEFAULT "HVGA"
278
279/* certain disk image files are mounted read/write by the emulator
280 * to ensure that several emulators referencing the same files
281 * do not corrupt these files, we need to lock them and respond
282 * to collision depending on the image type.
283 *
284 * the enumeration below is used to record information about
285 * each image file path.
286 *
287 * READONLY means that the file will be mounted read-only
288 * and this doesn't need to be locked. must be first in list
289 *
290 * MUSTLOCK means that the file should be locked before
291 * being mounted by the emulator
292 *
293 * TEMPORARY means that the file has been copied to a
294 * temporary image, which can be mounted read/write
295 * but doesn't require locking.
296 */
297typedef enum {
298 IMAGE_STATE_READONLY, /* unlocked */
299 IMAGE_STATE_MUSTLOCK, /* must be locked */
300 IMAGE_STATE_LOCKED, /* locked */
301 IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
302 IMAGE_STATE_TEMPORARY, /* copied to temp file (no lock needed) */
303} AvdImageState;
304
305struct AvdInfo {
306 /* for the Android build system case */
307 char inAndroidBuild;
308 char* androidOut;
309 char* androidBuildRoot;
310
311 /* for the normal virtual device case */
312 char* deviceName;
313 char* sdkRootPath;
314 char sdkRootPathFromEnv;
315 char* searchPaths[ MAX_SEARCH_PATHS ];
316 int numSearchPaths;
317#if SUPPORT_PLATFORM_OR_ADDON
318 int platformVersion;
319 char* platformPath;
320 char* addonTarget;
321 char* addonPath;
322#endif
323 char* contentPath;
324 IniFile* rootIni; /* root <foo>.ini file */
325 IniFile* configIni; /* virtual device's config.ini */
326
327 /* for both */
328 char* skinName; /* skin name */
329 char* skinDirPath; /* skin directory */
330
331 /* image files */
332 char* imagePath [ AVD_IMAGE_MAX ];
333 char imageState[ AVD_IMAGE_MAX ];
334};
335
336
337void
338avdInfo_free( AvdInfo* i )
339{
340 if (i) {
341 int nn;
342
343 for (nn = 0; nn < AVD_IMAGE_MAX; nn++)
344 AFREE(i->imagePath[nn]);
345
346 AFREE(i->skinName);
347 AFREE(i->skinDirPath);
348
349 for (nn = 0; nn < i->numSearchPaths; nn++)
350 AFREE(i->searchPaths[nn]);
351
352 i->numSearchPaths = 0;
353
354 if (i->configIni) {
355 iniFile_free(i->configIni);
356 i->configIni = NULL;
357 }
358
359 if (i->rootIni) {
360 iniFile_free(i->rootIni);
361 i->rootIni = NULL;
362 }
363
364 AFREE(i->contentPath);
365 AFREE(i->sdkRootPath);
366
367 if (i->inAndroidBuild) {
368 AFREE(i->androidOut);
369 AFREE(i->androidBuildRoot);
370 } else {
371#if SUPPORT_PLATFORM_OR_ADDON
372 AFREE(i->platformPath);
373 AFREE(i->addonTarget);
374 AFREE(i->addonPath);
375#endif
376 }
377
378 AFREE(i->deviceName);
379 AFREE(i);
380 }
381}
382
383/* list of default file names for each supported image file type */
384static const char* const _imageFileNames[ AVD_IMAGE_MAX ] = {
385#define _AVD_IMG(x,y,z) y,
386 AVD_IMAGE_LIST
387#undef _AVD_IMG
388};
389
390/* list of short text description for each supported image file type */
391static const char* const _imageFileText[ AVD_IMAGE_MAX ] = {
392#define _AVD_IMG(x,y,z) z,
393 AVD_IMAGE_LIST
394#undef _AVD_IMG
395};
396
397/***************************************************************
398 ***************************************************************
399 *****
400 ***** NORMAL VIRTUAL DEVICE SUPPORT
401 *****
402 *****/
403
404/* compute path to the root SDK directory
405 * assume we are in $SDKROOT/tools/emulator[.exe]
406 */
407static int
408_getSdkRoot( AvdInfo* i )
409{
410 const char* env;
411 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
412
413#define SDK_ROOT_ENV "ANDROID_SDK_ROOT"
414
415 env = getenv(SDK_ROOT_ENV);
416 if (env != NULL && env[0] != 0) {
417 if (path_exists(env)) {
418 D("found " SDK_ROOT_ENV ": %s", env);
419 i->sdkRootPath = ASTRDUP(env);
420 i->sdkRootPathFromEnv = 1;
421 return 0;
422 }
423 D(SDK_ROOT_ENV " points to unknown directory: %s", env);
424 }
425
426 (void) bufprint_app_dir(temp, end);
427
428 i->sdkRootPath = path_parent(temp, 1);
429 if (i->sdkRootPath == NULL) {
430 derror("can't find root of SDK directory");
431 return -1;
432 }
433 D("found SDK root at %s", i->sdkRootPath);
434 return 0;
435}
436
437static void
438_getSearchPaths( AvdInfo* i )
439{
440 char temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
441 int nn, count = 0;
442
443
444
445 for (nn = 0; nn < MAX_SEARCH_PATHS; nn++) {
446 char* path;
447
448 p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
449 if (p >= end)
450 continue;
451
452 path = iniFile_getString( i->configIni, temp );
453 if (path != NULL) {
454 DD(" found image search path: %s", path);
455 if (!path_is_absolute(path)) {
456 p = bufprint(temp, end, "%s/%s", i->sdkRootPath, path);
457 AFREE(path);
458 path = ASTRDUP(temp);
459 }
460 i->searchPaths[count++] = path;
461 }
462 }
463
464 i->numSearchPaths = count;
465 if (count == 0)
466 DD("no search paths found in this AVD's config.ini");
467 else
468 DD("found a total of %d search paths for this AVD", count);
469}
470
471#if SUPPORT_PLATFORM_OR_ADDON
472/* returns the full path of the platform subdirectory
473 * corresponding to a given API version
474 */
475static char*
476_findPlatformByVersion( const char* sdkRoot, int version )
477{
478 char temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
479 char* subdir = NULL;
480 DirScanner* scanner;
481
482 DD("> %s(%s,%d)", __FUNCTION__, sdkRoot, version);
483 p = bufprint(temp, end, "%s/%s", sdkRoot, PLATFORMS_SUBDIR);
484 if (p >= end) {
485 DD("! path too long");
486 return NULL;
487 }
488
489 scanner = dirScanner_new(temp);
490 if (scanner == NULL) {
491 DD("! cannot scan path %s: %s", temp, strerror(errno));
492 return NULL;
493 }
494
495 for (;;) {
496 IniFile* ini;
497 int apiVersion;
498
499 subdir = (char*) dirScanner_nextFull(scanner);
500 if (subdir == NULL)
501 break;
502
503 /* look for a file named "build.prop */
504 p = bufprint(temp, end, "%s/build.prop", subdir);
505 if (p >= end)
506 continue;
507
508 if (!path_exists(temp)) {
509 DD("! no file at %s", temp);
510 continue;
511 }
512
513 ini = iniFile_newFromFile(temp);
514 if (ini == NULL)
515 continue;
516
517 apiVersion = iniFile_getInteger(ini, "ro.build.version.sdk", -1);
518 iniFile_free(ini);
519
520 DD("! found %s (version %d)", temp, apiVersion);
521
522 if (apiVersion == version) {
523 /* Bingo */
524 subdir = ASTRDUP(subdir);
525 break;
526 }
527 }
528
529 if (!subdir) {
530 DD("< didn't found anything");
531 }
532
533 dirScanner_free(scanner);
534 return subdir;
535}
536
537/* returns the full path of the addon corresponding to a given target,
538 * or NULL if not found. on success, *pversion will contain the SDK
539 * version number
540 */
541static char*
542_findAddonByTarget( const char* sdkRoot, const char* target, int *pversion )
543{
544 char* targetCopy = ASTRDUP(target);
545 char* targetVendor = NULL;
546 char* targetName = NULL;
547 int targetVersion = -1;
548
549 char temp[PATH_MAX];
550 char* p;
551 char* end;
552 DirScanner* scanner;
553 char* subdir;
554
555 DD("> %s(%s,%s)", __FUNCTION__, sdkRoot, target);
556
557 /* extract triplet from target string */
558 targetVendor = targetCopy;
559
560 p = strchr(targetVendor, ':');
561 if (p == NULL) {
562 DD("< missing first column separator");
563 goto FAIL;
564 }
565 *p = 0;
566 targetName = p + 1;
567 p = strchr(targetName, ':');
568 if (p == NULL) {
569 DD("< missing second column separator");
570 goto FAIL;
571 }
572 *p++ = 0;
573
574 targetVersion = atoi(p);
575
576 if (targetVersion == 0) {
577 DD("< invalid version number");
578 goto FAIL;
579 }
580 /* now scan addons directory */
581 p = temp;
582 end = p + sizeof temp;
583
584 p = bufprint(p, end, "%s/%s", sdkRoot, ADDONS_SUBDIR);
585 if (p >= end) {
586 DD("< add-on path too long");
587 goto FAIL;
588 }
589 scanner = dirScanner_new(temp);
590 if (scanner == NULL) {
591 DD("< cannot scan add-on path %s: %s", temp, strerror(errno));
592 goto FAIL;
593 }
594 for (;;) {
595 IniFile* ini;
596 const char* vendor;
597 const char* name;
598 int version;
599 int matches;
600
601 subdir = (char*) dirScanner_nextFull(scanner);
602 if (subdir == NULL)
603 break;
604
605 /* try to open the manifest.ini file */
606 p = bufprint(temp, end, "%s/manifest.ini", subdir);
607 if (p >= end)
608 continue;
609
610 ini = iniFile_newFromFile(temp);
611 if (ini == NULL)
612 continue;
613
614 DD("! scanning manifest.ini in %s", temp);
615
616 /* find the vendor, name and version */
617 vendor = iniFile_getValue(ini, "vendor");
618 name = iniFile_getValue(ini, "name");
619 version = iniFile_getInteger(ini, "api", -1);
620
621 matches = 0;
622
623 matches += (version == targetVersion);
624 matches += (vendor && !strcmp(vendor, targetVendor));
625 matches += (name && !strcmp(name, targetName));
626
627 DD("! matches=%d vendor=[%s] name=[%s] version=%d",
628 matches,
629 vendor ? vendor : "<NULL>",
630 name ? name : "<NULL>",
631 version);
632
633 iniFile_free(ini);
634
635 if (matches == 3) {
636 /* bingo */
637 *pversion = version;
638 subdir = ASTRDUP(subdir);
639 break;
640 }
641 }
642
643 dirScanner_free(scanner);
644
645 DD("< returning %s", subdir ? subdir : "<NULL>");
646 return subdir;
647
648FAIL:
649 AFREE(targetCopy);
650 return NULL;
651}
652#endif /* SUPPORT_PLATFORM_OR_ADDON */
653
654static int
655_checkAvdName( const char* name )
656{
657 int len = strlen(name);
658 int len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
659 "abcdefghijklmnopqrstuvwxyz"
660 "0123456789_.-");
661 return (len == len2);
662}
663
664/* parse the root config .ini file. it is located in
665 * ~/.android/avd/<name>.ini or Windows equivalent
666 */
667static int
668_getRootIni( AvdInfo* i )
669{
670 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
671
672 p = bufprint_config_path(temp, end);
673 p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", i->deviceName);
674 if (p >= end) {
675 derror("device name too long");
676 return -1;
677 }
678
679 i->rootIni = iniFile_newFromFile(temp);
680 if (i->rootIni == NULL) {
681 derror("unknown virtual device name: '%s'", i->deviceName);
682 return -1;
683 }
684 D("root virtual device file at %s", temp);
685 return 0;
686}
687
688/* the .ini variable name that points to the content directory
689 * in a root AVD ini file. This is required */
690# define ROOT_PATH_KEY "path"
691
692static int
693_getContentPath( AvdInfo* i )
694{
695 i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY);
696
697 if (i->contentPath == NULL) {
698 derror("bad config: %s",
699 "virtual device file lacks a "ROOT_PATH_KEY" entry");
700 return -1;
701 }
702 D("virtual device content at %s", i->contentPath);
703 return 0;
704}
705
706#if SUPPORT_PLATFORM_OR_ADDON
707# define ROOT_TARGET_KEY "target"
708
709/* retrieve the content path and target from the root .ini file */
710static int
711_getTarget( AvdInfo* i )
712{
713 i->addonTarget = iniFile_getString(i->rootIni, ROOT_TARGET_KEY);
714
715 if (i->addonTarget == NULL) {
716 derror("bad config: %s",
717 "virtual device file lacks a "ROOT_TARGET_KEY" entry");
718 return -1;
719 }
720
721 D("virtual device target is %s", i->addonTarget);
722
723 if (!strncmp(i->addonTarget, "android-", 8)) { /* target is platform */
724 char* end;
725 const char* versionString = i->addonTarget+8;
726 int version = (int) strtol(versionString, &end, 10);
727 if (*end != 0 || version <= 0) {
728 derror("bad config: invalid platform version: '%s'", versionString);
729 return -1;
730 }
731 i->platformVersion = version;
732 i->platformPath = _findPlatformByVersion(i->sdkRootPath,
733 version);
734 if (i->platformPath == NULL) {
735 derror("bad config: unknown platform version: '%d'", version);
736 return -1;
737 }
738 }
739 else /* target is add-on */
740 {
741 i->addonPath = _findAddonByTarget(i->sdkRootPath, i->addonTarget,
742 &i->platformVersion);
743 if (i->addonPath == NULL) {
744 derror("bad config: %s",
745 "unknown add-on target: '%s'", i->addonTarget);
746 return -1;
747 }
748
749 i->platformPath = _findPlatformByVersion(i->sdkRootPath,
750 i->platformVersion);
751 if (i->platformPath == NULL) {
752 derror("bad config: %s",
753 "unknown add-on platform version: '%d'", i->platformVersion);
754 return -1;
755 }
756 D("virtual device add-on path: %s", i->addonPath);
757 }
758 D("virtual device platform path: %s", i->platformPath);
759 D("virtual device platform version %d", i->platformVersion);
760 return 0;
761}
762#endif /* SUPPORT_PLATFORM_OR_ADDON */
763
764/* find and parse the config.ini file from the content directory */
765static int
766_getConfigIni(AvdInfo* i)
767{
768 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
769
770 p = bufprint(p, end, "%s/config.ini", i->contentPath);
771 if (p >= end) {
772 derror("can't access virtual device content directory");
773 return -1;
774 }
775
776#if 1 /* XXX: TODO: remove this in the future */
777 /* for now, allow a non-existing config.ini */
778 if (!path_exists(temp)) {
779 D("virtual device has no config file - no problem");
780 return 0;
781 }
782#endif
783
784 i->configIni = iniFile_newFromFile(temp);
785 if (i->configIni == NULL) {
786 derror("bad config: %s",
787 "virtual device directory lacks config.ini");
788 return -1;
789 }
790 D("virtual device config file: %s", temp);
791 return 0;
792}
793
794/***************************************************************
795 ***************************************************************
796 *****
797 ***** KERNEL/DISK IMAGE LOADER
798 *****
799 *****/
800
801/* a structure used to handle the loading of
802 * kernel/disk images.
803 */
804typedef struct {
805 AvdInfo* info;
806 AvdInfoParams* params;
807 AvdImageType id;
808 const char* imageFile;
809 const char* imageText;
810 char** pPath;
811 char* pState;
812 char temp[PATH_MAX];
813} ImageLoader;
814
815static void
816imageLoader_init( ImageLoader* l, AvdInfo* info, AvdInfoParams* params )
817{
818 memset(l, 0, sizeof(*l));
819 l->info = info;
820 l->params = params;
821}
822
823/* set the type of the image to load */
824static void
825imageLoader_set( ImageLoader* l, AvdImageType id )
826{
827 l->id = id;
828 l->imageFile = _imageFileNames[id];
829 l->imageText = _imageFileText[id];
830 l->pPath = &l->info->imagePath[id];
831 l->pState = &l->info->imageState[id];
832
833 l->pState[0] = IMAGE_STATE_READONLY;
834}
835
836/* change the image path */
837static char*
838imageLoader_setPath( ImageLoader* l, const char* path )
839{
840 path = path ? ASTRDUP(path) : NULL;
841
842 AFREE(l->pPath[0]);
843 l->pPath[0] = (char*) path;
844
845 return (char*) path;
846}
847
848static char*
849imageLoader_extractPath( ImageLoader* l )
850{
851 char* result = l->pPath[0];
852 l->pPath[0] = NULL;
853 return result;
854}
855
856/* flags used when loading images */
857enum {
858 IMAGE_REQUIRED = (1<<0), /* image is required */
859 IMAGE_SEARCH_SDK = (1<<1), /* search image in SDK */
860 IMAGE_EMPTY_IF_MISSING = (1<<2), /* create empty file if missing */
861 IMAGE_DONT_LOCK = (1<<4), /* don't try to lock image */
862 IMAGE_IGNORE_IF_LOCKED = (1<<5), /* ignore file if it's locked */
863};
864
865#define IMAGE_OPTIONAL 0
866
867/* find an image from the SDK search directories.
868 * returns the full path or NULL if the file could not be found.
869 *
870 * note: this stores the result in the image's path as well
871 */
872static char*
873imageLoader_lookupSdk( ImageLoader* l )
874{
875 AvdInfo* i = l->info;
876 const char* image = l->imageFile;
877 char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp);
878
879 do {
880 /* try the search paths */
881 int nn;
882
883 for (nn = 0; nn < i->numSearchPaths; nn++) {
884 const char* searchDir = i->searchPaths[nn];
885
886 p = bufprint(temp, end, "%s/%s", searchDir, image);
887 if (p < end && path_exists(temp)) {
888 DD("found %s in search dir: %s", image, searchDir);
889 goto FOUND;
890 }
891 DD(" no %s in search dir: %s", image, searchDir);
892 }
893
894#if SUPPORT_PLATFORM_OR_ADDON
895 /* try the add-on directory, if any */
896 if (i->addonPath != NULL) {
897 p = bufprint(temp, end, "%s/images/%s", i->addonPath, image);
898 if (p < end && path_exists(temp)) {
899 DD("found %s in add-on dir:", image, i->addonPath);
900 break;
901 }
902 DD(" no %s in add-on dir: ", image, i->addonPath);
903 }
904
905 /* or try the platform directory */
906 p = bufprint(temp, end, "%s/images/%s",
907 i->platformPath, image);
908 if (p < end && path_exists(temp)) {
909 DD("found %s in platform dir:", image, i->platformPath);
910 break;
911 }
912 DD(" no %s in platform dir: ", image, i->platformPath);
913#endif
914 return NULL;
915
916 } while (0);
917
918FOUND:
919 l->pState[0] = IMAGE_STATE_READONLY;
920
921 return imageLoader_setPath(l, temp);
922}
923
924/* search for a file in the content directory.
925 * returns NULL if the file cannot be found.
926 *
927 * note that this formats l->temp with the file's path
928 * allowing you to retrieve it if the function returns NULL
929 */
930static char*
931imageLoader_lookupContent( ImageLoader* l )
932{
933 AvdInfo* i = l->info;
934 char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp);
935
936 p = bufprint(temp, end, "%s/%s", i->contentPath, l->imageFile);
937 if (p >= end) {
938 derror("content directory path too long");
939 exit(2);
940 }
941 if (!path_exists(temp)) {
942 DD(" no %s in content directory", l->imageFile);
943 return NULL;
944 }
945 DD("found %s in content directory", l->imageFile);
946
947 /* assume content image files must be locked */
948 l->pState[0] = IMAGE_STATE_MUSTLOCK;
949
950 return imageLoader_setPath(l, temp);
951}
952
953/* lock a file image depending on its state and user flags
954 * note that this clears l->pPath[0] if the lock could not
955 * be acquired and that IMAGE_IGNORE_IF_LOCKED is used.
956 */
957static void
958imageLoader_lock( ImageLoader* l, unsigned flags )
959{
960 const char* path = l->pPath[0];
961
962 if (flags & IMAGE_DONT_LOCK)
963 return;
964
965 if (l->pState[0] != IMAGE_STATE_MUSTLOCK)
966 return;
967
968 D(" locking %s image at %s", l->imageText, path);
969
970 if (filelock_create(path) != NULL) {
971 /* succesful lock */
972 l->pState[0] = IMAGE_STATE_LOCKED;
973 return;
974 }
975
976 if (flags & IMAGE_IGNORE_IF_LOCKED) {
977 dwarning("ignoring locked %s image at %s", l->imageText, path);
978 imageLoader_setPath(l, NULL);
979 return;
980 }
981
982 derror("the %s image is used by another emulator. aborting",
983 l->imageText);
984 exit(2);
985}
986
987/* make a file image empty, this may require locking */
988static void
989imageLoader_empty( ImageLoader* l, unsigned flags )
990{
991 const char* path;
992
993 imageLoader_lock(l, flags);
994
995 path = l->pPath[0];
996 if (path == NULL) /* failed to lock, caller will handle it */
997 return;
998
999 if (path_empty_file(path) < 0) {
1000 derror("could not create %s image at %s: %s",
1001 l->imageText, path, strerror(errno));
1002 exit(2);
1003 }
1004 l->pState[0] = IMAGE_STATE_LOCKED_EMPTY;
1005}
1006
1007
1008/* copy image file from a given source
1009 * assumes locking is needed.
1010 */
1011static void
1012imageLoader_copyFrom( ImageLoader* l, const char* srcPath )
1013{
1014 const char* dstPath = NULL;
1015
1016 /* find destination file */
1017 if (l->params) {
1018 dstPath = l->params->forcePaths[l->id];
1019 }
1020 if (!dstPath) {
1021 imageLoader_lookupContent(l);
1022 dstPath = l->temp;
1023 }
1024
1025 /* lock destination */
1026 imageLoader_setPath(l, dstPath);
1027 l->pState[0] = IMAGE_STATE_MUSTLOCK;
1028 imageLoader_lock(l, 0);
1029
1030 /* make the copy */
1031 if (path_copy_file(dstPath, srcPath) < 0) {
1032 derror("can't initialize %s image from SDK: %s: %s",
1033 l->imageText, dstPath, strerror(errno));
1034 exit(2);
1035 }
1036}
1037
1038/* this will load and eventually lock and image file, depending
1039 * on the flags being used. on exit, this function udpates
1040 * l->pState[0] and l->pPath[0]
1041 *
1042 * returns the path to the file. Note that it returns NULL
1043 * only if the file was optional and could not be found.
1044 *
1045 * if the file is required and missing, the function aborts
1046 * the program.
1047 */
1048static char*
1049imageLoader_load( ImageLoader* l,
1050 unsigned flags )
1051{
1052 const char* path = NULL;
1053
1054 /* first, check user-provided path */
1055 path = l->params->forcePaths[l->id];
1056 if (path != NULL) {
1057 imageLoader_setPath(l, path);
1058 if (path_exists(path)) {
1059 DD("found user-provided %s image: %s", l->imageText, l->imageFile);
1060 goto EXIT;
1061 }
1062 D("user-provided %s image does not exist: %s",
1063 l->imageText, path);
1064
1065 /* if the file is required, abort */
1066 if (flags & IMAGE_REQUIRED) {
1067 derror("user-provided %s image at %s doesn't exist",
1068 l->imageText, path);
1069 exit(2);
1070 }
1071 }
1072 else {
1073 const char* contentFile;
1074
1075 /* second, look in the content directory */
1076 path = imageLoader_lookupContent(l);
1077 if (path) goto EXIT;
1078
1079 contentFile = ASTRDUP(l->temp);
1080
1081 /* it's not there */
1082 if (flags & IMAGE_SEARCH_SDK) {
1083 /* third, look in the SDK directory */
1084 path = imageLoader_lookupSdk(l);
1085 if (path) {
1086 AFREE((char*)contentFile);
1087 goto EXIT;
1088 }
1089 }
1090 DD("found no %s image (%s)", l->imageText, l->imageFile);
1091
1092 /* if the file is required, abort */
1093 if (flags & IMAGE_REQUIRED) {
1094 AvdInfo* i = l->info;
1095
1096 derror("could not find required %s image (%s).",
1097 l->imageText, l->imageFile);
1098
1099 if (i->inAndroidBuild) {
1100 dprint( "Did you build everything ?" );
1101 } else if (!i->sdkRootPathFromEnv) {
1102 dprint( "Maybe defining %s to point to a valid SDK "
1103 "installation path might help ?", SDK_ROOT_ENV );
1104 } else {
1105 dprint( "Your %s is probably wrong: %s", SDK_ROOT_ENV,
1106 i->sdkRootPath );
1107 }
1108 exit(2);
1109 }
1110
1111 path = imageLoader_setPath(l, contentFile);
1112 AFREE((char*)contentFile);
1113 }
1114
1115 /* otherwise, do we need to create it ? */
1116 if (flags & IMAGE_EMPTY_IF_MISSING) {
1117 imageLoader_empty(l, flags);
1118 return l->pPath[0];
1119 }
1120 return NULL;
1121
1122EXIT:
1123 imageLoader_lock(l, flags);
1124 return l->pPath[0];
1125}
1126
1127
1128
1129/* find the correct path of all image files we're going to need
1130 * and lock the files that need it.
1131 */
1132static int
1133_getImagePaths(AvdInfo* i, AvdInfoParams* params )
1134{
1135 int wipeData = (params->flags & AVDINFO_WIPE_DATA) != 0;
1136 int wipeCache = (params->flags & AVDINFO_WIPE_CACHE) != 0;
1137 int noCache = (params->flags & AVDINFO_NO_CACHE) != 0;
1138 int noSdCard = (params->flags & AVDINFO_NO_SDCARD) != 0;
1139
1140 ImageLoader l[1];
1141
1142 imageLoader_init(l, i, params);
1143
1144 /* pick up the kernel and ramdisk image files - these don't
1145 * need a specific handling.
1146 */
1147 imageLoader_set ( l, AVD_IMAGE_KERNEL );
1148 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
1149
1150 imageLoader_set ( l, AVD_IMAGE_RAMDISK );
1151 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
1152
1153 /* the system image
1154 *
1155 * if there is one in the content directory just lock
1156 * and use it.
1157 */
1158 imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
1159 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK );
1160
1161 /* the data partition - this one is special because if it
1162 * is missing, we need to copy the initial image file into it.
1163 *
1164 * first, try to see if it is in the content directory
1165 * (or the user-provided path)
1166 */
1167 imageLoader_set( l, AVD_IMAGE_USERDATA );
1168 if ( !imageLoader_load( l, IMAGE_OPTIONAL |
1169 IMAGE_EMPTY_IF_MISSING |
1170 IMAGE_DONT_LOCK ) )
1171 {
1172 /* it's not, we're going to initialize it. simply
1173 * forcing a data wipe should be enough */
1174 D("initializing new data partition image: %s", l->pPath[0]);
1175 wipeData = 1;
1176 }
1177
1178 if (wipeData) {
1179 /* find SDK source file */
1180 const char* srcPath;
1181
1182 if (imageLoader_lookupSdk(l)) {
1183 derror("can't locate initial %s image in SDK",
1184 l->imageText);
1185 exit(2);
1186 }
1187 srcPath = imageLoader_extractPath(l);
1188
1189 imageLoader_copyFrom( l, srcPath );
1190 AFREE((char*) srcPath);
1191 }
1192 else
1193 {
1194 /* lock the data partition image */
1195 l->pState[0] = IMAGE_STATE_MUSTLOCK;
1196 imageLoader_lock( l, 0 );
1197 }
1198
1199 /* the cache partition: unless the user doesn't want one,
1200 * we're going to create it in the content directory
1201 */
1202 if (!noCache) {
1203 imageLoader_set (l, AVD_IMAGE_CACHE);
1204 imageLoader_load(l, IMAGE_OPTIONAL |
1205 IMAGE_EMPTY_IF_MISSING );
1206
1207 if (wipeCache) {
1208 if (path_empty_file(l->pPath[0]) < 0) {
1209 derror("cannot wipe %s image at %s: %s",
1210 l->imageText, l->pPath[0],
1211 strerror(errno));
1212 exit(2);
1213 }
1214 }
1215 }
1216
1217 /* the SD Card image. unless the user doesn't want to, we're
1218 * going to mount it if available. Note that if the image is
1219 * already used, we must ignore it.
1220 */
1221 if (!noSdCard) {
1222 imageLoader_set (l, AVD_IMAGE_SDCARD);
1223 imageLoader_load(l, IMAGE_OPTIONAL |
1224 IMAGE_IGNORE_IF_LOCKED);
1225
1226 /* if the file was not found, ignore it */
1227 if (l->pPath[0] && !path_exists(l->pPath[0]))
1228 {
1229 D("ignoring non-existing %s at %s: %s",
1230 l->imageText, l->pPath[0], strerror(errno));
1231
1232 /* if the user provided the SD Card path by hand,
1233 * warn him. */
1234 if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL)
1235 dwarning("ignoring non-existing SD Card image");
1236
1237 imageLoader_setPath(l, NULL);
1238 }
1239 }
1240
1241 return 0;
1242}
1243
1244/* check that a given directory contains a valid skin.
1245 * returns 1 on success, 0 on failure.
1246 */
1247static int
1248_checkSkinPath( const char* skinPath )
1249{
1250 char temp[MAX_PATH], *p=temp, *end=p+sizeof(temp);
1251
1252 /* for now, if it has a 'layout' file, it is a valid skin path */
1253 p = bufprint(temp, end, "%s/layout", skinPath);
1254 if (p >= end || !path_exists(temp))
1255 return 0;
1256
1257 return 1;
1258}
1259
1260/* check that there is a skin named 'skinName' listed from 'skinDirRoot'
1261 * this returns 1 on success, 0 on failure
1262 * on success, the 'temp' buffer will get the path containing the real
1263 * skin directory (after alias expansion), including the skin name.
1264 */
1265static int
1266_checkSkinDir( char* temp,
1267 char* end,
1268 const char* skinDirRoot,
1269 const char* skinName )
1270{
1271 DirScanner* scanner;
1272 char *p;
1273 int result;
1274
1275 p = bufprint(temp, end, "%s/skins/%s",
1276 skinDirRoot, skinName);
1277
1278 if (p >= end || !path_exists(temp)) {
1279 DD(" ignore bad skin directory %s", temp);
1280 return 0;
1281 }
1282
1283 /* first, is this a normal skin directory ? */
1284 if (_checkSkinPath(temp)) {
1285 /* yes */
1286 DD(" found skin directory: %s", temp);
1287 return 1;
1288 }
1289
1290 /* second, is it an alias to another skin ? */
1291 *p = 0;
1292 result = 0;
1293 scanner = dirScanner_new(temp);
1294 if (scanner != NULL) {
1295 for (;;) {
1296 const char* file = dirScanner_next(scanner);
1297
1298 if (file == NULL)
1299 break;
1300
1301 if (strncmp(file, "alias-", 6) || file[6] == 0)
1302 continue;
1303
1304 p = bufprint(temp, end, "%s/skins/%s",
1305 skinDirRoot, file+6);
1306
1307 if (p < end && _checkSkinPath(temp)) {
1308 /* yes, it's an alias */
1309 DD(" skin alias '%s' points to skin directory: %s",
1310 file+6, temp);
1311 result = 1;
1312 break;
1313 }
1314 }
1315 dirScanner_free(scanner);
1316 }
1317 return result;
1318}
1319
1320/* try to see if the skin name leads to a magic skin or skin path directly
1321 * returns 1 on success, 0 on error.
1322 * on success, this sets up 'skinDirPath' and 'skinName' in the AvdInfo.
1323 */
1324static int
1325_getSkinPathFromName( AvdInfo* i, const char* skinName )
1326{
1327 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
1328
1329 /* if the skin name has the format 'NNNNxNNN' where
1330 * NNN is a decimal value, then this is a 'magic' skin
1331 * name that doesn't require a skin directory
1332 */
1333 if (isdigit(skinName[0])) {
1334 int width, height;
1335 if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
1336 D("'magic' skin format detected: %s", skinName);
1337 i->skinName = ASTRDUP(skinName);
1338 i->skinDirPath = NULL;
1339 return 1;
1340 }
1341 }
1342
1343 /* is the skin name a direct path to the skin directory ? */
1344 if (_checkSkinPath(skinName)) {
1345 goto FOUND_IT;
1346 }
1347
1348 /* is the skin name a relative path from the SDK root ? */
1349 p = bufprint(temp, end, "%s/%s", i->sdkRootPath, skinName);
1350 if (p < end && _checkSkinPath(temp)) {
1351 skinName = temp;
1352 goto FOUND_IT;
1353 }
1354
1355 /* nope */
1356 return 0;
1357
1358FOUND_IT:
1359 if (path_split(skinName, &i->skinDirPath, &i->skinName) < 0) {
1360 derror("malformed skin name: %s", skinName);
1361 exit(2);
1362 }
1363 D("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
1364 return 1;
1365}
1366
1367/* return 0 on success, -1 on error */
1368static int
1369_getSkin( AvdInfo* i, AvdInfoParams* params )
1370{
1371 char* skinName;
1372 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
1373 char explicitSkin = 1;
1374
1375 /* this function is used to compute the 'skinName' and 'skinDirPath'
1376 * fields of the AvdInfo.
1377 */
1378
1379 /* processing here is a bit tricky, so here's how it happens
1380 *
1381 * - command-line option '-skin <name>' can be used to specify the
1382 * name of a skin, to override the AVD settings.
1383 *
1384 * - skins are searched from <dir>/../skins for each <dir> in the
1385 * images search list, unless a '-skindir <path>' option has been
1386 * provided on the command-line
1387 *
1388 * - otherwise, the config.ini can also contain a SKIN_PATH key that
1389 * shall give the full path to the skin directory, either relative
1390 * to the SDK root, or an absolute path.
1391 *
1392 * - skin names like '320x480' corresponds to "magic skins" that
1393 * simply display a framebuffer, without any ornaments of the
1394 * corresponding size. They do not correspond to any real skin
1395 * directory / files and are handled later. But they must be
1396 * recognized here and report a NULL skindir.
1397 */
1398 if (params->skinName) {
1399 skinName = ASTRDUP(params->skinName);
1400 } else {
1401 skinName = iniFile_getString( i->configIni, SKIN_PATH );
1402 explicitSkin = 0;
1403 }
1404
1405 /* first, check that the skin name is not magic or a direct
1406 * directory path
1407 */
1408 if (skinName != NULL && _getSkinPathFromName(i, skinName)) {
1409 AFREE(skinName);
1410 return 0;
1411 }
1412
1413 /* if not, the default skinName is "HVGA" */
1414 if (skinName == NULL) {
1415 skinName = ASTRDUP(SKIN_DEFAULT);
1416 explicitSkin = 0;
1417 }
1418
1419 i->skinName = skinName;
1420
1421 /* now try to find the skin directory for that name -
1422 * first try the content directory */
1423 do {
1424 /* if there is a single 'skin' directory in
1425 * the content directory, assume that's what the
1426 * user wants, unless an explicit name was given
1427 */
1428 if (!explicitSkin) {
1429 p = bufprint(temp, end, "%s/skin", i->contentPath);
1430 if (p < end && _checkSkinPath(temp)) {
1431 D("using skin content from %s", temp);
1432 AFREE(i->skinName);
1433 i->skinName = ASTRDUP("skin");
1434 i->skinDirPath = ASTRDUP(i->contentPath);
1435 return 0;
1436 }
1437 }
1438
1439 /* look in content directory */
1440 if (_checkSkinDir(temp, end, i->contentPath, skinName))
1441 break;
1442
1443 /* look in the search paths. For each <dir> in the list,
1444 * look the skins in <dir>/.. */
1445 {
1446 int nn;
1447 for (nn = 0; nn < i->numSearchPaths; nn++) {
1448 char* parentDir = path_parent(i->searchPaths[nn], 1);
1449 int ret;
1450 if (parentDir == NULL)
1451 continue;
1452 ret=_checkSkinDir(temp, end, parentDir, skinName);
1453 AFREE(parentDir);
1454 if (ret)
1455 break;
1456 }
1457 if (nn < i->numSearchPaths)
1458 break;
1459 }
1460
1461#if SUPPORT_PLATFORM_OR_ADDON
1462 /* look in the add-on directory, if any */
1463 if (i->addonPath &&
1464 _checkSkinDir(temp, end, i->addonPath, skinName))
1465 break;
1466
1467 /* look in the platforms directory */
1468 if (_checkSkinDir(temp, end, i->platformPath, skinName))
1469 break;
1470#endif
1471 /* didn't find it */
1472 if (explicitSkin) {
1473 derror("could not find directory for skin '%s',"
1474 " please use a different name", skinName);
1475 exit(2);
1476 } else {
1477 dwarning("no skin directory matched '%s', so reverted to default",
1478 skinName);
1479 AFREE(i->skinName);
1480 params->skinName = SKIN_DEFAULT;
1481 return _getSkin(i, params);
1482 }
1483
1484 return -1;
1485
1486 } while (0);
1487
1488 /* separate skin name from parent directory. the skin name
1489 * returned in 'temp' might be different from the original
1490 * one due to alias expansion so strip it.
1491 */
1492 AFREE(i->skinName);
1493
1494 if (path_split(temp, &i->skinDirPath, &i->skinName) < 0) {
1495 derror("weird skin path: %s", temp);
1496 return -1;
1497 }
1498 DD("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
1499 return 0;
1500}
1501
1502
1503AvdInfo*
1504avdInfo_new( const char* name, AvdInfoParams* params )
1505{
1506 AvdInfo* i;
1507
1508 if (name == NULL)
1509 return NULL;
1510
1511 if (!_checkAvdName(name)) {
1512 derror("virtual device name contains invalid characters");
1513 exit(1);
1514 }
1515
1516 ANEW0(i);
1517 i->deviceName = ASTRDUP(name);
1518
1519 if ( _getSdkRoot(i) < 0 ||
1520 _getRootIni(i) < 0 ||
1521 _getContentPath(i) < 0 ||
1522 _getConfigIni(i) < 0 )
1523 goto FAIL;
1524
1525 /* look for image search paths. handle post 1.1/pre cupcake
1526 * obsolete SDKs.
1527 */
1528 _getSearchPaths(i);
1529
1530 if (i->numSearchPaths == 0) {
1531#if SUPPORT_PLATFORM_OR_ADDON
1532 /* no search paths, look for platform/add-on */
1533 if (_getTarget(i) < 0)
1534 goto FAIL;
1535#endif
1536 }
1537
1538 /* don't need this anymore */
1539 iniFile_free(i->rootIni);
1540 i->rootIni = NULL;
1541
1542 if ( _getImagePaths(i, params) < 0 ||
1543 _getSkin (i, params) < 0 )
1544 goto FAIL;
1545
1546 return i;
1547
1548FAIL:
1549 avdInfo_free(i);
1550 return NULL;
1551}
1552
1553/***************************************************************
1554 ***************************************************************
1555 *****
1556 ***** ANDROID BUILD SUPPORT
1557 *****
1558 ***** The code below corresponds to the case where we're
1559 ***** starting the emulator inside the Android build
1560 ***** system. The main differences are that:
1561 *****
1562 ***** - the $ANDROID_PRODUCT_OUT directory is used as the
1563 ***** content file.
1564 *****
1565 ***** - built images must not be modified by the emulator,
1566 ***** so system.img must be copied to a temporary file
1567 ***** and userdata.img must be copied to userdata-qemu.img
1568 ***** if the latter doesn't exist.
1569 *****
1570 ***** - the kernel and default skin directory are taken from
1571 ***** prebuilt
1572 *****
1573 ***** - there is no root .ini file, or any config.ini in
1574 ***** the content directory, no SDK platform version
1575 ***** and no add-on to consider.
1576 *****/
1577
1578/* used to fake a config.ini located in the content directory */
1579static int
1580_getBuildConfigIni( AvdInfo* i )
1581{
1582 /* a blank file is ok at the moment */
1583 i->configIni = iniFile_newFromMemory( "", 0 );
1584 return 0;
1585}
1586
1587static int
1588_getBuildImagePaths( AvdInfo* i, AvdInfoParams* params )
1589{
1590 int wipeData = (params->flags & AVDINFO_WIPE_DATA) != 0;
1591 int noCache = (params->flags & AVDINFO_NO_CACHE) != 0;
1592 int noSdCard = (params->flags & AVDINFO_NO_SDCARD) != 0;
1593
1594 char temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
1595 char* srcData;
1596 ImageLoader l[1];
1597
1598 imageLoader_init(l, i, params);
1599
1600 /** load the kernel image
1601 **/
1602
1603 /* if it is not in the out directory, get it from prebuilt
1604 */
1605 imageLoader_set ( l, AVD_IMAGE_KERNEL );
1606
1607 if ( !imageLoader_load( l, IMAGE_OPTIONAL |
1608 IMAGE_DONT_LOCK ) )
1609 {
1610#define PREBUILT_KERNEL_PATH "prebuilt/android-arm/kernel/kernel-qemu"
1611 p = bufprint(temp, end, "%s/%s", i->androidBuildRoot,
1612 PREBUILT_KERNEL_PATH);
1613 if (p >= end || !path_exists(temp)) {
1614 derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
1615 exit(1);
1616 }
1617 imageLoader_setPath(l, temp);
1618 }
1619
1620 /** load the data partition. note that we use userdata-qemu.img
1621 ** since we don't want to modify userdata.img at all
1622 **/
1623 imageLoader_set ( l, AVD_IMAGE_USERDATA );
1624 imageLoader_load( l, IMAGE_OPTIONAL | IMAGE_DONT_LOCK );
1625
1626 /* get the path of the source file, and check that it actually exists
1627 * if the user didn't provide an explicit data file
1628 */
1629 srcData = imageLoader_extractPath(l);
1630 if (srcData == NULL && params->forcePaths[AVD_IMAGE_USERDATA] == NULL) {
1631 derror("There is no %s image in your build directory. Please make a full build",
1632 l->imageText, l->imageFile);
1633 exit(2);
1634 }
1635
1636 /* get the path of the target file */
1637 l->imageFile = "userdata-qemu.img";
1638 imageLoader_load( l, IMAGE_OPTIONAL |
1639 IMAGE_EMPTY_IF_MISSING |
1640 IMAGE_IGNORE_IF_LOCKED );
1641
1642 /* force a data wipe if we just created the image */
1643 if (l->pState[0] == IMAGE_STATE_LOCKED_EMPTY)
1644 wipeData = 1;
1645
1646 /* if the image was already locked, create a temp file
1647 * then force a data wipe.
1648 */
1649 if (l->pPath[0] == NULL) {
1650 TempFile* temp = tempfile_create();
1651 imageLoader_setPath(l, tempfile_path(temp));
1652 dwarning( "Another emulator is running. user data changes will *NOT* be saved");
1653 wipeData = 1;
1654 }
1655
1656 /* in the case of a data wipe, copy userdata.img into
1657 * the destination */
1658 if (wipeData) {
1659 if (srcData == NULL || !path_exists(srcData)) {
1660 derror("There is no %s image in your build directory. Please make a full build",
1661 l->imageText, _imageFileNames[l->id]);
1662 exit(2);
1663 }
1664 if (path_copy_file( l->pPath[0], srcData ) < 0) {
1665 derror("could not initialize %s image from %s: %s",
1666 l->imageText, temp, strerror(errno));
1667 exit(2);
1668 }
1669 }
1670
1671 AFREE(srcData);
1672
1673 /** load the ramdisk image
1674 **/
1675 imageLoader_set ( l, AVD_IMAGE_RAMDISK );
1676 imageLoader_load( l, IMAGE_REQUIRED |
1677 IMAGE_DONT_LOCK );
1678
1679 /** load the system image. read-only. the caller must
1680 ** take care of checking the state
1681 **/
1682 imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
1683 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK );
1684
1685 /* force the system image to read-only status */
1686 l->pState[0] = IMAGE_STATE_READONLY;
1687
1688 /** cache partition handling
1689 **/
1690 if (!noCache) {
1691 imageLoader_set (l, AVD_IMAGE_CACHE);
1692
1693 /* if the user provided one cache image, lock & use it */
1694 if ( params->forcePaths[l->id] != NULL ) {
1695 imageLoader_load(l, IMAGE_REQUIRED |
1696 IMAGE_IGNORE_IF_LOCKED);
1697 }
1698 }
1699
1700 /** SD Card image
1701 **/
1702 if (!noSdCard) {
1703 imageLoader_set (l, AVD_IMAGE_SDCARD);
1704 imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED);
1705 }
1706
1707 return 0;
1708}
1709
1710static int
1711_getBuildSkin( AvdInfo* i, AvdInfoParams* params )
1712{
1713 /* the (current) default skin name for our build system */
1714 const char* skinName = params->skinName;
1715 const char* skinDir = params->skinRootPath;
1716 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
1717 char* q;
1718
1719 if (!skinName) {
1720 /* the (current) default skin name for the build system */
1721 skinName = SKIN_DEFAULT;
1722 DD("selecting default skin name '%s'", skinName);
1723 }
1724
1725 i->skinName = ASTRDUP(skinName);
1726
1727 if (!skinDir) {
1728
1729#define PREBUILT_SKINS_DIR "development/emulator/skins"
1730
1731 /* the (current) default skin directory */
1732 p = bufprint( temp, end, "%s/%s",
1733 i->androidBuildRoot, PREBUILT_SKINS_DIR );
1734 } else {
1735 p = bufprint( temp, end, "%s", skinDir );
1736 }
1737
1738 q = bufprint(p, end, "/%s/layout", skinName);
1739 if (q >= end || !path_exists(temp)) {
1740 DD("skin content directory does not exist: %s", temp);
1741 if (skinDir)
1742 dwarning("could not find valid skin '%s' in %s:\n",
1743 skinName, temp);
1744 return -1;
1745 }
1746 *p = 0;
1747 DD("found skin path: %s", temp);
1748 i->skinDirPath = ASTRDUP(temp);
1749
1750 return 0;
1751}
1752
1753AvdInfo*
1754avdInfo_newForAndroidBuild( const char* androidBuildRoot,
1755 const char* androidOut,
1756 AvdInfoParams* params )
1757{
1758 AvdInfo* i;
1759
1760 ANEW0(i);
1761
1762 i->inAndroidBuild = 1;
1763 i->androidBuildRoot = ASTRDUP(androidBuildRoot);
1764 i->androidOut = ASTRDUP(androidOut);
1765 i->contentPath = ASTRDUP(androidOut);
1766
1767 /* TODO: find a way to provide better information from the build files */
1768 i->deviceName = ASTRDUP("<build>");
1769
1770 if (_getBuildConfigIni(i) < 0 ||
1771 _getBuildImagePaths(i, params) < 0 )
1772 goto FAIL;
1773
1774 /* we don't need to fail if there is no valid skin */
1775 _getBuildSkin(i, params);
1776
1777 return i;
1778
1779FAIL:
1780 avdInfo_free(i);
1781 return NULL;
1782}
1783
1784const char*
1785avdInfo_getName( AvdInfo* i )
1786{
1787 return i ? i->deviceName : NULL;
1788}
1789
1790const char*
1791avdInfo_getImageFile( AvdInfo* i, AvdImageType imageType )
1792{
1793 if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
1794 return NULL;
1795
1796 return i->imagePath[imageType];
1797}
1798
1799int
1800avdInfo_isImageReadOnly( AvdInfo* i, AvdImageType imageType )
1801{
1802 if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
1803 return 1;
1804
1805 return (i->imageState[imageType] == IMAGE_STATE_READONLY);
1806}
1807
1808const char*
1809avdInfo_getSkinName( AvdInfo* i )
1810{
1811 return i->skinName;
1812}
1813
1814const char*
1815avdInfo_getSkinDir ( AvdInfo* i )
1816{
1817 return i->skinDirPath;
1818}
1819
1820int
1821avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw )
1822{
1823 IniFile* ini = i->configIni;
1824 int ret;
1825
1826 if (ini == NULL)
1827 ini = iniFile_newFromMemory("", 0);
1828
1829 ret = androidHwConfig_read(hw, ini);
1830
1831 if (ini != i->configIni)
1832 iniFile_free(ini);
1833
1834 return ret;
1835}
1836
1837const char*
1838avdInfo_getContentPath( AvdInfo* i )
1839{
1840 return i->contentPath;
1841}
1842
1843int
1844avdInfo_inAndroidBuild( AvdInfo* i )
1845{
1846 return i->inAndroidBuild;
1847}
1848
1849char*
1850avdInfo_getTracePath( AvdInfo* i, const char* traceName )
1851{
1852 char tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
1853
1854 if (i == NULL || traceName == NULL || traceName[0] == 0)
1855 return NULL;
1856
1857 if (i->inAndroidBuild) {
1858 p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
1859 i->androidOut, traceName );
1860 } else {
1861 p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
1862 i->contentPath, traceName );
1863 }
1864 return ASTRDUP(tmp);
1865}