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