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 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 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 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* 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 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* 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 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 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 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 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 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 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* 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 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 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* 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* 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 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 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 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 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* 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 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 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* 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* 932 avdInfo_getName( AvdInfo* i ) 933 { 934 return i ? i->deviceName : NULL; 935 } 936 937 const char* 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 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 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* 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* 1015 avdInfo_getRamdiskPath( AvdInfo* i ) 1016 { 1017 const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ]; 1018 return _avdInfo_getContentOrSdkFilePath(i, imageName); 1019 } 1020 1021 char* avdInfo_getCachePath( AvdInfo* i ) 1022 { 1023 const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ]; 1024 return _avdInfo_getContentFilePath(i, imageName); 1025 } 1026 1027 char* avdInfo_getDefaultCachePath( AvdInfo* i ) 1028 { 1029 const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ]; 1030 return _getFullFilePath(i->contentPath, imageName); 1031 } 1032 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* 1057 avdInfo_getSnapStoragePath( AvdInfo* i ) 1058 { 1059 const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ]; 1060 return _avdInfo_getContentFilePath(i, imageName); 1061 } 1062 1063 char* 1064 avdInfo_getSystemImagePath( AvdInfo* i ) 1065 { 1066 const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ]; 1067 return _avdInfo_getContentFilePath(i, imageName); 1068 } 1069 1070 char* 1071 avdInfo_getSystemInitImagePath( AvdInfo* i ) 1072 { 1073 const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ]; 1074 return _avdInfo_getContentOrSdkFilePath(i, imageName); 1075 } 1076 1077 char* 1078 avdInfo_getDataImagePath( AvdInfo* i ) 1079 { 1080 const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ]; 1081 return _avdInfo_getContentFilePath(i, imageName); 1082 } 1083 1084 char* 1085 avdInfo_getDefaultDataImagePath( AvdInfo* i ) 1086 { 1087 const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ]; 1088 return _getFullFilePath(i->contentPath, imageName); 1089 } 1090 1091 char* 1092 avdInfo_getDataInitImagePath( AvdInfo* i ) 1093 { 1094 const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ]; 1095 return _avdInfo_getContentOrSdkFilePath(i, imageName); 1096 } 1097 1098 int 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* 1127 avdInfo_getContentPath( AvdInfo* i ) 1128 { 1129 return i->contentPath; 1130 } 1131 1132 int 1133 avdInfo_inAndroidBuild( AvdInfo* i ) 1134 { 1135 return i->inAndroidBuild; 1136 } 1137 1138 char* 1139 avdInfo_getTargetCpuArch(AvdInfo* i) { 1140 return ASTRDUP(i->targetArch); 1141 } 1142 1143 char* 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* 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* 1169 avdInfo_getCoreHwIniPath( AvdInfo* i ) 1170 { 1171 return i->coreHardwareIniPath; 1172 } 1173 1174 1175 void 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 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* 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* 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 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 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 1354 const FileData* avdInfo_getBootProperties(AvdInfo* i) { 1355 return i->bootProperties; 1356 } 1357