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 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 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 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* 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 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* 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 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 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 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 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 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* 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 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 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* 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* 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 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* 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 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 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* 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* 839 avdInfo_getName( AvdInfo* i ) 840 { 841 return i ? i->deviceName : NULL; 842 } 843 844 const char* 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 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 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* 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* 914 avdInfo_getRamdiskPath( AvdInfo* i ) 915 { 916 const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ]; 917 return _avdInfo_getContentOrSdkFilePath(i, imageName); 918 } 919 920 char* avdInfo_getCachePath( AvdInfo* i ) 921 { 922 const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ]; 923 return _avdInfo_getContentFilePath(i, imageName); 924 } 925 926 char* avdInfo_getDefaultCachePath( AvdInfo* i ) 927 { 928 const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ]; 929 return _getFullFilePath(i->contentPath, imageName); 930 } 931 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* 956 avdInfo_getSnapStoragePath( AvdInfo* i ) 957 { 958 const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ]; 959 return _avdInfo_getContentFilePath(i, imageName); 960 } 961 962 char* 963 avdInfo_getSystemImagePath( AvdInfo* i ) 964 { 965 const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ]; 966 return _avdInfo_getContentFilePath(i, imageName); 967 } 968 969 char* 970 avdInfo_getSystemInitImagePath( AvdInfo* i ) 971 { 972 const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ]; 973 return _avdInfo_getContentOrSdkFilePath(i, imageName); 974 } 975 976 char* 977 avdInfo_getDataImagePath( AvdInfo* i ) 978 { 979 const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ]; 980 return _avdInfo_getContentFilePath(i, imageName); 981 } 982 983 char* 984 avdInfo_getDefaultDataImagePath( AvdInfo* i ) 985 { 986 const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ]; 987 return _getFullFilePath(i->contentPath, imageName); 988 } 989 990 char* 991 avdInfo_getDataInitImagePath( AvdInfo* i ) 992 { 993 const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ]; 994 return _avdInfo_getContentOrSdkFilePath(i, imageName); 995 } 996 997 int 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* 1026 avdInfo_getContentPath( AvdInfo* i ) 1027 { 1028 return i->contentPath; 1029 } 1030 1031 int 1032 avdInfo_inAndroidBuild( AvdInfo* i ) 1033 { 1034 return i->inAndroidBuild; 1035 } 1036 1037 char* 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* 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* 1066 avdInfo_getCoreHwIniPath( AvdInfo* i ) 1067 { 1068 return i->coreHardwareIniPath; 1069 } 1070 1071 1072 void 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 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* 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 1214 int avdInfo_getAdbdCommunicationMode( AvdInfo* i ) 1215 { 1216 return path_getAdbdCommunicationMode(i->androidOut); 1217 } 1218 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