Home | History | Annotate | Download | only in android
      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 
     13 /* This is the source code to the tiny "emulator" launcher program
     14  * that is in charge of starting the target-specific emulator binary
     15  * for a given AVD, i.e. either 'emulator-arm' or 'emulator-x86'
     16  *
     17  * This program will be replaced in the future by what is currently
     18  * known as 'emulator-ui', but is a good placeholder until this
     19  * migration is completed.
     20  */
     21 
     22 #include <errno.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include <unistd.h>
     27 #include <android/utils/compiler.h>
     28 #include <android/utils/host_bitness.h>
     29 #include <android/utils/panic.h>
     30 #include <android/utils/path.h>
     31 #include <android/utils/bufprint.h>
     32 #include <android/utils/win32_cmdline_quote.h>
     33 #include <android/avd/util.h>
     34 
     35 /* Required by android/utils/debug.h */
     36 int android_verbose;
     37 
     38 
     39 #define DEBUG 1
     40 
     41 #if DEBUG
     42 #  define D(...)  do { if (android_verbose) printf("emulator:" __VA_ARGS__); } while (0)
     43 #else
     44 #  define D(...)  do{}while(0)
     45 #endif
     46 
     47 /* The extension used by dynamic libraries on the host platform */
     48 #ifdef _WIN32
     49 #  define DLL_EXTENSION  ".dll"
     50 #elif defined(__APPLE__)
     51 #  define DLL_EXTENSION  ".dylib"
     52 #else
     53 #  define DLL_EXTENSION  ".so"
     54 #endif
     55 
     56 // Name of GPU emulation main library for (32-bit and 64-bit versions)
     57 #define GLES_EMULATION_LIB    "libOpenglRender" DLL_EXTENSION
     58 #define GLES_EMULATION_LIB64  "lib64OpenglRender" DLL_EXTENSION
     59 
     60 /* Forward declarations */
     61 static char* getTargetEmulatorPath(const char* progName, const char* avdArch, const int force_32bit);
     62 static char* getSharedLibraryPath(const char* progName, const char* libName);
     63 static void  prependSharedLibraryPath(const char* prefix);
     64 
     65 /* The execv() definition in older mingw is slightly bogus.
     66  * It takes a second argument of type 'const char* const*'
     67  * while POSIX mandates char** instead.
     68  *
     69  * To avoid compiler warnings, define the safe_execv macro
     70  * to perform an explicit cast with mingw.
     71  */
     72 #if defined(_WIN32) && !ANDROID_GCC_PREREQ(4,4)
     73 #  define safe_execv(_filepath,_argv)  execv((_filepath),(const char* const*)(_argv))
     74 #else
     75 #  define safe_execv(_filepath,_argv)  execv((_filepath),(_argv))
     76 #endif
     77 
     78 /* Main routine */
     79 int main(int argc, char** argv)
     80 {
     81     const char* avdName = NULL;
     82     char*       avdArch = NULL;
     83     char*       emulatorPath;
     84     int         force_32bit = 0;
     85 
     86     /* Define ANDROID_EMULATOR_DEBUG to 1 in your environment if you want to
     87      * see the debug messages from this launcher program.
     88      */
     89     const char* debug = getenv("ANDROID_EMULATOR_DEBUG");
     90 
     91     if (debug != NULL && *debug && *debug != '0')
     92         android_verbose = 1;
     93 
     94     /* Parse command-line and look for
     95      * 1) an avd name either in the form or '-avd <name>' or '@<name>'
     96      * 2) '-force-32bit' which always use 32-bit emulator on 64-bit platforms
     97      * 3) '-verbose', or '-debug-all' or '-debug all' to enable verbose mode.
     98      */
     99     int  nn;
    100     for (nn = 1; nn < argc; nn++) {
    101         const char* opt = argv[nn];
    102 
    103         if (!strcmp(opt,"-qemu"))
    104             break;
    105 
    106         if (!strcmp(opt,"-verbose") || !strcmp(opt,"-debug-all")) {
    107             android_verbose = 1;
    108         }
    109 
    110         if (!strcmp(opt,"-debug") && nn + 1 < argc &&
    111             !strcmp(argv[nn + 1], "all")) {
    112             android_verbose = 1;
    113         }
    114 
    115         if (!strcmp(opt,"-force-32bit")) {
    116             force_32bit = 1;
    117             continue;
    118         }
    119 
    120         if (!avdName) {
    121             if (!strcmp(opt,"-avd") && nn+1 < argc) {
    122                 avdName = argv[nn+1];
    123             }
    124             else if (opt[0] == '@' && opt[1] != '\0') {
    125                 avdName = opt+1;
    126             }
    127         }
    128     }
    129 
    130     /* If there is an AVD name, we're going to extract its target architecture
    131      * by looking at its config.ini
    132      */
    133     if (avdName != NULL) {
    134         D("Found AVD name '%s'\n", avdName);
    135         avdArch = path_getAvdTargetArch(avdName);
    136         D("Found AVD target architecture: %s\n", avdArch);
    137     } else {
    138         /* Otherwise, using the ANDROID_PRODUCT_OUT directory */
    139         const char* androidOut = getenv("ANDROID_PRODUCT_OUT");
    140 
    141         if (androidOut != NULL) {
    142             D("Found ANDROID_PRODUCT_OUT: %s\n", androidOut);
    143             avdArch = path_getBuildTargetArch(androidOut);
    144             D("Found build target architecture: %s\n",
    145               avdArch ? avdArch : "<NULL>");
    146         }
    147     }
    148 
    149     if (avdArch == NULL) {
    150         avdArch = "arm";
    151         D("Can't determine target AVD architecture: defaulting to %s\n", avdArch);
    152     }
    153 
    154     /* Find the architecture-specific program in the same directory */
    155     emulatorPath = getTargetEmulatorPath(argv[0], avdArch, force_32bit);
    156     D("Found target-specific emulator binary: %s\n", emulatorPath);
    157 
    158     /* Replace it in our command-line */
    159     argv[0] = emulatorPath;
    160 
    161     /* We need to find the location of the GLES emulation shared libraries
    162      * and modify either LD_LIBRARY_PATH or PATH accordingly
    163      */
    164     {
    165         char*  sharedLibPath = getSharedLibraryPath(emulatorPath, GLES_EMULATION_LIB);
    166 
    167         if (!sharedLibPath) {
    168             // Sometimes, only the 64-bit libraries are available, for example
    169             // when storing binaries under $AOSP/prebuilts/android-emulator/<system>/
    170             sharedLibPath = getSharedLibraryPath(emulatorPath, GLES_EMULATION_LIB64);
    171         }
    172 
    173         if (sharedLibPath != NULL) {
    174             D("Found OpenGLES emulation libraries in %s\n", sharedLibPath);
    175             prependSharedLibraryPath(sharedLibPath);
    176         } else {
    177             D("Could not find OpenGLES emulation host libraries!\n");
    178         }
    179     }
    180 
    181 #ifdef _WIN32
    182     // Take care of quoting all parameters before sending them to execv().
    183     // See the "Eveyone quotes command line arguments the wrong way" on
    184     // MSDN.
    185     int n;
    186     for (n = 0; n < argc; ++n) {
    187         // Technically, this leaks the quoted strings, but we don't care
    188         // since this process will terminate after the execv() anyway.
    189         argv[n] = win32_cmdline_quote(argv[n]);
    190         D("Quoted param: [%s]\n", argv[n]);
    191     }
    192 #endif
    193 
    194     // Launch it with the same set of options !
    195     // Note that on Windows, the first argument must _not_ be quoted or
    196     // Windows will fail to find the program.
    197     safe_execv(emulatorPath, argv);
    198 
    199     /* We could not launch the program ! */
    200     fprintf(stderr, "Could not launch '%s': %s\n", emulatorPath, strerror(errno));
    201     return errno;
    202 }
    203 
    204 /* Probe the filesystem to check if an emulator executable named like
    205  * <progDir>/<prefix><arch> exists.
    206  *
    207  * |progDir| is an optional program directory. If NULL, the executable
    208  * will be searched in the current directory.
    209  * |archSuffix| is an architecture-specific suffix, like "arm", or 'x86"
    210  * If |search_for_64bit_emulator| is true, lookup for 64-bit emulator first,
    211  * then the 32-bit version.
    212  * If |try_current_path|, try to look into the current path if no
    213  * executable was found under |progDir|.
    214  * On success, returns the path of the executable (string must be freed by
    215  * the caller). On failure, return NULL.
    216  */
    217 static char*
    218 probeTargetEmulatorPath(const char* progDir,
    219                         const char* archSuffix,
    220                         bool search_for_64bit_emulator,
    221                         bool try_current_path)
    222 {
    223     char path[PATH_MAX], *pathEnd = path + sizeof(path), *p;
    224 
    225     static const char kEmulatorPrefix[] = "emulator-";
    226     static const char kEmulator64Prefix[] = "emulator64-";
    227 #ifdef _WIN32
    228     const char kExeExtension[] = ".exe";
    229 #else
    230     const char kExeExtension[] = "";
    231 #endif
    232 
    233     // First search for the 64-bit emulator binary.
    234     if (search_for_64bit_emulator) {
    235         p = path;
    236         if (progDir) {
    237             p = bufprint(p, pathEnd, "%s/", progDir);
    238         }
    239         p = bufprint(p, pathEnd, "%s%s%s", kEmulator64Prefix,
    240                         archSuffix, kExeExtension);
    241         D("Probing program: %s\n", path);
    242         if (p < pathEnd && path_exists(path)) {
    243             return strdup(path);
    244         }
    245     }
    246 
    247     // Then for the 32-bit one.
    248     p = path;
    249     if (progDir) {
    250         p = bufprint(p, pathEnd, "%s/", progDir);
    251     }
    252     p = bufprint(p, pathEnd, "%s%s%s", kEmulatorPrefix,
    253                     archSuffix, kExeExtension);
    254     D("Probing program: %s\n", path);
    255     if (p < pathEnd && path_exists(path)) {
    256         return strdup(path);
    257     }
    258 
    259     // Not found, try in the current path then
    260     if (try_current_path) {
    261         char* result;
    262 
    263         if (search_for_64bit_emulator) {
    264             p = bufprint(path, pathEnd, "%s%s%s", kEmulator64Prefix,
    265                           archSuffix, kExeExtension);
    266             if (p < pathEnd) {
    267                 D("Probing path for: %s\n", path);
    268                 result = path_search_exec(path);
    269                 if (result) {
    270                     return result;
    271                 }
    272             }
    273         }
    274 
    275         p = bufprint(path, pathEnd, "%s%s%s", kEmulatorPrefix,
    276                       archSuffix, kExeExtension);
    277         if (p < pathEnd) {
    278             D("Probing path for: %s\n", path);
    279             result = path_search_exec(path);
    280             if (result) {
    281                 return result;
    282             }
    283         }
    284     }
    285 
    286     return NULL;
    287 }
    288 
    289 static char*
    290 getTargetEmulatorPath(const char* progName,
    291                       const char* avdArch,
    292                       const int force_32bit)
    293 {
    294     char*  progDir;
    295     char*  result;
    296 #ifdef _WIN32
    297     /* TODO: currently amd64-mingw32msvc-gcc doesn't work which prevents
    298              generating 64-bit binaries for Windows */
    299     bool search_for_64bit_emulator = false;
    300 #else
    301     bool search_for_64bit_emulator =
    302             !force_32bit && android_getHostBitness() == 64;
    303 #endif
    304 
    305     /* Only search in current path if there is no directory separator
    306      * in |progName|. */
    307 #ifdef _WIN32
    308     bool try_current_path =
    309             (!strchr(progName, '/') && !strchr(progName, '\\'));
    310 #else
    311     bool try_current_path = !strchr(progName, '/');
    312 #endif
    313 
    314     /* Get program's directory name in progDir */
    315     path_split(progName, &progDir, NULL);
    316 
    317     const char* emulatorSuffix;
    318 
    319     // Special case: for x86_64, first try to find emulator-x86_64 before
    320     // looking for emulator-x86.
    321     if (!strcmp(avdArch, "x86_64")) {
    322         emulatorSuffix = "x86_64";
    323 
    324         D("Looking for emulator backend for %s CPU\n", avdArch);
    325 
    326         result = probeTargetEmulatorPath(progDir,
    327                                          emulatorSuffix,
    328                                          search_for_64bit_emulator,
    329                                          try_current_path);
    330         if (result) {
    331             return result;
    332         }
    333     }
    334 
    335     // Special case: for arm64, first try to find emulator-arm64 before
    336     // looking for emulator-arm.
    337     if (!strcmp(avdArch, "arm64")) {
    338         emulatorSuffix = "arm64";
    339 
    340         D("Looking for emulator backend for %s CPU\n", avdArch);
    341 
    342         result = probeTargetEmulatorPath(progDir,
    343                                          emulatorSuffix,
    344                                          search_for_64bit_emulator,
    345                                          try_current_path);
    346         if (result) {
    347             return result;
    348         }
    349     }
    350 
    351     // Now for the regular case.
    352     emulatorSuffix = emulator_getBackendSuffix(avdArch);
    353     if (!emulatorSuffix) {
    354         APANIC("This emulator cannot emulate %s CPUs!\n", avdArch);
    355     }
    356     D("Looking for emulator-%s to emulate '%s' CPU\n", emulatorSuffix,
    357       avdArch);
    358 
    359     result = probeTargetEmulatorPath(progDir,
    360                                      emulatorSuffix,
    361                                      search_for_64bit_emulator,
    362                                      try_current_path);
    363     if (result) {
    364         return result;
    365     }
    366 
    367     /* Otherwise, the program is missing */
    368     APANIC("Missing emulator engine program for '%s' CPUS.\n", avdArch);
    369     return NULL;
    370 }
    371 
    372 /* return 1 iff <path>/<filename> exists */
    373 static int
    374 probePathForFile(const char* path, const char* filename)
    375 {
    376     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    377     p = bufprint(temp, end, "%s/%s", path, filename);
    378     D("Probing for: %s\n", temp);
    379     return (p < end && path_exists(temp));
    380 }
    381 
    382 /* Find the directory containing a given shared library required by the
    383  * emulator (for GLES emulation). We will probe several directories
    384  * that correspond to various use-cases.
    385  *
    386  * Caller must free() result string. NULL if not found.
    387  */
    388 
    389 static char*
    390 getSharedLibraryPath(const char* progName, const char* libName)
    391 {
    392     char* progDir;
    393     char* result = NULL;
    394     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    395 
    396     /* Get program's directory name */
    397     path_split(progName, &progDir, NULL);
    398 
    399     /* First, try to probe the program's directory itself, this corresponds
    400      * to the standalone build with ./android-configure.sh where the script
    401      * will copy the host shared library under external/qemu/objs where
    402      * the binaries are located.
    403      */
    404     if (probePathForFile(progDir, libName)) {
    405         return progDir;
    406     }
    407 
    408     /* Try under $progDir/lib/, this should correspond to the SDK installation
    409      * where the binary is under tools/, and the libraries under tools/lib/
    410      */
    411     {
    412         p = bufprint(temp, end, "%s/lib", progDir);
    413         if (p < end && probePathForFile(temp, libName)) {
    414             result = strdup(temp);
    415             goto EXIT;
    416         }
    417     }
    418 
    419     /* try in $progDir/../lib, this corresponds to the platform build
    420      * where the emulator binary is under out/host/<system>/bin and
    421      * the libraries are under out/host/<system>/lib
    422      */
    423     {
    424         char* parentDir = path_parent(progDir, 1);
    425 
    426         if (parentDir == NULL) {
    427             parentDir = strdup(".");
    428         }
    429         p = bufprint(temp, end, "%s/lib", parentDir);
    430         free(parentDir);
    431         if (p < end && probePathForFile(temp, libName)) {
    432             result = strdup(temp);
    433             goto EXIT;
    434         }
    435     }
    436 
    437     /* Nothing found! */
    438 EXIT:
    439     free(progDir);
    440     return result;
    441 }
    442 
    443 /* Prepend the path in 'prefix' to either LD_LIBRARY_PATH or PATH to
    444  * ensure that the shared libraries inside the path will be available
    445  * through dlopen() to the emulator program being launched.
    446  */
    447 static void
    448 prependSharedLibraryPath(const char* prefix)
    449 {
    450     size_t len = 0;
    451     char *temp = NULL;
    452     const char* path = NULL;
    453 
    454 #ifdef _WIN32
    455     path = getenv("PATH");
    456 #else
    457     path = getenv("LD_LIBRARY_PATH");
    458 #endif
    459 
    460     /* Will need up to 7 extra characters: "PATH=", ';' or ':', and '\0' */
    461     len = 7 + strlen(prefix) + (path ? strlen(path) : 0);
    462     temp = malloc(len);
    463     if (!temp)
    464         return;
    465 
    466     if (path && path[0] != '\0') {
    467 #ifdef _WIN32
    468         bufprint(temp, temp + len, "PATH=%s;%s", prefix, path);
    469 #else
    470         bufprint(temp, temp + len, "%s:%s", prefix, path);
    471 #endif
    472     } else {
    473 #ifdef _WIN32
    474         bufprint(temp, temp + len, "PATH=%s", prefix);
    475 #else
    476         strcpy(temp, prefix);
    477 #endif
    478     }
    479 
    480 #ifdef _WIN32
    481     D("Setting %s\n", temp);
    482     putenv(strdup(temp));
    483 #else
    484     D("Setting LD_LIBRARY_PATH=%s\n", temp);
    485     setenv("LD_LIBRARY_PATH", temp, 1);
    486 #endif
    487 }
    488