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 */ 29AvdInfoParams android_avdParams[1]; 30AvdInfo* 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 */ 120typedef 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 128struct 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 158void 159avdInfo_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 */ 205static 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 */ 212static 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 */ 238static 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 */ 270static 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 */ 287static 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 */ 306static 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 */ 323static 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 */ 378static 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 415FOUND_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 */ 434static 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 */ 448static 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 */ 476static 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 492static 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 } 548EXIT: 549 AFREE(target); 550 return level; 551 552NOT_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 */ 565static 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 */ 582static 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 */ 609static 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 */ 631static 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 655FOUND: 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 */ 662static 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 679static 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 */ 700static 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 712AvdInfo* 713avdInfo_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 748FAIL: 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 */ 778static 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 803AvdInfo* 804avdInfo_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 833FAIL: 834 avdInfo_free(i); 835 return NULL; 836} 837 838const char* 839avdInfo_getName( AvdInfo* i ) 840{ 841 return i ? i->deviceName : NULL; 842} 843 844const char* 845avdInfo_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 853uint64_t 854avdInfo_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 868int 869avdInfo_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 877char* 878avdInfo_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 913char* 914avdInfo_getRamdiskPath( AvdInfo* i ) 915{ 916 const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ]; 917 return _avdInfo_getContentOrSdkFilePath(i, imageName); 918} 919 920char* avdInfo_getCachePath( AvdInfo* i ) 921{ 922 const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ]; 923 return _avdInfo_getContentFilePath(i, imageName); 924} 925 926char* avdInfo_getDefaultCachePath( AvdInfo* i ) 927{ 928 const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ]; 929 return _getFullFilePath(i->contentPath, imageName); 930} 931 932char* 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 955char* 956avdInfo_getSnapStoragePath( AvdInfo* i ) 957{ 958 const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ]; 959 return _avdInfo_getContentFilePath(i, imageName); 960} 961 962char* 963avdInfo_getSystemImagePath( AvdInfo* i ) 964{ 965 const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ]; 966 return _avdInfo_getContentFilePath(i, imageName); 967} 968 969char* 970avdInfo_getSystemInitImagePath( AvdInfo* i ) 971{ 972 const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ]; 973 return _avdInfo_getContentOrSdkFilePath(i, imageName); 974} 975 976char* 977avdInfo_getDataImagePath( AvdInfo* i ) 978{ 979 const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ]; 980 return _avdInfo_getContentFilePath(i, imageName); 981} 982 983char* 984avdInfo_getDefaultDataImagePath( AvdInfo* i ) 985{ 986 const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ]; 987 return _getFullFilePath(i->contentPath, imageName); 988} 989 990char* 991avdInfo_getDataInitImagePath( AvdInfo* i ) 992{ 993 const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ]; 994 return _avdInfo_getContentOrSdkFilePath(i, imageName); 995} 996 997int 998avdInfo_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 1025const char* 1026avdInfo_getContentPath( AvdInfo* i ) 1027{ 1028 return i->contentPath; 1029} 1030 1031int 1032avdInfo_inAndroidBuild( AvdInfo* i ) 1033{ 1034 return i->inAndroidBuild; 1035} 1036 1037char* 1038avdInfo_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 1047char* 1048avdInfo_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 1065const char* 1066avdInfo_getCoreHwIniPath( AvdInfo* i ) 1067{ 1068 return i->coreHardwareIniPath; 1069} 1070 1071 1072void 1073avdInfo_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 1187char* 1188avdInfo_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 1206int avdInfo_getAdbdCommunicationMode( AvdInfo* i ) 1207{ 1208 return path_getAdbdCommunicationMode(i->androidOut); 1209} 1210