/* Copyright (C) 2011 The Android Open Source Project ** ** This software is licensed under the terms of the GNU General Public ** License version 2, as published by the Free Software Foundation, and ** may be copied, distributed, and modified under those terms. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. */ /* This is the source code to the tiny "emulator" launcher program * that is in charge of starting the target-specific emulator binary * for a given AVD, i.e. either 'emulator-arm' or 'emulator-x86' * * This program will be replaced in the future by what is currently * known as 'emulator-ui', but is a good placeholder until this * migration is completed. */ #include #include #include #include #include #include #include #include #include /* Required by android/utils/debug.h */ int android_verbose; #define DEBUG 1 #if DEBUG # define D(...) do { if (android_verbose) printf("emulator:" __VA_ARGS__); } while (0) #else # define D(...) do{}while(0) #endif /* Forward declarations */ static char* getTargetEmulatorPath(const char* progName, const char* avdArch); #ifdef _WIN32 static char* quotePath(const char* path); #endif /* The execv() definition in mingw is slightly bogus. * It takes a second argument of type 'const char* const*' * while POSIX mandates char** instead. * * To avoid compiler warnings, define the safe_execv macro * to perform an explicit cast with mingw. */ #ifdef _WIN32 # define safe_execv(_filepath,_argv) execv((_filepath),(const char* const*)(_argv)) #else # define safe_execv(_filepath,_argv) execv((_filepath),(_argv)) #endif /* Main routine */ int main(int argc, char** argv) { const char* avdName = NULL; char* avdArch = NULL; char* emulatorPath; /* Define ANDROID_EMULATOR_DEBUG to 1 in your environment if you want to * see the debug messages from this launcher program. */ const char* debug = getenv("ANDROID_EMULATOR_DEBUG"); if (debug != NULL && *debug && *debug != '0') android_verbose = 1; /* Parse command-line and look for an avd name * Either in the form or '-avd ' or '@' */ int nn; for (nn = 1; nn < argc; nn++) { const char* opt = argv[nn]; if (!strcmp(opt,"-qemu")) break; if (!strcmp(opt,"-avd") && nn+1 < argc) { avdName = argv[nn+1]; break; } else if (opt[0] == '@' && opt[1] != '\0') { avdName = opt+1; break; } } /* If there is an AVD name, we're going to extract its target architecture * by looking at its config.ini */ if (avdName != NULL) { D("Found AVD name '%s'\n", avdName); avdArch = path_getAvdTargetArch(avdName); D("Found AVD target architecture: %s\n", avdArch); } else { /* Otherwise, using the ANDROID_PRODUCT_OUT directory */ const char* androidOut = getenv("ANDROID_PRODUCT_OUT"); if (androidOut != NULL && *androidOut != '\0') { D("Found ANDROID_PRODUCT_OUT: %s\n", androidOut); avdArch = path_getBuildTargetArch(androidOut); D("Found build target architecture: %s\n", avdArch); } } if (avdArch == NULL) { avdArch = "arm"; D("Can't determine target AVD architecture: defaulting to %s\n", avdArch); } /* Find the architecture-specific program in the same directory */ emulatorPath = getTargetEmulatorPath(argv[0], avdArch); D("Found target-specific emulator binary: %s\n", emulatorPath); /* Replace it in our command-line */ argv[0] = emulatorPath; #ifdef _WIN32 /* Looks like execv() in mingw (or is it MSVCRT.DLL?) doesn't * support a space in argv[0] unless we explicitely quote it. * IMPORTANT: do not quote the first argument to execv() or it will fail. * This was tested on a 32-bit Vista installation. */ if (strchr(emulatorPath, ' ')) { argv[0] = quotePath(emulatorPath); D("Quoted emulator binary path: %s\n", emulatorPath); } #endif /* Launch it with the same set of options ! */ safe_execv(emulatorPath, argv); /* We could not launch the program ! */ fprintf(stderr, "Could not launch '%s': %s\n", emulatorPath, strerror(errno)); return errno; } /* Find the target-specific emulator binary. This will be something * like /emulator-, where is * the directory of the current program. */ static char* getTargetEmulatorPath(const char* progName, const char* avdArch) { char* progDir; char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); #ifdef _WIN32 const char* exeExt = ".exe"; #else const char* exeExt = ""; #endif /* Get program's directory name in progDir */ path_split(progName, &progDir, NULL); p = bufprint(temp, end, "%s/emulator-%s%s", progDir, avdArch, exeExt); free(progDir); if (p >= end) { APANIC("Path too long: %s\n", progName); } if (path_exists(temp)) { return strdup(temp); } /* Mmm, the file doesn't exist, If there is no slash / backslash * in our path, we're going to try to search it in our path. */ #ifdef _WIN32 if (strchr(progName, '/') == NULL && strchr(progName, '\\') == NULL) { #else if (strchr(progName, '/') == NULL) { #endif p = bufprint(temp, end, "emulator-%s%s", avdArch, exeExt); if (p < end) { char* resolved = path_search_exec(temp); if (resolved != NULL) return resolved; } } /* Otherwise, the program is missing */ APANIC("Missing arch-specific emulator program: %s\n", temp); return NULL; } #ifdef _WIN32 static char* quotePath(const char* path) { int len = strlen(path); char* ret = malloc(len+3); ret[0] = '"'; memcpy(ret+1, path, len); ret[len+1] = '"'; ret[len+2] = '\0'; return ret; } #endif /* _WIN32 */