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