1 /* 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/avd/util.h"
14 #include "android/config/config.h"
15 #include "android/utils/path.h"
16 #include "android/utils/bufprint.h"
17 #include "android/utils/filelock.h"
18 #include "android/utils/tempfile.h"
19 #include "android/utils/debug.h"
20 #include "android/utils/dirscanner.h"
21 #include <ctype.h>
22 #include <stddef.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <errno.h>
27
28 /* global variables - see android/globals.h */
29 AvdInfoParams android_avdParams[1];
30 AvdInfo* android_avdInfo;
31
32 /* for debugging */
33 #define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
34 #define DD(...) VERBOSE_PRINT(avd_config,__VA_ARGS__)
35
36 /* technical note on how all of this is supposed to work:
37 *
38 * Each AVD corresponds to a "content directory" that is used to
39 * store persistent disk images and configuration files. Most remarkable
40 * are:
41 *
42 * - a "config.ini" file used to hold configuration information for the
43 * AVD
44 *
45 * - mandatory user data image ("userdata-qemu.img") and cache image
46 * ("cache.img")
47 *
48 * - optional mutable system image ("system-qemu.img"), kernel image
49 * ("kernel-qemu") and read-only ramdisk ("ramdisk.img")
50 *
51 * When starting up an AVD, the emulator looks for relevant disk images
52 * in the content directory. If it doesn't find a given image there, it
53 * will try to search in the list of system directories listed in the
54 * 'config.ini' file through one of the following (key,value) pairs:
55 *
56 * images.sysdir.1 = <first search path>
57 * images.sysdir.2 = <second search path>
58 *
59 * The search paths can be absolute, or relative to the root SDK installation
60 * path (which is determined from the emulator program's location, or from the
61 * ANDROID_SDK_ROOT environment variable).
62 *
63 * Individual image disk search patch can be over-riden on the command-line
64 * with one of the usual options.
65 */
66
67 /* the prefix of config.ini keys that will be used for search directories
68 * of system images.
69 */
70 #define SEARCH_PREFIX "image.sysdir."
71
72 /* the maximum number of search path keys we're going to read from the
73 * config.ini file
74 */
75 #define MAX_SEARCH_PATHS 2
76
77 /* the config.ini key that will be used to indicate the full relative
78 * path to the skin directory (including the skin name).
79 */
80 #define SKIN_PATH "skin.path"
81
82 /* the config.ini key that will be used to indicate the default skin's name.
83 * this is ignored if there is a valid SKIN_PATH entry in the file.
84 */
85 #define SKIN_NAME "skin.name"
86
87 /* default skin name */
88 #define SKIN_DEFAULT "HVGA"
89
90 /* 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
96 /* the name of the .ini file that will contain the complete hardware
97 * properties for the AVD. This will be used to launch the corresponding
98 * core from the UI.
99 */
100 #define CORE_HARDWARE_INI "hardware-qemu.ini"
101
102 /* certain disk image files are mounted read/write by the emulator
103 * to ensure that several emulators referencing the same files
104 * do not corrupt these files, we need to lock them and respond
105 * to collision depending on the image type.
106 *
107 * the enumeration below is used to record information about
108 * each image file path.
109 *
110 * READONLY means that the file will be mounted read-only
111 * and this doesn't need to be locked. must be first in list
112 *
113 * MUSTLOCK means that the file should be locked before
114 * being mounted by the emulator
115 *
116 * TEMPORARY means that the file has been copied to a
117 * temporary image, which can be mounted read/write
118 * but doesn't require locking.
119 */
120 typedef enum {
121 IMAGE_STATE_READONLY, /* unlocked */
122 IMAGE_STATE_MUSTLOCK, /* must be locked */
123 IMAGE_STATE_LOCKED, /* locked */
124 IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
125 IMAGE_STATE_TEMPORARY, /* copied to temp file (no lock needed) */
126 } AvdImageState;
127
128 struct AvdInfo {
129 /* for the Android build system case */
130 char inAndroidBuild;
131 char* androidOut;
132 char* androidBuildRoot;
133 char* targetArch;
134
135 /* for the normal virtual device case */
136 char* deviceName;
137 char* sdkRootPath;
138 char sdkRootPathFromEnv;
139 char* searchPaths[ MAX_SEARCH_PATHS ];
140 int numSearchPaths;
141 char* contentPath;
142 IniFile* rootIni; /* root <foo>.ini file, empty if missing */
143 IniFile* configIni; /* virtual device's config.ini, NULL if missing */
144 IniFile* skinHardwareIni; /* skin-specific hardware.ini */
145
146 /* for both */
147 int apiLevel;
148 char* skinName; /* skin name */
149 char* skinDirPath; /* skin directory */
150 char* coreHardwareIniPath; /* core hardware.ini path */
151
152 /* image files */
153 char* imagePath [ AVD_IMAGE_MAX ];
154 char imageState[ AVD_IMAGE_MAX ];
155 };
156
157
158 void
avdInfo_free(AvdInfo * i)159 avdInfo_free( AvdInfo* i )
160 {
161 if (i) {
162 int nn;
163
164 for (nn = 0; nn < AVD_IMAGE_MAX; nn++)
165 AFREE(i->imagePath[nn]);
166
167 AFREE(i->skinName);
168 AFREE(i->skinDirPath);
169 AFREE(i->coreHardwareIniPath);
170
171 for (nn = 0; nn < i->numSearchPaths; nn++)
172 AFREE(i->searchPaths[nn]);
173
174 i->numSearchPaths = 0;
175
176 if (i->configIni) {
177 iniFile_free(i->configIni);
178 i->configIni = NULL;
179 }
180
181 if (i->skinHardwareIni) {
182 iniFile_free(i->skinHardwareIni);
183 i->skinHardwareIni = NULL;
184 }
185
186 if (i->rootIni) {
187 iniFile_free(i->rootIni);
188 i->rootIni = NULL;
189 }
190
191 AFREE(i->contentPath);
192 AFREE(i->sdkRootPath);
193
194 if (i->inAndroidBuild) {
195 AFREE(i->androidOut);
196 AFREE(i->androidBuildRoot);
197 }
198
199 AFREE(i->deviceName);
200 AFREE(i);
201 }
202 }
203
204 /* list of default file names for each supported image file type */
205 static const char* const _imageFileNames[ AVD_IMAGE_MAX ] = {
206 #define _AVD_IMG(x,y,z) y,
207 AVD_IMAGE_LIST
208 #undef _AVD_IMG
209 };
210
211 /* list of short text description for each supported image file type */
212 static const char* const _imageFileText[ AVD_IMAGE_MAX ] = {
213 #define _AVD_IMG(x,y,z) z,
214 AVD_IMAGE_LIST
215 #undef _AVD_IMG
216 };
217
218 /***************************************************************
219 ***************************************************************
220 *****
221 ***** UTILITY FUNCTIONS
222 *****
223 ***** The following functions do not depend on the AvdInfo
224 ***** structure and could easily be moved elsewhere.
225 *****
226 *****/
227
228 /* Parse a given config.ini file and extract the list of SDK search paths
229 * from it. Returns the number of valid paths stored in 'searchPaths', or -1
230 * in case of problem.
231 *
232 * Relative search paths in the config.ini will be stored as full pathnames
233 * relative to 'sdkRootPath'.
234 *
235 * 'searchPaths' must be an array of char* pointers of at most 'maxSearchPaths'
236 * entries.
237 */
238 static int
_getSearchPaths(IniFile * configIni,const char * sdkRootPath,int maxSearchPaths,char ** searchPaths)239 _getSearchPaths( IniFile* configIni,
240 const char* sdkRootPath,
241 int maxSearchPaths,
242 char** searchPaths )
243 {
244 char temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
245 int nn, count = 0;
246
247 for (nn = 0; nn < maxSearchPaths; nn++) {
248 char* path;
249
250 p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
251 if (p >= end)
252 continue;
253
254 path = iniFile_getString(configIni, temp, NULL);
255 if (path != NULL) {
256 DD(" found image search path: %s", path);
257 if (!path_is_absolute(path)) {
258 p = bufprint(temp, end, "%s/%s", sdkRootPath, path);
259 AFREE(path);
260 path = ASTRDUP(temp);
261 }
262 searchPaths[count++] = path;
263 }
264 }
265 return count;
266 }
267
268 /* Check that an AVD name is valid. Returns 1 on success, 0 otherwise.
269 */
270 static int
_checkAvdName(const char * name)271 _checkAvdName( const char* name )
272 {
273 int len = strlen(name);
274 int len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
275 "abcdefghijklmnopqrstuvwxyz"
276 "0123456789_.-");
277 return (len == len2);
278 }
279
280 /* Returns the full path of a given file.
281 *
282 * If 'fileName' is an absolute path, this returns a simple copy.
283 * Otherwise, this returns a new string corresponding to <rootPath>/<fileName>
284 *
285 * This returns NULL if the paths are too long.
286 */
287 static char*
_getFullFilePath(const char * rootPath,const char * fileName)288 _getFullFilePath( const char* rootPath, const char* fileName )
289 {
290 if (path_is_absolute(fileName)) {
291 return ASTRDUP(fileName);
292 } else {
293 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
294
295 p = bufprint(temp, end, "%s/%s", rootPath, fileName);
296 if (p >= end) {
297 return NULL;
298 }
299 return ASTRDUP(temp);
300 }
301 }
302
303 /* check that a given directory contains a valid skin.
304 * returns 1 on success, 0 on failure.
305 */
306 static int
_checkSkinPath(const char * skinPath)307 _checkSkinPath( const char* skinPath )
308 {
309 char temp[MAX_PATH], *p=temp, *end=p+sizeof(temp);
310
311 /* for now, if it has a 'layout' file, it is a valid skin path */
312 p = bufprint(temp, end, "%s/layout", skinPath);
313 if (p >= end || !path_exists(temp))
314 return 0;
315
316 return 1;
317 }
318
319 /* Check that there is a skin named 'skinName' listed from 'skinDirRoot'
320 * this returns the full path of the skin directory (after alias expansions),
321 * including the skin name, or NULL on failure.
322 */
323 static char*
_checkSkinSkinsDir(const char * skinDirRoot,const char * skinName)324 _checkSkinSkinsDir( const char* skinDirRoot,
325 const char* skinName )
326 {
327 DirScanner* scanner;
328 char* result;
329 char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
330
331 p = bufprint(temp, end, "%s/skins/%s", skinDirRoot, skinName);
332 DD("Probing skin directory: %s", temp);
333 if (p >= end || !path_exists(temp)) {
334 DD(" ignore bad skin directory %s", temp);
335 return NULL;
336 }
337
338 /* first, is this a normal skin directory ? */
339 if (_checkSkinPath(temp)) {
340 /* yes */
341 DD(" found skin directory: %s", temp);
342 return ASTRDUP(temp);
343 }
344
345 /* second, is it an alias to another skin ? */
346 *p = 0;
347 result = NULL;
348 scanner = dirScanner_new(temp);
349 if (scanner != NULL) {
350 for (;;) {
351 const char* file = dirScanner_next(scanner);
352
353 if (file == NULL)
354 break;
355
356 if (strncmp(file, "alias-", 6) || file[6] == 0)
357 continue;
358
359 p = bufprint(temp, end, "%s/skins/%s", skinDirRoot, file+6);
360 if (p < end && _checkSkinPath(temp)) {
361 /* yes, it's an alias */
362 DD(" skin alias '%s' points to skin directory: %s",
363 file+6, temp);
364 result = ASTRDUP(temp);
365 break;
366 }
367 }
368 dirScanner_free(scanner);
369 }
370 return result;
371 }
372
373 /* try to see if the skin name leads to a magic skin or skin path directly
374 * returns 1 on success, 0 on error.
375 *
376 * on success, this sets up '*pSkinName' and '*pSkinDir'
377 */
378 static int
_getSkinPathFromName(const char * skinName,const char * sdkRootPath,char ** pSkinName,char ** pSkinDir)379 _getSkinPathFromName( const char* skinName,
380 const char* sdkRootPath,
381 char** pSkinName,
382 char** pSkinDir )
383 {
384 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
385
386 /* if the skin name has the format 'NNNNxNNN' where
387 * NNN is a decimal value, then this is a 'magic' skin
388 * name that doesn't require a skin directory
389 */
390 if (isdigit(skinName[0])) {
391 int width, height;
392 if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
393 D("'magic' skin format detected: %s", skinName);
394 *pSkinName = ASTRDUP(skinName);
395 *pSkinDir = NULL;
396 return 1;
397 }
398 }
399
400 /* is the skin name a direct path to the skin directory ? */
401 if (path_is_absolute(skinName) && _checkSkinPath(skinName)) {
402 goto FOUND_IT;
403 }
404
405 /* is the skin name a relative path from the SDK root ? */
406 p = bufprint(temp, end, "%s/%s", sdkRootPath, skinName);
407 if (p < end && _checkSkinPath(temp)) {
408 skinName = temp;
409 goto FOUND_IT;
410 }
411
412 /* nope */
413 return 0;
414
415 FOUND_IT:
416 if (path_split(skinName, pSkinDir, pSkinName) < 0) {
417 derror("malformed skin name: %s", skinName);
418 exit(2);
419 }
420 D("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
421 return 1;
422 }
423
424 /***************************************************************
425 ***************************************************************
426 *****
427 ***** NORMAL VIRTUAL DEVICE SUPPORT
428 *****
429 *****/
430
431 /* compute path to the root SDK directory
432 * assume we are in $SDKROOT/tools/emulator[.exe]
433 */
434 static int
_avdInfo_getSdkRoot(AvdInfo * i)435 _avdInfo_getSdkRoot( AvdInfo* i )
436 {
437
438 i->sdkRootPath = path_getSdkRoot(&i->sdkRootPathFromEnv);
439 if (i->sdkRootPath == NULL)
440 return -1;
441
442 return 0;
443 }
444
445 /* parse the root config .ini file. it is located in
446 * ~/.android/avd/<name>.ini or Windows equivalent
447 */
448 static int
_avdInfo_getRootIni(AvdInfo * i)449 _avdInfo_getRootIni( AvdInfo* i )
450 {
451 char* iniPath = path_getRootIniPath( i->deviceName );
452
453 if (iniPath == NULL) {
454 derror("unknown virtual device name: '%s'", i->deviceName);
455 return -1;
456 }
457
458 D("Android virtual device file at: %s", iniPath);
459
460 i->rootIni = iniFile_newFromFile(iniPath);
461 AFREE(iniPath);
462
463 if (i->rootIni == NULL) {
464 derror("Corrupt virtual device config file!");
465 return -1;
466 }
467 return 0;
468 }
469
470 /* Returns the AVD's content path, i.e. the directory that contains
471 * the AVD's content files (e.g. data partition, cache, sd card, etc...).
472 *
473 * We extract this by parsing the root config .ini file, looking for
474 * a "path" elements.
475 */
476 static int
_avdInfo_getContentPath(AvdInfo * i)477 _avdInfo_getContentPath( AvdInfo* i )
478 {
479 # define ROOT_PATH_KEY "path"
480
481 i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY, NULL);
482
483 if (i->contentPath == NULL) {
484 derror("bad config: %s",
485 "virtual device file lacks a "ROOT_PATH_KEY" entry");
486 return -1;
487 }
488 D("virtual device content at %s", i->contentPath);
489 return 0;
490 }
491
492 static int
_avdInfo_getApiLevel(AvdInfo * i)493 _avdInfo_getApiLevel( AvdInfo* i )
494 {
495 char* target;
496 const char* p;
497 const int defaultLevel = 1000;
498 int level = defaultLevel;
499
500 # define ROOT_TARGET_KEY "target"
501
502 target = iniFile_getString(i->rootIni, ROOT_TARGET_KEY, NULL);
503 if (target == NULL) {
504 D("No target field in root AVD .ini file?");
505 D("Defaulting to API level %d", level);
506 return level;
507 }
508
509 DD("Found target field in root AVD .ini file: '%s'", target);
510
511 /* There are two acceptable formats for the target key.
512 *
513 * 1/ android-<level>
514 * 2/ <vendor-name>:<add-on-name>:<level>
515 *
516 * Where <level> can be either a _name_ (for experimental/preview SDK builds)
517 * or a decimal number. Note that if a _name_, it can start with a digit.
518 */
519
520 /* First, extract the level */
521 if (!memcmp(target, "android-", 8))
522 p = target + 8;
523 else {
524 /* skip two columns */
525 p = strchr(target, ':');
526 if (p != NULL) {
527 p = strchr(p+1, ':');
528 if (p != NULL)
529 p += 1;
530 }
531 }
532 if (p == NULL || !isdigit(*p)) {
533 goto NOT_A_NUMBER;
534 } else {
535 char* end;
536 long val = strtol(p, &end, 10);
537 if (end == NULL || *end != '\0' || val != (int)val) {
538 goto NOT_A_NUMBER;
539 }
540 level = (int)val;
541
542 /* Sanity check, we don't support anything prior to Android 1.5 */
543 if (level < 3)
544 level = 3;
545
546 D("Found AVD target API level: %d", level);
547 }
548 EXIT:
549 AFREE(target);
550 return level;
551
552 NOT_A_NUMBER:
553 if (p == NULL) {
554 D("Invalid target field in root AVD .ini file");
555 } else {
556 D("Target AVD api level is not a number");
557 }
558 D("Defaulting to API level %d", level);
559 goto EXIT;
560 }
561
562 /* Look for a named file inside the AVD's content directory.
563 * Returns NULL if it doesn't exist, or a strdup() copy otherwise.
564 */
565 static char*
_avdInfo_getContentFilePath(AvdInfo * i,const char * fileName)566 _avdInfo_getContentFilePath(AvdInfo* i, const char* fileName)
567 {
568 char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
569
570 p = bufprint(p, end, "%s/%s", i->contentPath, fileName);
571 if (p >= end) {
572 derror("can't access virtual device content directory");
573 return NULL;
574 }
575 if (!path_exists(temp)) {
576 return NULL;
577 }
578 return ASTRDUP(temp);
579 }
580
581 /* find and parse the config.ini file from the content directory */
582 static int
_avdInfo_getConfigIni(AvdInfo * i)583 _avdInfo_getConfigIni(AvdInfo* i)
584 {
585 char* iniPath = _avdInfo_getContentFilePath(i, "config.ini");
586
587 /* Allow non-existing config.ini */
588 if (iniPath == NULL) {
589 D("virtual device has no config file - no problem");
590 return 0;
591 }
592
593 D("virtual device config file: %s", iniPath);
594 i->configIni = iniFile_newFromFile(iniPath);
595 AFREE(iniPath);
596
597 if (i->configIni == NULL) {
598 derror("bad config: %s",
599 "virtual device has corrupted config.ini");
600 return -1;
601 }
602 return 0;
603 }
604
605 /* The AVD's config.ini contains a list of search paths (all beginning
606 * with SEARCH_PREFIX) which are directory locations searched for
607 * AVD platform files.
608 */
609 static void
_avdInfo_getSearchPaths(AvdInfo * i)610 _avdInfo_getSearchPaths( AvdInfo* i )
611 {
612 if (i->configIni == NULL)
613 return;
614
615 i->numSearchPaths = _getSearchPaths( i->configIni,
616 i->sdkRootPath,
617 MAX_SEARCH_PATHS,
618 i->searchPaths );
619 if (i->numSearchPaths == 0) {
620 derror("no search paths found in this AVD's configuration.\n"
621 "Weird, the AVD's config.ini file is malformed. Try re-creating it.\n");
622 exit(2);
623 }
624 else
625 DD("found a total of %d search paths for this AVD", i->numSearchPaths);
626 }
627
628 /* Search a file in the SDK search directories. Return NULL if not found,
629 * or a strdup() otherwise.
630 */
631 static char*
_avdInfo_getSdkFilePath(AvdInfo * i,const char * fileName)632 _avdInfo_getSdkFilePath(AvdInfo* i, const char* fileName)
633 {
634 char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
635
636 do {
637 /* try the search paths */
638 int nn;
639
640 for (nn = 0; nn < i->numSearchPaths; nn++) {
641 const char* searchDir = i->searchPaths[nn];
642
643 p = bufprint(temp, end, "%s/%s", searchDir, fileName);
644 if (p < end && path_exists(temp)) {
645 DD("found %s in search dir: %s", fileName, searchDir);
646 goto FOUND;
647 }
648 DD(" no %s in search dir: %s", fileName, searchDir);
649 }
650
651 return NULL;
652
653 } while (0);
654
655 FOUND:
656 return ASTRDUP(temp);
657 }
658
659 /* Search for a file in the content directory, and if not found, in the
660 * SDK search directory. Returns NULL if not found.
661 */
662 static char*
_avdInfo_getContentOrSdkFilePath(AvdInfo * i,const char * fileName)663 _avdInfo_getContentOrSdkFilePath(AvdInfo* i, const char* fileName)
664 {
665 char* path;
666
667 path = _avdInfo_getContentFilePath(i, fileName);
668 if (path)
669 return path;
670
671 path = _avdInfo_getSdkFilePath(i, fileName);
672 if (path)
673 return path;
674
675 return NULL;
676 }
677
678 #if 0
679 static int
680 _avdInfo_findContentOrSdkImage(AvdInfo* i, AvdImageType id)
681 {
682 const char* fileName = _imageFileNames[id];
683 char* path = _avdInfo_getContentOrSdkFilePath(i, fileName);
684
685 i->imagePath[id] = path;
686 i->imageState[id] = IMAGE_STATE_READONLY;
687
688 if (path == NULL)
689 return -1;
690 else
691 return 0;
692 }
693 #endif
694
695 /* Returns path to the core hardware .ini file. This contains the
696 * hardware configuration that is read by the core. The content of this
697 * file is auto-generated before launching a core, but we need to know
698 * its path before that.
699 */
700 static int
_avdInfo_getCoreHwIniPath(AvdInfo * i,const char * basePath)701 _avdInfo_getCoreHwIniPath( AvdInfo* i, const char* basePath )
702 {
703 i->coreHardwareIniPath = _getFullFilePath(basePath, CORE_HARDWARE_INI);
704 if (i->coreHardwareIniPath == NULL) {
705 DD("Path too long for %s: %s", CORE_HARDWARE_INI, basePath);
706 return -1;
707 }
708 D("using core hw config path: %s", i->coreHardwareIniPath);
709 return 0;
710 }
711
712 AvdInfo*
avdInfo_new(const char * name,AvdInfoParams * params)713 avdInfo_new( const char* name, AvdInfoParams* params )
714 {
715 AvdInfo* i;
716
717 if (name == NULL)
718 return NULL;
719
720 if (!_checkAvdName(name)) {
721 derror("virtual device name contains invalid characters");
722 exit(1);
723 }
724
725 ANEW0(i);
726 i->deviceName = ASTRDUP(name);
727
728 if ( _avdInfo_getSdkRoot(i) < 0 ||
729 _avdInfo_getRootIni(i) < 0 ||
730 _avdInfo_getContentPath(i) < 0 ||
731 _avdInfo_getConfigIni(i) < 0 ||
732 _avdInfo_getCoreHwIniPath(i, i->contentPath) < 0 )
733 goto FAIL;
734
735 i->apiLevel = _avdInfo_getApiLevel(i);
736
737 /* look for image search paths. handle post 1.1/pre cupcake
738 * obsolete SDKs.
739 */
740 _avdInfo_getSearchPaths(i);
741
742 /* don't need this anymore */
743 iniFile_free(i->rootIni);
744 i->rootIni = NULL;
745
746 return i;
747
748 FAIL:
749 avdInfo_free(i);
750 return NULL;
751 }
752
753 /***************************************************************
754 ***************************************************************
755 *****
756 ***** ANDROID BUILD SUPPORT
757 *****
758 ***** The code below corresponds to the case where we're
759 ***** starting the emulator inside the Android build
760 ***** system. The main differences are that:
761 *****
762 ***** - the $ANDROID_PRODUCT_OUT directory is used as the
763 ***** content file.
764 *****
765 ***** - built images must not be modified by the emulator,
766 ***** so system.img must be copied to a temporary file
767 ***** and userdata.img must be copied to userdata-qemu.img
768 ***** if the latter doesn't exist.
769 *****
770 ***** - the kernel and default skin directory are taken from
771 ***** prebuilt
772 *****
773 ***** - there is no root .ini file, or any config.ini in
774 ***** the content directory, no SDK images search path.
775 *****/
776
777 /* Read a hardware.ini if it is located in the skin directory */
778 static int
_avdInfo_getBuildSkinHardwareIni(AvdInfo * i)779 _avdInfo_getBuildSkinHardwareIni( AvdInfo* i )
780 {
781 char* skinName;
782 char* skinDirPath;
783
784 avdInfo_getSkinInfo(i, &skinName, &skinDirPath);
785 if (skinDirPath == NULL)
786 return 0;
787
788 int result = avdInfo_getSkinHardwareIni(i, skinName, skinDirPath);
789
790 AFREE(skinName);
791 AFREE(skinDirPath);
792
793 return result;
794 }
795
avdInfo_getSkinHardwareIni(AvdInfo * i,char * skinName,char * skinDirPath)796 int avdInfo_getSkinHardwareIni( AvdInfo* i, char* skinName, char* skinDirPath)
797 {
798 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
799
800 p = bufprint(temp, end, "%s/%s/hardware.ini", skinDirPath, skinName);
801 if (p >= end || !path_exists(temp)) {
802 DD("no skin-specific hardware.ini in %s", skinDirPath);
803 return 0;
804 }
805
806 D("found skin-specific hardware.ini: %s", temp);
807 if (i->skinHardwareIni != NULL)
808 iniFile_free(i->skinHardwareIni);
809 i->skinHardwareIni = iniFile_newFromFile(temp);
810 if (i->skinHardwareIni == NULL)
811 return -1;
812
813 return 0;
814 }
815
816 AvdInfo*
avdInfo_newForAndroidBuild(const char * androidBuildRoot,const char * androidOut,AvdInfoParams * params)817 avdInfo_newForAndroidBuild( const char* androidBuildRoot,
818 const char* androidOut,
819 AvdInfoParams* params )
820 {
821 AvdInfo* i;
822
823 ANEW0(i);
824
825 i->inAndroidBuild = 1;
826 i->androidBuildRoot = ASTRDUP(androidBuildRoot);
827 i->androidOut = ASTRDUP(androidOut);
828 i->contentPath = ASTRDUP(androidOut);
829 i->targetArch = path_getBuildTargetArch(i->androidOut);
830 i->apiLevel = path_getBuildTargetApiLevel(i->androidOut);
831
832 /* TODO: find a way to provide better information from the build files */
833 i->deviceName = ASTRDUP("<build>");
834
835 /* There is no config.ini in the build */
836 i->configIni = NULL;
837
838 if (_avdInfo_getCoreHwIniPath(i, i->androidOut) < 0 )
839 goto FAIL;
840
841 /* Read the build skin's hardware.ini, if any */
842 _avdInfo_getBuildSkinHardwareIni(i);
843
844 return i;
845
846 FAIL:
847 avdInfo_free(i);
848 return NULL;
849 }
850
851 const char*
avdInfo_getName(AvdInfo * i)852 avdInfo_getName( AvdInfo* i )
853 {
854 return i ? i->deviceName : NULL;
855 }
856
857 const char*
avdInfo_getImageFile(AvdInfo * i,AvdImageType imageType)858 avdInfo_getImageFile( AvdInfo* i, AvdImageType imageType )
859 {
860 if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
861 return NULL;
862
863 return i->imagePath[imageType];
864 }
865
866 uint64_t
avdInfo_getImageFileSize(AvdInfo * i,AvdImageType imageType)867 avdInfo_getImageFileSize( AvdInfo* i, AvdImageType imageType )
868 {
869 const char* file = avdInfo_getImageFile(i, imageType);
870 uint64_t size;
871
872 if (file == NULL)
873 return 0ULL;
874
875 if (path_get_size(file, &size) < 0)
876 return 0ULL;
877
878 return size;
879 }
880
881 int
avdInfo_isImageReadOnly(AvdInfo * i,AvdImageType imageType)882 avdInfo_isImageReadOnly( AvdInfo* i, AvdImageType imageType )
883 {
884 if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX)
885 return 1;
886
887 return (i->imageState[imageType] == IMAGE_STATE_READONLY);
888 }
889
890 char*
avdInfo_getKernelPath(AvdInfo * i)891 avdInfo_getKernelPath( AvdInfo* i )
892 {
893 const char* imageName = _imageFileNames[ AVD_IMAGE_KERNEL ];
894
895 char* kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
896
897 if (kernelPath == NULL && i->inAndroidBuild) {
898 /* When in the Android build, look into the prebuilt directory
899 * for our target architecture.
900 */
901 char temp[PATH_MAX], *p = temp, *end = p + sizeof(temp);
902 const char* suffix = "";
903 char* abi;
904
905 /* If the target ABI is armeabi-v7a, then look for
906 * kernel-qemu-armv7 instead of kernel-qemu in the prebuilt
907 * directory. */
908 abi = path_getBuildTargetAbi(i->androidOut);
909 if (!strcmp(abi,"armeabi-v7a")) {
910 suffix = "-armv7";
911 }
912 AFREE(abi);
913
914 p = bufprint(temp, end, "%s/prebuilts/qemu-kernel/%s/kernel-qemu%s",
915 i->androidBuildRoot, i->targetArch, suffix);
916 if (p >= end || !path_exists(temp)) {
917 derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
918 exit(1);
919 }
920 kernelPath = ASTRDUP(temp);
921 }
922 return kernelPath;
923 }
924
925
926 char*
avdInfo_getRamdiskPath(AvdInfo * i)927 avdInfo_getRamdiskPath( AvdInfo* i )
928 {
929 const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ];
930 return _avdInfo_getContentOrSdkFilePath(i, imageName);
931 }
932
avdInfo_getCachePath(AvdInfo * i)933 char* avdInfo_getCachePath( AvdInfo* i )
934 {
935 const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
936 return _avdInfo_getContentFilePath(i, imageName);
937 }
938
avdInfo_getDefaultCachePath(AvdInfo * i)939 char* avdInfo_getDefaultCachePath( AvdInfo* i )
940 {
941 const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
942 return _getFullFilePath(i->contentPath, imageName);
943 }
944
avdInfo_getSdCardPath(AvdInfo * i)945 char* avdInfo_getSdCardPath( AvdInfo* i )
946 {
947 const char* imageName = _imageFileNames[ AVD_IMAGE_SDCARD ];
948 char* path;
949
950 /* Special case, the config.ini can have a SDCARD_PATH entry
951 * that gives the full path to the SD Card.
952 */
953 if (i->configIni != NULL) {
954 path = iniFile_getString(i->configIni, SDCARD_PATH, NULL);
955 if (path != NULL) {
956 if (path_exists(path))
957 return path;
958
959 dwarning("Ignoring invalid SDCard path: %s", path);
960 AFREE(path);
961 }
962 }
963
964 /* Otherwise, simply look into the content directory */
965 return _avdInfo_getContentFilePath(i, imageName);
966 }
967
968 char*
avdInfo_getSnapStoragePath(AvdInfo * i)969 avdInfo_getSnapStoragePath( AvdInfo* i )
970 {
971 const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ];
972 return _avdInfo_getContentFilePath(i, imageName);
973 }
974
975 char*
avdInfo_getSystemImagePath(AvdInfo * i)976 avdInfo_getSystemImagePath( AvdInfo* i )
977 {
978 const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ];
979 return _avdInfo_getContentFilePath(i, imageName);
980 }
981
982 char*
avdInfo_getSystemInitImagePath(AvdInfo * i)983 avdInfo_getSystemInitImagePath( AvdInfo* i )
984 {
985 const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ];
986 return _avdInfo_getContentOrSdkFilePath(i, imageName);
987 }
988
989 char*
avdInfo_getDataImagePath(AvdInfo * i)990 avdInfo_getDataImagePath( AvdInfo* i )
991 {
992 const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
993 return _avdInfo_getContentFilePath(i, imageName);
994 }
995
996 char*
avdInfo_getDefaultDataImagePath(AvdInfo * i)997 avdInfo_getDefaultDataImagePath( AvdInfo* i )
998 {
999 const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
1000 return _getFullFilePath(i->contentPath, imageName);
1001 }
1002
1003 char*
avdInfo_getDataInitImagePath(AvdInfo * i)1004 avdInfo_getDataInitImagePath( AvdInfo* i )
1005 {
1006 const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ];
1007 return _avdInfo_getContentOrSdkFilePath(i, imageName);
1008 }
1009
1010 int
avdInfo_initHwConfig(AvdInfo * i,AndroidHwConfig * hw)1011 avdInfo_initHwConfig( AvdInfo* i, AndroidHwConfig* hw )
1012 {
1013 int ret = 0;
1014
1015 androidHwConfig_init(hw, i->apiLevel);
1016
1017 /* First read the config.ini, if any */
1018 if (i->configIni != NULL) {
1019 ret = androidHwConfig_read(hw, i->configIni);
1020 }
1021
1022 /* The skin's hardware.ini can override values */
1023 if (ret == 0 && i->skinHardwareIni != NULL) {
1024 ret = androidHwConfig_read(hw, i->skinHardwareIni);
1025 }
1026
1027 /* Auto-disable keyboard emulation on sapphire platform builds */
1028 if (i->androidOut != NULL) {
1029 char* p = strrchr(i->androidOut, '/');
1030 if (p != NULL && !strcmp(p,"sapphire")) {
1031 hw->hw_keyboard = 0;
1032 }
1033 }
1034
1035 return ret;
1036 }
1037
1038 const char*
avdInfo_getContentPath(AvdInfo * i)1039 avdInfo_getContentPath( AvdInfo* i )
1040 {
1041 return i->contentPath;
1042 }
1043
1044 int
avdInfo_inAndroidBuild(AvdInfo * i)1045 avdInfo_inAndroidBuild( AvdInfo* i )
1046 {
1047 return i->inAndroidBuild;
1048 }
1049
1050 char*
avdInfo_getTargetAbi(AvdInfo * i)1051 avdInfo_getTargetAbi( AvdInfo* i )
1052 {
1053 /* For now, we can't get the ABI from SDK AVDs */
1054 if (!i->inAndroidBuild)
1055 return NULL;
1056
1057 return path_getBuildTargetAbi(i->androidOut);
1058 }
1059
1060 char*
avdInfo_getTracePath(AvdInfo * i,const char * traceName)1061 avdInfo_getTracePath( AvdInfo* i, const char* traceName )
1062 {
1063 char tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
1064
1065 if (i == NULL || traceName == NULL || traceName[0] == 0)
1066 return NULL;
1067
1068 if (i->inAndroidBuild) {
1069 p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
1070 i->androidOut, traceName );
1071 } else {
1072 p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
1073 i->contentPath, traceName );
1074 }
1075 return ASTRDUP(tmp);
1076 }
1077
1078 const char*
avdInfo_getCoreHwIniPath(AvdInfo * i)1079 avdInfo_getCoreHwIniPath( AvdInfo* i )
1080 {
1081 return i->coreHardwareIniPath;
1082 }
1083
1084
1085 void
avdInfo_getSkinInfo(AvdInfo * i,char ** pSkinName,char ** pSkinDir)1086 avdInfo_getSkinInfo( AvdInfo* i, char** pSkinName, char** pSkinDir )
1087 {
1088 char* skinName = NULL;
1089 char* skinPath;
1090 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
1091
1092 *pSkinName = NULL;
1093 *pSkinDir = NULL;
1094
1095 /* First, see if the config.ini contains a SKIN_PATH entry that
1096 * names the full directory path for the skin.
1097 */
1098 if (i->configIni != NULL ) {
1099 skinPath = iniFile_getString( i->configIni, SKIN_PATH, NULL );
1100 if (skinPath != NULL) {
1101 /* If this skin name is magic or a direct directory path
1102 * we have our result right here.
1103 */
1104 if (_getSkinPathFromName(skinPath, i->sdkRootPath,
1105 pSkinName, pSkinDir )) {
1106 AFREE(skinPath);
1107 return;
1108 }
1109 }
1110
1111 /* The SKIN_PATH entry was not valid, so look at SKIN_NAME */
1112 D("Warning: config.ini contains invalid %s entry: %s", SKIN_PATH, skinPath);
1113 AFREE(skinPath);
1114
1115 skinName = iniFile_getString( i->configIni, SKIN_NAME, NULL );
1116 }
1117
1118 if (skinName == NULL) {
1119 /* If there is no skin listed in the config.ini, try to see if
1120 * there is one single 'skin' directory in the content directory.
1121 */
1122 p = bufprint(temp, end, "%s/skin", i->contentPath);
1123 if (p < end && _checkSkinPath(temp)) {
1124 D("using skin content from %s", temp);
1125 AFREE(i->skinName);
1126 *pSkinName = ASTRDUP("skin");
1127 *pSkinDir = ASTRDUP(i->contentPath);
1128 return;
1129 }
1130
1131 /* otherwise, use the default name */
1132 skinName = ASTRDUP(SKIN_DEFAULT);
1133 }
1134
1135 /* now try to find the skin directory for that name -
1136 */
1137 do {
1138 /* first try the content directory, i.e. $CONTENT/skins/<name> */
1139 skinPath = _checkSkinSkinsDir(i->contentPath, skinName);
1140 if (skinPath != NULL)
1141 break;
1142
1143 #define PREBUILT_SKINS_ROOT "development/tools/emulator"
1144
1145 /* if we are in the Android build, try the prebuilt directory */
1146 if (i->inAndroidBuild) {
1147 p = bufprint( temp, end, "%s/%s",
1148 i->androidBuildRoot, PREBUILT_SKINS_ROOT );
1149 if (p < end) {
1150 skinPath = _checkSkinSkinsDir(temp, skinName);
1151 if (skinPath != NULL)
1152 break;
1153 }
1154
1155 /* or in the parent directory of the system dir */
1156 {
1157 char* parentDir = path_parent(i->androidOut, 1);
1158 if (parentDir != NULL) {
1159 skinPath = _checkSkinSkinsDir(parentDir, skinName);
1160 AFREE(parentDir);
1161 if (skinPath != NULL)
1162 break;
1163 }
1164 }
1165 }
1166
1167 /* look in the search paths. For each <dir> in the list,
1168 * look into <dir>/../skins/<name>/ */
1169 {
1170 int nn;
1171 for (nn = 0; nn < i->numSearchPaths; nn++) {
1172 char* parentDir = path_parent(i->searchPaths[nn], 1);
1173 if (parentDir == NULL)
1174 continue;
1175 skinPath = _checkSkinSkinsDir(parentDir, skinName);
1176 AFREE(parentDir);
1177 if (skinPath != NULL)
1178 break;
1179 }
1180 if (nn < i->numSearchPaths)
1181 break;
1182 }
1183
1184 /* We didn't find anything ! */
1185 *pSkinName = skinName;
1186 return;
1187
1188 } while (0);
1189
1190 if (path_split(skinPath, pSkinDir, pSkinName) < 0) {
1191 derror("weird skin path: %s", skinPath);
1192 AFREE(skinPath);
1193 return;
1194 }
1195 DD("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
1196 AFREE(skinPath);
1197 return;
1198 }
1199
1200 char*
avdInfo_getCharmapFile(AvdInfo * i,const char * charmapName)1201 avdInfo_getCharmapFile( AvdInfo* i, const char* charmapName )
1202 {
1203 char fileNameBuff[PATH_MAX];
1204 const char* fileName;
1205
1206 if (charmapName == NULL || charmapName[0] == '\0')
1207 return NULL;
1208
1209 if (strstr(charmapName, ".kcm") == NULL) {
1210 snprintf(fileNameBuff, sizeof fileNameBuff, "%s.kcm", charmapName);
1211 fileName = fileNameBuff;
1212 } else {
1213 fileName = charmapName;
1214 }
1215
1216 return _avdInfo_getContentOrSdkFilePath(i, fileName);
1217 }
1218
avdInfo_getAdbdCommunicationMode(AvdInfo * i)1219 int avdInfo_getAdbdCommunicationMode( AvdInfo* i )
1220 {
1221 return path_getAdbdCommunicationMode(i->androidOut);
1222 }
1223
avdInfo_getSnapshotPresent(AvdInfo * i)1224 int avdInfo_getSnapshotPresent(AvdInfo* i)
1225 {
1226 if (i->configIni == NULL) {
1227 return 0;
1228 } else {
1229 return iniFile_getBoolean(i->configIni, "snapshot.present", "no");
1230 }
1231 }
1232