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