info.c revision fc8ed80ba1362d2ce500003625e1c9c39f765661
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/config/config.h" 14#include "android/utils/path.h" 15#include "android/utils/bufprint.h" 16#include "android/utils/filelock.h" 17#include "android/utils/tempfile.h" 18#include "android/utils/debug.h" 19#include "android/utils/dirscanner.h" 20#include <ctype.h> 21#include <stddef.h> 22#include <string.h> 23#include <stdlib.h> 24#include <stdio.h> 25#include <errno.h> 26 27/* global variables - see android/globals.h */ 28AvdInfoParams android_avdParams[1]; 29AvdInfo* android_avdInfo; 30 31/* for debugging */ 32#define D(...) VERBOSE_PRINT(init,__VA_ARGS__) 33#define DD(...) VERBOSE_PRINT(avd_config,__VA_ARGS__) 34 35/* technical note on how all of this is supposed to work: 36 * 37 * Each AVD corresponds to a "content directory" that is used to 38 * store persistent disk images and configuration files. Most remarkable 39 * are: 40 * 41 * - a "config.ini" file used to hold configuration information for the 42 * AVD 43 * 44 * - mandatory user data image ("userdata-qemu.img") and cache image 45 * ("cache.img") 46 * 47 * - optional mutable system image ("system-qemu.img"), kernel image 48 * ("kernel-qemu") and read-only ramdisk ("ramdisk.img") 49 * 50 * When starting up an AVD, the emulator looks for relevant disk images 51 * in the content directory. If it doesn't find a given image there, it 52 * will try to search in the list of system directories listed in the 53 * 'config.ini' file through one of the following (key,value) pairs: 54 * 55 * images.sysdir.1 = <first search path> 56 * images.sysdir.2 = <second search path> 57 * 58 * The search paths can be absolute, or relative to the root SDK installation 59 * path (which is determined from the emulator program's location, or from the 60 * ANDROID_SDK_ROOT environment variable). 61 * 62 * Individual image disk search patch can be over-riden on the command-line 63 * with one of the usual options. 64 */ 65 66/* this is the subdirectory of $HOME/.android where all 67 * root configuration files (and default content directories) 68 * are located. 69 */ 70#define ANDROID_AVD_DIR "avd" 71 72/* the prefix of config.ini keys that will be used for search directories 73 * of system images. 74 */ 75#define SEARCH_PREFIX "image.sysdir." 76 77/* the maximum number of search path keys we're going to read from the 78 * config.ini file 79 */ 80#define MAX_SEARCH_PATHS 2 81 82/* the config.ini key that will be used to indicate the full relative 83 * path to the skin directory (including the skin name). 84 */ 85#define SKIN_PATH "skin.path" 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/* certain disk image files are mounted read/write by the emulator 97 * to ensure that several emulators referencing the same files 98 * do not corrupt these files, we need to lock them and respond 99 * to collision depending on the image type. 100 * 101 * the enumeration below is used to record information about 102 * each image file path. 103 * 104 * READONLY means that the file will be mounted read-only 105 * and this doesn't need to be locked. must be first in list 106 * 107 * MUSTLOCK means that the file should be locked before 108 * being mounted by the emulator 109 * 110 * TEMPORARY means that the file has been copied to a 111 * temporary image, which can be mounted read/write 112 * but doesn't require locking. 113 */ 114typedef enum { 115 IMAGE_STATE_READONLY, /* unlocked */ 116 IMAGE_STATE_MUSTLOCK, /* must be locked */ 117 IMAGE_STATE_LOCKED, /* locked */ 118 IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */ 119 IMAGE_STATE_TEMPORARY, /* copied to temp file (no lock needed) */ 120} AvdImageState; 121 122struct AvdInfo { 123 /* for the Android build system case */ 124 char inAndroidBuild; 125 char* androidOut; 126 char* androidBuildRoot; 127 128 /* for the normal virtual device case */ 129 char* deviceName; 130 char* sdkRootPath; 131 char sdkRootPathFromEnv; 132 char* searchPaths[ MAX_SEARCH_PATHS ]; 133 int numSearchPaths; 134 char* contentPath; 135 IniFile* rootIni; /* root <foo>.ini file */ 136 IniFile* configIni; /* virtual device's config.ini */ 137 IniFile* hardwareIni; /* skin-specific hardware.ini */ 138 139 /* for both */ 140 char* skinName; /* skin name */ 141 char* skinDirPath; /* skin directory */ 142 143 /* image files */ 144 char* imagePath [ AVD_IMAGE_MAX ]; 145 char imageState[ AVD_IMAGE_MAX ]; 146}; 147 148 149void 150avdInfo_free( AvdInfo* i ) 151{ 152 if (i) { 153 int nn; 154 155 for (nn = 0; nn < AVD_IMAGE_MAX; nn++) 156 AFREE(i->imagePath[nn]); 157 158 AFREE(i->skinName); 159 AFREE(i->skinDirPath); 160 161 for (nn = 0; nn < i->numSearchPaths; nn++) 162 AFREE(i->searchPaths[nn]); 163 164 i->numSearchPaths = 0; 165 166 if (i->configIni) { 167 iniFile_free(i->configIni); 168 i->configIni = NULL; 169 } 170 171 if (i->hardwareIni) { 172 iniFile_free(i->hardwareIni); 173 i->hardwareIni = NULL; 174 } 175 176 if (i->rootIni) { 177 iniFile_free(i->rootIni); 178 i->rootIni = NULL; 179 } 180 181 AFREE(i->contentPath); 182 AFREE(i->sdkRootPath); 183 184 if (i->inAndroidBuild) { 185 AFREE(i->androidOut); 186 AFREE(i->androidBuildRoot); 187 } 188 189 AFREE(i->deviceName); 190 AFREE(i); 191 } 192} 193 194/* list of default file names for each supported image file type */ 195static const char* const _imageFileNames[ AVD_IMAGE_MAX ] = { 196#define _AVD_IMG(x,y,z) y, 197 AVD_IMAGE_LIST 198#undef _AVD_IMG 199}; 200 201/* list of short text description for each supported image file type */ 202static const char* const _imageFileText[ AVD_IMAGE_MAX ] = { 203#define _AVD_IMG(x,y,z) z, 204 AVD_IMAGE_LIST 205#undef _AVD_IMG 206}; 207 208/*************************************************************** 209 *************************************************************** 210 ***** 211 ***** NORMAL VIRTUAL DEVICE SUPPORT 212 ***** 213 *****/ 214 215/* compute path to the root SDK directory 216 * assume we are in $SDKROOT/tools/emulator[.exe] 217 */ 218static int 219_getSdkRoot( AvdInfo* i ) 220{ 221 const char* env; 222 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 223 224#define SDK_ROOT_ENV "ANDROID_SDK_ROOT" 225 226 env = getenv(SDK_ROOT_ENV); 227 if (env != NULL && env[0] != 0) { 228 if (path_exists(env)) { 229 D("found " SDK_ROOT_ENV ": %s", env); 230 i->sdkRootPath = ASTRDUP(env); 231 i->sdkRootPathFromEnv = 1; 232 return 0; 233 } 234 D(SDK_ROOT_ENV " points to unknown directory: %s", env); 235 } 236 237 (void) bufprint_app_dir(temp, end); 238 239 i->sdkRootPath = path_parent(temp, 1); 240 if (i->sdkRootPath == NULL) { 241 derror("can't find root of SDK directory"); 242 return -1; 243 } 244 D("found SDK root at %s", i->sdkRootPath); 245 return 0; 246} 247 248static void 249_getSearchPaths( AvdInfo* i ) 250{ 251 char temp[PATH_MAX], *p = temp, *end= p+sizeof temp; 252 int nn, count = 0; 253 254 255 256 for (nn = 0; nn < MAX_SEARCH_PATHS; nn++) { 257 char* path; 258 259 p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 ); 260 if (p >= end) 261 continue; 262 263 path = iniFile_getString( i->configIni, temp ); 264 if (path != NULL) { 265 DD(" found image search path: %s", path); 266 if (!path_is_absolute(path)) { 267 p = bufprint(temp, end, "%s/%s", i->sdkRootPath, path); 268 AFREE(path); 269 path = ASTRDUP(temp); 270 } 271 i->searchPaths[count++] = path; 272 } 273 } 274 275 i->numSearchPaths = count; 276 if (count == 0) { 277 derror("no search paths found in this AVD's configuration.\n" 278 "Weird, the AVD's config.ini file is malformed. Try re-creating it.\n"); 279 exit(2); 280 } 281 else 282 DD("found a total of %d search paths for this AVD", count); 283} 284 285static int 286_checkAvdName( const char* name ) 287{ 288 int len = strlen(name); 289 int len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 290 "abcdefghijklmnopqrstuvwxyz" 291 "0123456789_.-"); 292 return (len == len2); 293} 294 295/* parse the root config .ini file. it is located in 296 * ~/.android/avd/<name>.ini or Windows equivalent 297 */ 298static int 299_getRootIni( AvdInfo* i ) 300{ 301 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 302 303 p = bufprint_config_path(temp, end); 304 p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", i->deviceName); 305 if (p >= end) { 306 derror("device name too long"); 307 return -1; 308 } 309 310 i->rootIni = iniFile_newFromFile(temp); 311 if (i->rootIni == NULL) { 312 derror("unknown virtual device name: '%s'", i->deviceName); 313 return -1; 314 } 315 D("root virtual device file at %s", temp); 316 return 0; 317} 318 319/* the .ini variable name that points to the content directory 320 * in a root AVD ini file. This is required */ 321# define ROOT_PATH_KEY "path" 322 323static int 324_getContentPath( AvdInfo* i ) 325{ 326 i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY); 327 328 if (i->contentPath == NULL) { 329 derror("bad config: %s", 330 "virtual device file lacks a "ROOT_PATH_KEY" entry"); 331 return -1; 332 } 333 D("virtual device content at %s", i->contentPath); 334 return 0; 335} 336 337/* find and parse the config.ini file from the content directory */ 338static int 339_getConfigIni(AvdInfo* i) 340{ 341 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 342 343 p = bufprint(p, end, "%s/config.ini", i->contentPath); 344 if (p >= end) { 345 derror("can't access virtual device content directory"); 346 return -1; 347 } 348 349#if 1 /* XXX: TODO: remove this in the future */ 350 /* for now, allow a non-existing config.ini */ 351 if (!path_exists(temp)) { 352 D("virtual device has no config file - no problem"); 353 return 0; 354 } 355#endif 356 357 i->configIni = iniFile_newFromFile(temp); 358 if (i->configIni == NULL) { 359 derror("bad config: %s", 360 "virtual device directory lacks config.ini"); 361 return -1; 362 } 363 D("virtual device config file: %s", temp); 364 return 0; 365} 366 367/*************************************************************** 368 *************************************************************** 369 ***** 370 ***** KERNEL/DISK IMAGE LOADER 371 ***** 372 *****/ 373 374/* a structure used to handle the loading of 375 * kernel/disk images. 376 */ 377typedef struct { 378 AvdInfo* info; 379 AvdInfoParams* params; 380 AvdImageType id; 381 const char* imageFile; 382 const char* imageText; 383 char** pPath; 384 char* pState; 385 char temp[PATH_MAX]; 386} ImageLoader; 387 388static void 389imageLoader_init( ImageLoader* l, AvdInfo* info, AvdInfoParams* params ) 390{ 391 memset(l, 0, sizeof(*l)); 392 l->info = info; 393 l->params = params; 394} 395 396/* set the type of the image to load */ 397static void 398imageLoader_set( ImageLoader* l, AvdImageType id ) 399{ 400 l->id = id; 401 l->imageFile = _imageFileNames[id]; 402 l->imageText = _imageFileText[id]; 403 l->pPath = &l->info->imagePath[id]; 404 l->pState = &l->info->imageState[id]; 405 406 l->pState[0] = IMAGE_STATE_READONLY; 407} 408 409/* change the image path */ 410static char* 411imageLoader_setPath( ImageLoader* l, const char* path ) 412{ 413 path = path ? ASTRDUP(path) : NULL; 414 415 AFREE(l->pPath[0]); 416 l->pPath[0] = (char*) path; 417 418 return (char*) path; 419} 420 421static char* 422imageLoader_extractPath( ImageLoader* l ) 423{ 424 char* result = l->pPath[0]; 425 l->pPath[0] = NULL; 426 return result; 427} 428 429/* flags used when loading images */ 430enum { 431 IMAGE_REQUIRED = (1<<0), /* image is required */ 432 IMAGE_SEARCH_SDK = (1<<1), /* search image in SDK */ 433 IMAGE_EMPTY_IF_MISSING = (1<<2), /* create empty file if missing */ 434 IMAGE_DONT_LOCK = (1<<4), /* don't try to lock image */ 435 IMAGE_IGNORE_IF_LOCKED = (1<<5), /* ignore file if it's locked */ 436}; 437 438#define IMAGE_OPTIONAL 0 439 440/* find an image from the SDK search directories. 441 * returns the full path or NULL if the file could not be found. 442 * 443 * note: this stores the result in the image's path as well 444 */ 445static char* 446imageLoader_lookupSdk( ImageLoader* l ) 447{ 448 AvdInfo* i = l->info; 449 const char* image = l->imageFile; 450 char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp); 451 452 do { 453 /* try the search paths */ 454 int nn; 455 456 for (nn = 0; nn < i->numSearchPaths; nn++) { 457 const char* searchDir = i->searchPaths[nn]; 458 459 p = bufprint(temp, end, "%s/%s", searchDir, image); 460 if (p < end && path_exists(temp)) { 461 DD("found %s in search dir: %s", image, searchDir); 462 goto FOUND; 463 } 464 DD(" no %s in search dir: %s", image, searchDir); 465 } 466 467 return NULL; 468 469 } while (0); 470 471FOUND: 472 l->pState[0] = IMAGE_STATE_READONLY; 473 474 return imageLoader_setPath(l, temp); 475} 476 477/* search for a file in the content directory. 478 * returns NULL if the file cannot be found. 479 * 480 * note that this formats l->temp with the file's path 481 * allowing you to retrieve it if the function returns NULL 482 */ 483static char* 484imageLoader_lookupContent( ImageLoader* l ) 485{ 486 AvdInfo* i = l->info; 487 char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp); 488 489 p = bufprint(temp, end, "%s/%s", i->contentPath, l->imageFile); 490 if (p >= end) { 491 derror("content directory path too long"); 492 exit(2); 493 } 494 if (!path_exists(temp)) { 495 DD(" no %s in content directory", l->imageFile); 496 return NULL; 497 } 498 DD("found %s in content directory", l->imageFile); 499 500 /* assume content image files must be locked */ 501 l->pState[0] = IMAGE_STATE_MUSTLOCK; 502 503 return imageLoader_setPath(l, temp); 504} 505 506/* lock a file image depending on its state and user flags 507 * note that this clears l->pPath[0] if the lock could not 508 * be acquired and that IMAGE_IGNORE_IF_LOCKED is used. 509 */ 510static void 511imageLoader_lock( ImageLoader* l, unsigned flags ) 512{ 513 const char* path = l->pPath[0]; 514 515 if (flags & IMAGE_DONT_LOCK) 516 return; 517 518 if (l->pState[0] != IMAGE_STATE_MUSTLOCK) 519 return; 520 521 D(" locking %s image at %s", l->imageText, path); 522 523 if (filelock_create(path) != NULL) { 524 /* succesful lock */ 525 l->pState[0] = IMAGE_STATE_LOCKED; 526 return; 527 } 528 529 if (flags & IMAGE_IGNORE_IF_LOCKED) { 530 dwarning("ignoring locked %s image at %s", l->imageText, path); 531 imageLoader_setPath(l, NULL); 532 return; 533 } 534 535 derror("the %s image is used by another emulator. aborting", 536 l->imageText); 537 exit(2); 538} 539 540/* make a file image empty, this may require locking */ 541static void 542imageLoader_empty( ImageLoader* l, unsigned flags ) 543{ 544 const char* path; 545 546 imageLoader_lock(l, flags); 547 548 path = l->pPath[0]; 549 if (path == NULL) /* failed to lock, caller will handle it */ 550 return; 551 552 if (path_empty_file(path) < 0) { 553 derror("could not create %s image at %s: %s", 554 l->imageText, path, strerror(errno)); 555 exit(2); 556 } 557 l->pState[0] = IMAGE_STATE_LOCKED_EMPTY; 558} 559 560 561/* copy image file from a given source 562 * assumes locking is needed. 563 */ 564static void 565imageLoader_copyFrom( ImageLoader* l, const char* srcPath ) 566{ 567 const char* dstPath = NULL; 568 569 /* find destination file */ 570 if (l->params) { 571 dstPath = l->params->forcePaths[l->id]; 572 } 573 if (!dstPath) { 574 imageLoader_lookupContent(l); 575 dstPath = l->temp; 576 } 577 578 /* lock destination */ 579 imageLoader_setPath(l, dstPath); 580 l->pState[0] = IMAGE_STATE_MUSTLOCK; 581 imageLoader_lock(l, 0); 582 583 /* make the copy */ 584 if (path_copy_file(dstPath, srcPath) < 0) { 585 derror("can't initialize %s image from SDK: %s: %s", 586 l->imageText, dstPath, strerror(errno)); 587 exit(2); 588 } 589} 590 591/* this will load and eventually lock and image file, depending 592 * on the flags being used. on exit, this function udpates 593 * l->pState[0] and l->pPath[0] 594 * 595 * returns the path to the file. Note that it returns NULL 596 * only if the file was optional and could not be found. 597 * 598 * if the file is required and missing, the function aborts 599 * the program. 600 */ 601static char* 602imageLoader_load( ImageLoader* l, 603 unsigned flags ) 604{ 605 const char* path = NULL; 606 607 /* set image state */ 608 l->pState[0] = (flags & IMAGE_DONT_LOCK) == 0 609 ? IMAGE_STATE_MUSTLOCK 610 : IMAGE_STATE_READONLY; 611 612 /* check user-provided path */ 613 path = l->params->forcePaths[l->id]; 614 if (path != NULL) { 615 imageLoader_setPath(l, path); 616 if (path_exists(path)) { 617 DD("found user-provided %s image: %s", l->imageText, l->imageFile); 618 goto EXIT; 619 } 620 D("user-provided %s image does not exist: %s", 621 l->imageText, path); 622 623 /* if the file is required, abort */ 624 if (flags & IMAGE_REQUIRED) { 625 derror("user-provided %s image at %s doesn't exist", 626 l->imageText, path); 627 exit(2); 628 } 629 } 630 else { 631 const char* contentFile; 632 633 /* second, look in the content directory */ 634 path = imageLoader_lookupContent(l); 635 if (path) goto EXIT; 636 637 contentFile = ASTRDUP(l->temp); 638 639 /* it's not there */ 640 if (flags & IMAGE_SEARCH_SDK) { 641 /* third, look in the SDK directory */ 642 path = imageLoader_lookupSdk(l); 643 if (path) { 644 AFREE((char*)contentFile); 645 goto EXIT; 646 } 647 } 648 DD("found no %s image (%s)", l->imageText, l->imageFile); 649 650 /* if the file is required, abort */ 651 if (flags & IMAGE_REQUIRED) { 652 AvdInfo* i = l->info; 653 654 derror("could not find required %s image (%s).", 655 l->imageText, l->imageFile); 656 657 if (i->inAndroidBuild) { 658 dprint( "Did you build everything ?" ); 659 } else if (!i->sdkRootPathFromEnv) { 660 dprint( "Maybe defining %s to point to a valid SDK " 661 "installation path might help ?", SDK_ROOT_ENV ); 662 } else { 663 dprint( "Your %s is probably wrong: %s", SDK_ROOT_ENV, 664 i->sdkRootPath ); 665 } 666 exit(2); 667 } 668 669 path = imageLoader_setPath(l, contentFile); 670 AFREE((char*)contentFile); 671 } 672 673 /* otherwise, do we need to create it ? */ 674 if (flags & IMAGE_EMPTY_IF_MISSING) { 675 imageLoader_empty(l, flags); 676 return l->pPath[0]; 677 } 678 return NULL; 679 680EXIT: 681 imageLoader_lock(l, flags); 682 return l->pPath[0]; 683} 684 685/* Attempts to load an AVD image, but does not kill the process if loading 686 * fails. 687 */ 688static void 689imageLoader_loadOptional( ImageLoader *l, AvdImageType img_type, 690 const char *forcedPath ) 691{ 692 imageLoader_set (l, img_type); 693 imageLoader_load(l, IMAGE_OPTIONAL | 694 IMAGE_IGNORE_IF_LOCKED); 695 696 /* if the file was not found, ignore it */ 697 if (l->pPath[0] && !path_exists(l->pPath[0])) 698 { 699 D("ignoring non-existing %s at %s: %s", 700 l->imageText, l->pPath[0], strerror(errno)); 701 702 /* if the user provided the path by hand, warn him. */ 703 if (forcedPath != NULL) 704 dwarning("ignoring non-existing %s image", l->imageText); 705 706 imageLoader_setPath(l, NULL); 707 } 708} 709 710/* find the correct path of all image files we're going to need 711 * and lock the files that need it. 712 */ 713static int 714_getImagePaths(AvdInfo* i, AvdInfoParams* params ) 715{ 716 int wipeData = (params->flags & AVDINFO_WIPE_DATA) != 0; 717 int wipeCache = (params->flags & AVDINFO_WIPE_CACHE) != 0; 718 int noCache = (params->flags & AVDINFO_NO_CACHE) != 0; 719 int noSdCard = (params->flags & AVDINFO_NO_SDCARD) != 0; 720#if CONFIG_ANDROID_SNAPSHOTS 721 int noSnapshots = (params->flags & AVDINFO_NO_SNAPSHOTS) != 0; 722#endif 723 724 ImageLoader l[1]; 725 726 imageLoader_init(l, i, params); 727 728 /* pick up the kernel and ramdisk image files - these don't 729 * need a specific handling. 730 */ 731 imageLoader_set ( l, AVD_IMAGE_KERNEL ); 732 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK ); 733 734 imageLoader_set ( l, AVD_IMAGE_RAMDISK ); 735 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK ); 736 737 /* the system image 738 * 739 * if there is one in the content directory just lock 740 * and use it. 741 */ 742 imageLoader_set ( l, AVD_IMAGE_INITSYSTEM ); 743 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK ); 744 745 /* the data partition - this one is special because if it 746 * is missing, we need to copy the initial image file into it. 747 * 748 * first, try to see if it is in the content directory 749 * (or the user-provided path) 750 */ 751 imageLoader_set( l, AVD_IMAGE_USERDATA ); 752 if ( !imageLoader_load( l, IMAGE_OPTIONAL | 753 IMAGE_DONT_LOCK ) ) 754 { 755 /* it's not, we're going to initialize it. simply 756 * forcing a data wipe should be enough */ 757 D("initializing new data partition image: %s", l->pPath[0]); 758 wipeData = 1; 759 } 760 761 if (wipeData) { 762 /* find SDK source file */ 763 const char* srcPath; 764 765 imageLoader_set( l, AVD_IMAGE_INITDATA ); 766 if (imageLoader_lookupSdk(l) == NULL) { 767 derror("can't locate initial %s image in SDK", 768 l->imageText); 769 exit(2); 770 } 771 srcPath = imageLoader_extractPath(l); 772 773 imageLoader_set( l, AVD_IMAGE_USERDATA ); 774 imageLoader_copyFrom( l, srcPath ); 775 AFREE((char*) srcPath); 776 } 777 else 778 { 779 /* lock the data partition image */ 780 l->pState[0] = IMAGE_STATE_MUSTLOCK; 781 imageLoader_lock( l, 0 ); 782 } 783 784 /* the cache partition: unless the user doesn't want one, 785 * we're going to create it in the content directory 786 */ 787 if (!noCache) { 788 imageLoader_set (l, AVD_IMAGE_CACHE); 789 imageLoader_load(l, IMAGE_OPTIONAL | 790 IMAGE_EMPTY_IF_MISSING ); 791 792 if (wipeCache) { 793 if (path_empty_file(l->pPath[0]) < 0) { 794 derror("cannot wipe %s image at %s: %s", 795 l->imageText, l->pPath[0], 796 strerror(errno)); 797 exit(2); 798 } 799 } 800 } 801 802 /* the SD Card image. unless the user doesn't want to, we're 803 * going to mount it if available. Note that if the image is 804 * already used, we must ignore it. 805 */ 806 if (!noSdCard) { 807 imageLoader_loadOptional(l, AVD_IMAGE_SDCARD, 808 params->forcePaths[AVD_IMAGE_SDCARD]); 809 } 810 811#if CONFIG_ANDROID_SNAPSHOTS 812 /* the state snapshot image. Mounting behaviour identical to 813 * SD card. 814 */ 815 if (!noSnapshots) { 816 imageLoader_loadOptional(l, AVD_IMAGE_SNAPSHOTS, 817 params->forcePaths[AVD_IMAGE_SNAPSHOTS]); 818 } 819#endif 820 821 return 0; 822} 823 824/* check that a given directory contains a valid skin. 825 * returns 1 on success, 0 on failure. 826 */ 827static int 828_checkSkinPath( const char* skinPath ) 829{ 830 char temp[MAX_PATH], *p=temp, *end=p+sizeof(temp); 831 832 /* for now, if it has a 'layout' file, it is a valid skin path */ 833 p = bufprint(temp, end, "%s/layout", skinPath); 834 if (p >= end || !path_exists(temp)) 835 return 0; 836 837 return 1; 838} 839 840/* check that there is a skin named 'skinName' listed from 'skinDirRoot' 841 * this returns 1 on success, 0 on failure 842 * on success, the 'temp' buffer will get the path containing the real 843 * skin directory (after alias expansion), including the skin name. 844 */ 845static int 846_checkSkinDir( char* temp, 847 char* end, 848 const char* skinDirRoot, 849 const char* skinName ) 850{ 851 DirScanner* scanner; 852 char *p; 853 int result; 854 855 p = bufprint(temp, end, "%s/skins/%s", 856 skinDirRoot, skinName); 857 858 if (p >= end || !path_exists(temp)) { 859 DD(" ignore bad skin directory %s", temp); 860 return 0; 861 } 862 863 /* first, is this a normal skin directory ? */ 864 if (_checkSkinPath(temp)) { 865 /* yes */ 866 DD(" found skin directory: %s", temp); 867 return 1; 868 } 869 870 /* second, is it an alias to another skin ? */ 871 *p = 0; 872 result = 0; 873 scanner = dirScanner_new(temp); 874 if (scanner != NULL) { 875 for (;;) { 876 const char* file = dirScanner_next(scanner); 877 878 if (file == NULL) 879 break; 880 881 if (strncmp(file, "alias-", 6) || file[6] == 0) 882 continue; 883 884 p = bufprint(temp, end, "%s/skins/%s", 885 skinDirRoot, file+6); 886 887 if (p < end && _checkSkinPath(temp)) { 888 /* yes, it's an alias */ 889 DD(" skin alias '%s' points to skin directory: %s", 890 file+6, temp); 891 result = 1; 892 break; 893 } 894 } 895 dirScanner_free(scanner); 896 } 897 return result; 898} 899 900/* try to see if the skin name leads to a magic skin or skin path directly 901 * returns 1 on success, 0 on error. 902 * on success, this sets up 'skinDirPath' and 'skinName' in the AvdInfo. 903 */ 904static int 905_getSkinPathFromName( AvdInfo* i, const char* skinName ) 906{ 907 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 908 909 /* if the skin name has the format 'NNNNxNNN' where 910 * NNN is a decimal value, then this is a 'magic' skin 911 * name that doesn't require a skin directory 912 */ 913 if (isdigit(skinName[0])) { 914 int width, height; 915 if (sscanf(skinName, "%dx%d", &width, &height) == 2) { 916 D("'magic' skin format detected: %s", skinName); 917 i->skinName = ASTRDUP(skinName); 918 i->skinDirPath = NULL; 919 return 1; 920 } 921 } 922 923 /* is the skin name a direct path to the skin directory ? */ 924 if (_checkSkinPath(skinName)) { 925 goto FOUND_IT; 926 } 927 928 /* is the skin name a relative path from the SDK root ? */ 929 p = bufprint(temp, end, "%s/%s", i->sdkRootPath, skinName); 930 if (p < end && _checkSkinPath(temp)) { 931 skinName = temp; 932 goto FOUND_IT; 933 } 934 935 /* nope */ 936 return 0; 937 938FOUND_IT: 939 if (path_split(skinName, &i->skinDirPath, &i->skinName) < 0) { 940 derror("malformed skin name: %s", skinName); 941 exit(2); 942 } 943 D("found skin '%s' in directory: %s", i->skinName, i->skinDirPath); 944 return 1; 945} 946 947/* return 0 on success, -1 on error */ 948static int 949_getSkin( AvdInfo* i, AvdInfoParams* params ) 950{ 951 char* skinName; 952 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 953 char explicitSkin = 1; 954 955 /* this function is used to compute the 'skinName' and 'skinDirPath' 956 * fields of the AvdInfo. 957 */ 958 959 /* processing here is a bit tricky, so here's how it happens 960 * 961 * - command-line option '-skin <name>' can be used to specify the 962 * name of a skin, to override the AVD settings. 963 * 964 * - skins are searched from <dir>/../skins for each <dir> in the 965 * images search list, unless a '-skindir <path>' option has been 966 * provided on the command-line 967 * 968 * - otherwise, the config.ini can also contain a SKIN_PATH key that 969 * shall give the full path to the skin directory, either relative 970 * to the SDK root, or an absolute path. 971 * 972 * - skin names like '320x480' corresponds to "magic skins" that 973 * simply display a framebuffer, without any ornaments of the 974 * corresponding size. They do not correspond to any real skin 975 * directory / files and are handled later. But they must be 976 * recognized here and report a NULL skindir. 977 */ 978 if (params->skinName) { 979 skinName = ASTRDUP(params->skinName); 980 } else { 981 skinName = iniFile_getString( i->configIni, SKIN_PATH ); 982 explicitSkin = 0; 983 } 984 985 /* first, check that the skin name is not magic or a direct 986 * directory path 987 */ 988 if (skinName != NULL && _getSkinPathFromName(i, skinName)) { 989 AFREE(skinName); 990 return 0; 991 } 992 993 /* if not, the default skinName is "HVGA" */ 994 if (skinName == NULL) { 995 skinName = ASTRDUP(SKIN_DEFAULT); 996 explicitSkin = 0; 997 } 998 999 i->skinName = skinName; 1000 1001 /* now try to find the skin directory for that name - 1002 * first try the content directory */ 1003 do { 1004 /* if there is a single 'skin' directory in 1005 * the content directory, assume that's what the 1006 * user wants, unless an explicit name was given 1007 */ 1008 if (!explicitSkin) { 1009 p = bufprint(temp, end, "%s/skin", i->contentPath); 1010 if (p < end && _checkSkinPath(temp)) { 1011 D("using skin content from %s", temp); 1012 AFREE(i->skinName); 1013 i->skinName = ASTRDUP("skin"); 1014 i->skinDirPath = ASTRDUP(i->contentPath); 1015 return 0; 1016 } 1017 } 1018 1019 /* look in content directory */ 1020 if (_checkSkinDir(temp, end, i->contentPath, skinName)) 1021 break; 1022 1023 /* look in the search paths. For each <dir> in the list, 1024 * look the skins in <dir>/.. */ 1025 { 1026 int nn; 1027 for (nn = 0; nn < i->numSearchPaths; nn++) { 1028 char* parentDir = path_parent(i->searchPaths[nn], 1); 1029 int ret; 1030 if (parentDir == NULL) 1031 continue; 1032 ret=_checkSkinDir(temp, end, parentDir, skinName); 1033 AFREE(parentDir); 1034 if (ret) 1035 break; 1036 } 1037 if (nn < i->numSearchPaths) 1038 break; 1039 } 1040 1041 /* didn't find it */ 1042 if (explicitSkin) { 1043 derror("could not find directory for skin '%s'," 1044 " please use a different name", skinName); 1045 exit(2); 1046 } else { 1047 dwarning("no skin directory matched '%s', so reverted to default", 1048 skinName); 1049 AFREE(i->skinName); 1050 params->skinName = SKIN_DEFAULT; 1051 return _getSkin(i, params); 1052 } 1053 1054 return -1; 1055 1056 } while (0); 1057 1058 /* separate skin name from parent directory. the skin name 1059 * returned in 'temp' might be different from the original 1060 * one due to alias expansion so strip it. 1061 */ 1062 AFREE(i->skinName); 1063 1064 if (path_split(temp, &i->skinDirPath, &i->skinName) < 0) { 1065 derror("weird skin path: %s", temp); 1066 return -1; 1067 } 1068 DD("found skin '%s' in directory: %s", i->skinName, i->skinDirPath); 1069 return 0; 1070} 1071 1072/* If the user didn't explicitely provide an SD Card path, 1073 * check the SDCARD_PATH key in config.ini and use that if 1074 * available. 1075 */ 1076static void 1077_getSDCardPath( AvdInfo* i, AvdInfoParams* params ) 1078{ 1079 const char* path; 1080 1081 if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL) 1082 return; 1083 1084 path = iniFile_getString(i->configIni, SDCARD_PATH); 1085 if (path == NULL) 1086 return; 1087 1088 params->forcePaths[AVD_IMAGE_SDCARD] = path; 1089} 1090 1091AvdInfo* 1092avdInfo_new( const char* name, AvdInfoParams* params ) 1093{ 1094 AvdInfo* i; 1095 1096 if (name == NULL) 1097 return NULL; 1098 1099 if (!_checkAvdName(name)) { 1100 derror("virtual device name contains invalid characters"); 1101 exit(1); 1102 } 1103 1104 ANEW0(i); 1105 i->deviceName = ASTRDUP(name); 1106 1107 if ( _getSdkRoot(i) < 0 || 1108 _getRootIni(i) < 0 || 1109 _getContentPath(i) < 0 || 1110 _getConfigIni(i) < 0 ) 1111 goto FAIL; 1112 1113 /* look for image search paths. handle post 1.1/pre cupcake 1114 * obsolete SDKs. 1115 */ 1116 _getSearchPaths(i); 1117 _getSDCardPath(i, params); 1118 1119 /* don't need this anymore */ 1120 iniFile_free(i->rootIni); 1121 i->rootIni = NULL; 1122 1123 if ( _getImagePaths(i, params) < 0 || 1124 _getSkin (i, params) < 0 ) 1125 goto FAIL; 1126 1127 return i; 1128 1129FAIL: 1130 avdInfo_free(i); 1131 return NULL; 1132} 1133 1134/*************************************************************** 1135 *************************************************************** 1136 ***** 1137 ***** ANDROID BUILD SUPPORT 1138 ***** 1139 ***** The code below corresponds to the case where we're 1140 ***** starting the emulator inside the Android build 1141 ***** system. The main differences are that: 1142 ***** 1143 ***** - the $ANDROID_PRODUCT_OUT directory is used as the 1144 ***** content file. 1145 ***** 1146 ***** - built images must not be modified by the emulator, 1147 ***** so system.img must be copied to a temporary file 1148 ***** and userdata.img must be copied to userdata-qemu.img 1149 ***** if the latter doesn't exist. 1150 ***** 1151 ***** - the kernel and default skin directory are taken from 1152 ***** prebuilt 1153 ***** 1154 ***** - there is no root .ini file, or any config.ini in 1155 ***** the content directory, no SDK images search path. 1156 *****/ 1157 1158/* used to fake a config.ini located in the content directory */ 1159static int 1160_getBuildConfigIni( AvdInfo* i ) 1161{ 1162 /* a blank file is ok at the moment */ 1163 i->configIni = iniFile_newFromMemory( "", 0 ); 1164 return 0; 1165} 1166 1167static int 1168_getBuildImagePaths( AvdInfo* i, AvdInfoParams* params ) 1169{ 1170 int wipeData = (params->flags & AVDINFO_WIPE_DATA) != 0; 1171 int noCache = (params->flags & AVDINFO_NO_CACHE) != 0; 1172 int noSdCard = (params->flags & AVDINFO_NO_SDCARD) != 0; 1173#if CONFIG_ANDROID_SNAPSHOTS 1174 int noSnapshots = (params->flags & AVDINFO_NO_SNAPSHOTS) != 0; 1175#endif 1176 1177 char temp[PATH_MAX], *p=temp, *end=p+sizeof temp; 1178 char* srcData; 1179 ImageLoader l[1]; 1180 1181 imageLoader_init(l, i, params); 1182 1183 /** load the kernel image 1184 **/ 1185 1186 /* if it is not in the out directory, get it from prebuilt 1187 */ 1188 imageLoader_set ( l, AVD_IMAGE_KERNEL ); 1189 1190 if ( !imageLoader_load( l, IMAGE_OPTIONAL | 1191 IMAGE_DONT_LOCK ) ) 1192 { 1193#ifdef TARGET_ARM 1194#define PREBUILT_KERNEL_PATH "prebuilt/android-arm/kernel/kernel-qemu" 1195#endif 1196#ifdef TARGET_I386 1197#define PREBUILT_KERNEL_PATH "prebuilt/android-x86/kernel/kernel-qemu" 1198#endif 1199 p = bufprint(temp, end, "%s/%s", i->androidBuildRoot, 1200 PREBUILT_KERNEL_PATH); 1201 if (p >= end || !path_exists(temp)) { 1202 derror("bad workspace: cannot find prebuilt kernel in: %s", temp); 1203 exit(1); 1204 } 1205 imageLoader_setPath(l, temp); 1206 } 1207 1208 /** load the data partition. note that we use userdata-qemu.img 1209 ** since we don't want to modify userdata.img at all 1210 **/ 1211 imageLoader_set ( l, AVD_IMAGE_USERDATA ); 1212 imageLoader_load( l, IMAGE_OPTIONAL | IMAGE_DONT_LOCK ); 1213 1214 /* get the path of the source file, and check that it actually exists 1215 * if the user didn't provide an explicit data file 1216 */ 1217 srcData = imageLoader_extractPath(l); 1218 if (srcData == NULL && params->forcePaths[AVD_IMAGE_USERDATA] == NULL) { 1219 derror("There is no %s image in your build directory. Please make a full build", 1220 l->imageText, l->imageFile); 1221 exit(2); 1222 } 1223 1224 /* get the path of the target file */ 1225 l->imageFile = "userdata-qemu.img"; 1226 imageLoader_load( l, IMAGE_OPTIONAL | 1227 IMAGE_EMPTY_IF_MISSING | 1228 IMAGE_IGNORE_IF_LOCKED ); 1229 1230 /* force a data wipe if we just created the image */ 1231 if (l->pState[0] == IMAGE_STATE_LOCKED_EMPTY) 1232 wipeData = 1; 1233 1234 /* if the image was already locked, create a temp file 1235 * then force a data wipe. 1236 */ 1237 if (l->pPath[0] == NULL) { 1238 TempFile* temp = tempfile_create(); 1239 imageLoader_setPath(l, tempfile_path(temp)); 1240 dwarning( "Another emulator is running. user data changes will *NOT* be saved"); 1241 wipeData = 1; 1242 } 1243 1244 /* in the case of a data wipe, copy userdata.img into 1245 * the destination */ 1246 if (wipeData) { 1247 if (srcData == NULL || !path_exists(srcData)) { 1248 derror("There is no %s image in your build directory. Please make a full build", 1249 l->imageText, _imageFileNames[l->id]); 1250 exit(2); 1251 } 1252 if (path_copy_file( l->pPath[0], srcData ) < 0) { 1253 derror("could not initialize %s image from %s: %s", 1254 l->imageText, temp, strerror(errno)); 1255 exit(2); 1256 } 1257 } 1258 1259 AFREE(srcData); 1260 1261 /** load the ramdisk image 1262 **/ 1263 imageLoader_set ( l, AVD_IMAGE_RAMDISK ); 1264 imageLoader_load( l, IMAGE_REQUIRED | 1265 IMAGE_DONT_LOCK ); 1266 1267 /** load the system image. read-only. the caller must 1268 ** take care of checking the state 1269 **/ 1270 imageLoader_set ( l, AVD_IMAGE_INITSYSTEM ); 1271 imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK ); 1272 1273 /* force the system image to read-only status */ 1274 l->pState[0] = IMAGE_STATE_READONLY; 1275 1276 /** cache partition handling 1277 **/ 1278 if (!noCache) { 1279 imageLoader_set (l, AVD_IMAGE_CACHE); 1280 1281 /* if the user provided one cache image, lock & use it */ 1282 if ( params->forcePaths[l->id] != NULL ) { 1283 imageLoader_load(l, IMAGE_REQUIRED | 1284 IMAGE_IGNORE_IF_LOCKED); 1285 } 1286 } 1287 1288 /** SD Card image 1289 **/ 1290 if (!noSdCard) { 1291 imageLoader_set (l, AVD_IMAGE_SDCARD); 1292 imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED); 1293 } 1294 1295#if CONFIG_ANDROID_SNAPSHOTS 1296 /** State snapshots image 1297 **/ 1298 if (!noSnapshots) { 1299 imageLoader_set (l, AVD_IMAGE_SNAPSHOTS); 1300 imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED); 1301 } 1302#endif 1303 1304 return 0; 1305} 1306 1307static int 1308_getBuildSkin( AvdInfo* i, AvdInfoParams* params ) 1309{ 1310 /* the (current) default skin name for our build system */ 1311 const char* skinName = params->skinName; 1312 const char* skinDir = params->skinRootPath; 1313 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 1314 char* q; 1315 1316 if (!skinName) { 1317 /* the (current) default skin name for the build system */ 1318 skinName = SKIN_DEFAULT; 1319 D("selecting default skin name '%s'", skinName); 1320 } 1321 1322 if (!skinDir) { 1323 1324#define PREBUILT_SKINS_DIR "development/tools/emulator/skins" 1325#define PRODUCT_SKIN_DIR "skin" 1326 1327 do { 1328 /* look for the product skin in $ANDROID_PRODUCT_OUT/skin if no skin name is defined */ 1329 if (!params->skinName) { 1330 /* look for <product_out>/skin first */ 1331 p = bufprint( temp, end, "%s/skin", 1332 i->androidOut ); 1333 if (path_exists(temp)) { 1334 p = bufprint( temp, end, "%s", 1335 i->androidOut ); 1336 skinName = PRODUCT_SKIN_DIR; 1337 D("selecting default product skin at '%s/%s'", temp, skinName); 1338 break; 1339 } 1340 } 1341 1342 /* next try in <sysdir>/../skins */ 1343 p = bufprint( temp, end, "%s/../skins", 1344 i->androidBuildRoot ); 1345 if (path_exists(temp)) 1346 break; 1347 1348 /* the (current) default skin directory */ 1349 p = bufprint( temp, end, "%s/%s", 1350 i->androidBuildRoot, PREBUILT_SKINS_DIR ); 1351 } while (0); 1352 1353 } else { 1354 p = bufprint( temp, end, "%s", skinDir ); 1355 } 1356 1357 i->skinName = ASTRDUP(skinName); 1358 1359 q = bufprint(p, end, "/%s/layout", skinName); 1360 if (q >= end || !path_exists(temp)) { 1361 DD("skin content directory does not exist: %s", temp); 1362 if (skinDir) 1363 dwarning("could not find valid skin '%s' in %s:\n", 1364 skinName, temp); 1365 return -1; 1366 } 1367 *p = 0; 1368 DD("found skin path: %s", temp); 1369 i->skinDirPath = ASTRDUP(temp); 1370 1371 return 0; 1372} 1373 1374/* Read a hardware.ini if it is located in the skin directory */ 1375static int 1376_getBuildHardwareIni( AvdInfo* i ) 1377{ 1378 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 1379 1380 if (i->skinDirPath == NULL || i->skinName == NULL) 1381 return 0; 1382 1383 p = bufprint(temp, end, "%s/%s/hardware.ini", i->skinDirPath, i->skinName); 1384 if (p >= end || !path_exists(temp)) { 1385 DD("no skin-specific hardware.ini in %s", i->skinDirPath); 1386 return 0; 1387 } 1388 1389 D("found skin-specific hardware.ini: %s", temp); 1390 i->hardwareIni = iniFile_newFromFile(temp); 1391 if (i->hardwareIni == NULL) 1392 return -1; 1393 1394 return 0; 1395} 1396 1397 1398AvdInfo* 1399avdInfo_newForAndroidBuild( const char* androidBuildRoot, 1400 const char* androidOut, 1401 AvdInfoParams* params ) 1402{ 1403 AvdInfo* i; 1404 1405 ANEW0(i); 1406 1407 i->inAndroidBuild = 1; 1408 i->androidBuildRoot = ASTRDUP(androidBuildRoot); 1409 i->androidOut = ASTRDUP(androidOut); 1410 i->contentPath = ASTRDUP(androidOut); 1411 1412 /* TODO: find a way to provide better information from the build files */ 1413 i->deviceName = ASTRDUP("<build>"); 1414 1415 if (_getBuildConfigIni(i) < 0 || 1416 _getBuildImagePaths(i, params) < 0 ) 1417 goto FAIL; 1418 1419 /* we don't need to fail if there is no valid skin */ 1420 _getBuildSkin(i, params); 1421 _getBuildHardwareIni(i); 1422 1423 return i; 1424 1425FAIL: 1426 avdInfo_free(i); 1427 return NULL; 1428} 1429 1430const char* 1431avdInfo_getName( AvdInfo* i ) 1432{ 1433 return i ? i->deviceName : NULL; 1434} 1435 1436const char* 1437avdInfo_getImageFile( AvdInfo* i, AvdImageType imageType ) 1438{ 1439 if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX) 1440 return NULL; 1441 1442 return i->imagePath[imageType]; 1443} 1444 1445uint64_t 1446avdInfo_getImageFileSize( AvdInfo* i, AvdImageType imageType ) 1447{ 1448 const char* file = avdInfo_getImageFile(i, imageType); 1449 uint64_t size; 1450 1451 if (file == NULL) 1452 return 0ULL; 1453 1454 if (path_get_size(file, &size) < 0) 1455 return 0ULL; 1456 1457 return size; 1458} 1459 1460int 1461avdInfo_isImageReadOnly( AvdInfo* i, AvdImageType imageType ) 1462{ 1463 if (i == NULL || (unsigned)imageType >= AVD_IMAGE_MAX) 1464 return 1; 1465 1466 return (i->imageState[imageType] == IMAGE_STATE_READONLY); 1467} 1468 1469const char* 1470avdInfo_getSkinName( AvdInfo* i ) 1471{ 1472 return i->skinName; 1473} 1474 1475const char* 1476avdInfo_getSkinDir ( AvdInfo* i ) 1477{ 1478 return i->skinDirPath; 1479} 1480 1481int 1482avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw ) 1483{ 1484 IniFile* ini = i->configIni; 1485 int ret; 1486 1487 if (ini == NULL) 1488 ini = iniFile_newFromMemory("", 0); 1489 1490 ret = androidHwConfig_read(hw, ini); 1491 1492 if (ini != i->configIni) 1493 iniFile_free(ini); 1494 1495 if (ret == 0 && i->hardwareIni != NULL) { 1496 ret = androidHwConfig_read(hw, i->hardwareIni); 1497 } 1498 1499 /* special product-specific hardware configuration */ 1500 if (i->androidOut != NULL) 1501 { 1502 char* p = strrchr(i->androidOut, '/'); 1503 if (p != NULL && p[0] != 0) { 1504 if (p[1] == 's') { 1505 hw->hw_keyboard = 0; 1506 } 1507 } 1508 } 1509 1510 return ret; 1511} 1512 1513const char* 1514avdInfo_getContentPath( AvdInfo* i ) 1515{ 1516 return i->contentPath; 1517} 1518 1519int 1520avdInfo_inAndroidBuild( AvdInfo* i ) 1521{ 1522 return i->inAndroidBuild; 1523} 1524 1525char* 1526avdInfo_getTracePath( AvdInfo* i, const char* traceName ) 1527{ 1528 char tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp); 1529 1530 if (i == NULL || traceName == NULL || traceName[0] == 0) 1531 return NULL; 1532 1533 if (i->inAndroidBuild) { 1534 p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s", 1535 i->androidOut, traceName ); 1536 } else { 1537 p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s", 1538 i->contentPath, traceName ); 1539 } 1540 return ASTRDUP(tmp); 1541} 1542