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