1 /* Copyright (C) 2011 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/util.h" 13 #include "android/utils/bufprint.h" 14 #include "android/utils/debug.h" 15 #include "android/utils/eintr_wrapper.h" 16 #include "android/utils/path.h" 17 #include "android/utils/dirscanner.h" 18 #include "android/main-common.h" 19 #include "android/globals.h" 20 #include "android/resource.h" 21 #include "android/user-config.h" 22 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <limits.h> 26 #ifdef _WIN32 27 #include <process.h> 28 #endif 29 #include <signal.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <sys/time.h> 33 #include <unistd.h> 34 35 36 /***********************************************************************/ 37 /***********************************************************************/ 38 /***** *****/ 39 /***** U T I L I T Y R O U T I N E S *****/ 40 /***** *****/ 41 /***********************************************************************/ 42 /***********************************************************************/ 43 44 #define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) 45 46 void reassign_string(char** string, const char* new_value) { 47 free(*string); 48 *string = ASTRDUP(new_value); 49 } 50 51 unsigned convertBytesToMB( uint64_t size ) 52 { 53 if (size == 0) 54 return 0; 55 56 size = (size + ONE_MB-1) >> 20; 57 if (size > UINT_MAX) 58 size = UINT_MAX; 59 60 return (unsigned) size; 61 } 62 63 uint64_t convertMBToBytes( unsigned megaBytes ) 64 { 65 return ((uint64_t)megaBytes << 20); 66 } 67 68 /* this function is used to perform auto-detection of the 69 * system directory in the case of a SDK installation. 70 * 71 * we want to deal with several historical usages, hence 72 * the slightly complicated logic. 73 * 74 * NOTE: the function returns the path to the directory 75 * containing 'fileName'. this is *not* the full 76 * path to 'fileName'. 77 */ 78 static char* 79 _getSdkImagePath( const char* fileName ) 80 { 81 char temp[MAX_PATH]; 82 char* p = temp; 83 char* end = p + sizeof(temp); 84 char* q; 85 char* app; 86 87 static const char* const searchPaths[] = { 88 "", /* program's directory */ 89 "/lib/images", /* this is for SDK 1.0 */ 90 "/../platforms/android-1.1/images", /* this is for SDK 1.1 */ 91 NULL 92 }; 93 94 app = bufprint_app_dir(temp, end); 95 if (app >= end) 96 return NULL; 97 98 do { 99 int nn; 100 101 /* first search a few well-known paths */ 102 for (nn = 0; searchPaths[nn] != NULL; nn++) { 103 p = bufprint(app, end, "%s", searchPaths[nn]); 104 q = bufprint(p, end, "/%s", fileName); 105 if (q < end && path_exists(temp)) { 106 *p = 0; 107 goto FOUND_IT; 108 } 109 } 110 111 /* hmmm. let's assume that we are in a post-1.1 SDK 112 * scan ../platforms if it exists 113 */ 114 p = bufprint(app, end, "/../platforms"); 115 if (p < end) { 116 DirScanner* scanner = dirScanner_new(temp); 117 if (scanner != NULL) { 118 int found = 0; 119 const char* subdir; 120 121 for (;;) { 122 subdir = dirScanner_next(scanner); 123 if (!subdir) break; 124 125 q = bufprint(p, end, "/%s/images/%s", subdir, fileName); 126 if (q >= end || !path_exists(temp)) 127 continue; 128 129 found = 1; 130 p = bufprint(p, end, "/%s/images", subdir); 131 break; 132 } 133 dirScanner_free(scanner); 134 if (found) 135 break; 136 } 137 } 138 139 /* I'm out of ideas */ 140 return NULL; 141 142 } while (0); 143 144 FOUND_IT: 145 //D("image auto-detection: %s/%s", temp, fileName); 146 return android_strdup(temp); 147 } 148 149 static char* 150 _getSdkImage( const char* path, const char* file ) 151 { 152 char temp[MAX_PATH]; 153 char *p = temp, *end = p + sizeof(temp); 154 155 p = bufprint(temp, end, "%s/%s", path, file); 156 if (p >= end || !path_exists(temp)) 157 return NULL; 158 159 return android_strdup(temp); 160 } 161 162 static char* 163 _getSdkSystemImage( const char* path, const char* optionName, const char* file ) 164 { 165 char* image = _getSdkImage(path, file); 166 167 if (image == NULL) { 168 derror("Your system directory is missing the '%s' image file.\n" 169 "Please specify one with the '%s <filepath>' option", 170 file, optionName); 171 exit(2); 172 } 173 return image; 174 } 175 176 void sanitizeOptions( AndroidOptions* opts ) 177 { 178 /* legacy support: we used to use -system <dir> and -image <file> 179 * instead of -sysdir <dir> and -system <file>, so handle this by checking 180 * whether the options point to directories or files. 181 */ 182 if (opts->image != NULL) { 183 if (opts->system != NULL) { 184 if (opts->sysdir != NULL) { 185 derror( "You can't use -sysdir, -system and -image at the same time.\n" 186 "You should probably use '-sysdir <path> -system <file>'.\n" ); 187 exit(2); 188 } 189 } 190 dwarning( "Please note that -image is obsolete and that -system is now used to point\n" 191 "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" ); 192 opts->sysdir = opts->system; 193 opts->system = opts->image; 194 opts->image = NULL; 195 } 196 else if (opts->system != NULL && path_is_dir(opts->system)) { 197 if (opts->sysdir != NULL) { 198 derror( "Option -system should now be followed by a file path, not a directory one.\n" 199 "Please use '-sysdir <path>' to point to the system directory.\n" ); 200 exit(1); 201 } 202 dwarning( "Please note that the -system option should now be used to point to the initial\n" 203 "system image (like the obsolete -image option). To point to the system directory\n" 204 "please now use '-sysdir <path>' instead.\n" ); 205 206 opts->sysdir = opts->system; 207 opts->system = NULL; 208 } 209 210 if (opts->nojni) { 211 opts->no_jni = opts->nojni; 212 opts->nojni = 0; 213 } 214 215 if (opts->nocache) { 216 opts->no_cache = opts->nocache; 217 opts->nocache = 0; 218 } 219 220 if (opts->noaudio) { 221 opts->no_audio = opts->noaudio; 222 opts->noaudio = 0; 223 } 224 225 if (opts->noskin) { 226 opts->no_skin = opts->noskin; 227 opts->noskin = 0; 228 } 229 230 /* If -no-cache is used, ignore any -cache argument */ 231 if (opts->no_cache) { 232 opts->cache = 0; 233 } 234 235 /* the purpose of -no-audio is to disable sound output from the emulator, 236 * not to disable Audio emulation. So simply force the 'none' backends */ 237 if (opts->no_audio) 238 opts->audio = "none"; 239 240 /* we don't accept -skindir without -skin now 241 * to simplify the autoconfig stuff with virtual devices 242 */ 243 if (opts->no_skin) { 244 opts->skin = "320x480"; 245 opts->skindir = NULL; 246 } 247 248 if (opts->skindir) { 249 if (!opts->skin) { 250 derror( "the -skindir <path> option requires a -skin <name> option"); 251 exit(1); 252 } 253 } 254 255 if (opts->bootchart) { 256 char* end; 257 int timeout = strtol(opts->bootchart, &end, 10); 258 if (timeout == 0) 259 opts->bootchart = NULL; 260 else if (timeout < 0 || timeout > 15*60) { 261 derror( "timeout specified for -bootchart option is invalid.\n" 262 "please use integers between 1 and 900\n"); 263 exit(1); 264 } 265 } 266 } 267 268 AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild) 269 { 270 AvdInfo* ret = NULL; 271 char tmp[MAX_PATH]; 272 char* tmpend = tmp + sizeof(tmp); 273 char* android_build_root = NULL; 274 char* android_build_out = NULL; 275 276 /* If no AVD name was given, try to find the top of the 277 * Android build tree 278 */ 279 if (opts->avd == NULL) { 280 do { 281 char* out = getenv("ANDROID_PRODUCT_OUT"); 282 283 if (out == NULL || out[0] == 0) 284 break; 285 286 if (!path_exists(out)) { 287 derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n" 288 "You need to build the Android system before launching the emulator", 289 out); 290 exit(2); 291 } 292 293 android_build_root = getenv("ANDROID_BUILD_TOP"); 294 if (android_build_root == NULL || android_build_root[0] == 0) 295 break; 296 297 if (!path_exists(android_build_root)) { 298 derror("Can't find the Android build root '%s'\n" 299 "Please check the definition of the ANDROID_BUILD_TOP variable.\n" 300 "It should point to the root of your source tree.\n", 301 android_build_root ); 302 exit(2); 303 } 304 android_build_out = out; 305 D( "found Android build root: %s", android_build_root ); 306 D( "found Android build out: %s", android_build_out ); 307 } while (0); 308 } 309 /* if no virtual device name is given, and we're not in the 310 * Android build system, we'll need to perform some auto-detection 311 * magic :-) 312 */ 313 if (opts->avd == NULL && !android_build_out) 314 { 315 if (!opts->sysdir) { 316 opts->sysdir = _getSdkImagePath("system.img"); 317 if (!opts->sysdir) { 318 derror( 319 "You did not specify a virtual device name, and the system\n" 320 "directory could not be found.\n\n" 321 "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n" 322 "to start a given virtual device (see -help-avd for details).\n\n" 323 324 "Otherwise, follow the instructions in -help-disk-images to start the emulator\n" 325 ); 326 exit(2); 327 } 328 D("autoconfig: -sysdir %s", opts->sysdir); 329 } 330 331 if (!opts->system) { 332 opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img"); 333 D("autoconfig: -system %s", opts->system); 334 } 335 336 if (!opts->kernel) { 337 opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu"); 338 D("autoconfig: -kernel %s", opts->kernel); 339 } 340 341 if (!opts->ramdisk) { 342 opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img"); 343 D("autoconfig: -ramdisk %s", opts->ramdisk); 344 } 345 346 /* if no data directory is specified, use the system directory */ 347 if (!opts->datadir) { 348 opts->datadir = android_strdup(opts->sysdir); 349 D("autoconfig: -datadir %s", opts->sysdir); 350 } 351 352 if (!opts->data) { 353 /* check for userdata-qemu.img in the data directory */ 354 bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir); 355 if (!path_exists(tmp)) { 356 derror( 357 "You did not provide the name of an Android Virtual Device\n" 358 "with the '-avd <name>' option. Read -help-avd for more information.\n\n" 359 360 "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n" 361 "to specify a data partition image file (I hope you know what you're doing).\n" 362 ); 363 exit(2); 364 } 365 366 opts->data = android_strdup(tmp); 367 D("autoconfig: -data %s", opts->data); 368 } 369 370 if (!opts->snapstorage && opts->datadir) { 371 bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir); 372 if (path_exists(tmp)) { 373 opts->snapstorage = android_strdup(tmp); 374 D("autoconfig: -snapstorage %s", opts->snapstorage); 375 } 376 } 377 } 378 379 /* setup the virtual device differently depending on whether 380 * we are in the Android build system or not 381 */ 382 if (opts->avd != NULL) 383 { 384 ret = avdInfo_new( opts->avd, android_avdParams ); 385 if (ret == NULL) { 386 /* an error message has already been printed */ 387 dprint("could not find virtual device named '%s'", opts->avd); 388 exit(1); 389 } 390 } 391 else 392 { 393 if (!android_build_out) { 394 android_build_out = android_build_root = opts->sysdir; 395 } 396 ret = avdInfo_newForAndroidBuild( 397 android_build_root, 398 android_build_out, 399 android_avdParams ); 400 401 if(ret == NULL) { 402 D("could not start virtual device\n"); 403 exit(1); 404 } 405 } 406 407 if (android_build_out) { 408 *inAndroidBuild = 1; 409 } else { 410 *inAndroidBuild = 0; 411 } 412 413 return ret; 414 } 415 416 void handle_ui_options( AndroidOptions* opts ) 417 { 418 return; 419 } 420 421 int attach_ui_to_core( AndroidOptions* opts ) 422 { 423 return 0; 424 } 425