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 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 784 785 avdInfo_getSkinInfo(i, &skinName, &skinDirPath); 786 if (skinDirPath == NULL) 787 return 0; 788 789 p = bufprint(temp, end, "%s/%s/hardware.ini", skinDirPath, skinName); 790 if (p >= end || !path_exists(temp)) { 791 DD("no skin-specific hardware.ini in %s", skinDirPath); 792 return 0; 793 } 794 795 D("found skin-specific hardware.ini: %s", temp); 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/prebuilt/android-%s/kernel/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 char* 1188 avdInfo_getCharmapFile( AvdInfo* i, const char* charmapName ) 1189 { 1190 char fileNameBuff[PATH_MAX]; 1191 const char* fileName; 1192 1193 if (charmapName == NULL || charmapName[0] == '\0') 1194 return NULL; 1195 1196 if (strstr(charmapName, ".kcm") == NULL) { 1197 snprintf(fileNameBuff, sizeof fileNameBuff, "%s.kcm", charmapName); 1198 fileName = fileNameBuff; 1199 } else { 1200 fileName = charmapName; 1201 } 1202 1203 return _avdInfo_getContentOrSdkFilePath(i, fileName); 1204 } 1205