Merge "emulator: Special case x86_64 emulation engine."
diff --git a/android/main-emulator.c b/android/main-emulator.c
index ef2b4b0..3f09c33 100644
--- a/android/main-emulator.c
+++ b/android/main-emulator.c
@@ -201,91 +201,155 @@
     return errno;
 }
 
-/* Find the target-specific emulator binary. This will be something
- * like  <programDir>/emulator-<targetArch>, where <programDir> is
- * the directory of the current program.
+/* Probe the filesystem to check if an emulator executable named like
+ * <progDir>/<prefix><arch> exists.
+ *
+ * |progDir| is an optional program directory. If NULL, the executable
+ * will be searched in the current directory.
+ * |archSuffix| is an architecture-specific suffix, like "arm", or 'x86"
+ * If |search_for_64bit_emulator| is true, lookup for 64-bit emulator first,
+ * then the 32-bit version.
+ * If |try_current_path|, try to look into the current path if no
+ * executable was found under |progDir|.
+ * On success, returns the path of the executable (string must be freed by
+ * the caller). On failure, return NULL.
  */
 static char*
-getTargetEmulatorPath(const char* progName, const char* avdArch, const int force_32bit)
+probeTargetEmulatorPath(const char* progDir,
+                        const char* archSuffix,
+                        bool search_for_64bit_emulator,
+                        bool try_current_path)
 {
-    char*  progDir;
-    char   path[PATH_MAX], *pathEnd=path+sizeof(path), *p;
-    const char* emulatorPrefix = "emulator-";
-    const char* emulator64Prefix = "emulator64-";
+    char path[PATH_MAX], *pathEnd = path + sizeof(path), *p;
+
+    static const char kEmulatorPrefix[] = "emulator-";
+    static const char kEmulator64Prefix[] = "emulator64-";
 #ifdef _WIN32
-    const char* exeExt = ".exe";
-    /* ToDo: currently amd64-mingw32msvc-gcc doesn't work (http://b/issue?id=5949152)
-             which prevents us from generating 64-bit emulator for Windows */
-    int search_for_64bit_emulator = 0;
+    const char kExeExtension[] = ".exe";
 #else
-    const char* exeExt = "";
-    int search_for_64bit_emulator =
-            !force_32bit && android_getHostBitness() == 64;
+    const char kExeExtension[] = "";
 #endif
 
-    const char* emulatorSuffix = emulator_getBackendSuffix(avdArch);
-    if (!emulatorSuffix) {
-        APANIC("This emulator cannot emulate %s CPUs!\n", avdArch);
-    }
-    D("Using emulator-%s to emulate '%s' CPUs\n", emulatorSuffix, avdArch);
-
-    /* Get program's directory name in progDir */
-    path_split(progName, &progDir, NULL);
-
+    // First search for the 64-bit emulator binary.
     if (search_for_64bit_emulator) {
-        /* Find 64-bit emulator first */
-        p = bufprint(path, pathEnd, "%s/%s%s%s", progDir,
-                     emulator64Prefix, emulatorSuffix, exeExt);
-        if (p >= pathEnd) {
-            APANIC("Path too long: %s\n", progName);
+        p = path;
+        if (progDir) {
+            p = bufprint(p, pathEnd, "%s/", progDir);
         }
-        if (path_exists(path)) {
-            free(progDir);
+        p = bufprint(p, pathEnd, "%s%s%s", kEmulator64Prefix,
+                        archSuffix, kExeExtension);
+        D("Probing program: %s\n", path);
+        if (p < pathEnd && path_exists(path)) {
             return strdup(path);
         }
     }
 
-    /* Find 32-bit emulator */
-    p = bufprint(path, pathEnd, "%s/%s%s%s", progDir, emulatorPrefix,
-                 emulatorSuffix, exeExt);
-    free(progDir);
-    if (p >= pathEnd) {
-        APANIC("Path too long: %s\n", progName);
+    // Then for the 32-bit one.
+    p = path;
+    if (progDir) {
+        p = bufprint(p, pathEnd, "%s/", progDir);
     }
-
-    if (path_exists(path)) {
+    p = bufprint(p, pathEnd, "%s%s%s", kEmulatorPrefix,
+                    archSuffix, kExeExtension);
+    D("Probing program: %s\n", path);
+    if (p < pathEnd && path_exists(path)) {
         return strdup(path);
     }
 
-    /* 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
+    // Not found, try in the current path then
+    if (try_current_path) {
+        char* result;
+
         if (search_for_64bit_emulator) {
-           p = bufprint(path, pathEnd, "%s%s%s", emulator64Prefix,
-                        emulatorSuffix, exeExt);
-           if (p < pathEnd) {
-               char*  resolved = path_search_exec(path);
-               if (resolved != NULL)
-                   return resolved;
-           }
+            p = bufprint(path, pathEnd, "%s%s%s", kEmulator64Prefix,
+                          archSuffix, kExeExtension);
+            if (p < pathEnd) {
+                D("Probing path for: %s\n", path);
+                result = path_search_exec(path);
+                if (result) {
+                    return result;
+                }
+            }
         }
 
-        p = bufprint(path, pathEnd, "%s%s%s", emulatorPrefix,
-                     emulatorSuffix, exeExt);
+        p = bufprint(path, pathEnd, "%s%s%s", kEmulatorPrefix,
+                      archSuffix, kExeExtension);
         if (p < pathEnd) {
-            char*  resolved = path_search_exec(path);
-            if (resolved != NULL)
-                return resolved;
+            D("Probing path for: %s\n", path);
+            result = path_search_exec(path);
+            if (result) {
+                return result;
+            }
         }
     }
 
+    return NULL;
+}
+
+static char*
+getTargetEmulatorPath(const char* progName,
+                      const char* avdArch,
+                      const int force_32bit)
+{
+    char*  progDir;
+    char*  result;
+#ifdef _WIN32
+    /* TODO: currently amd64-mingw32msvc-gcc doesn't work which prevents
+             generating 64-bit binaries for Windows */
+    bool search_for_64bit_emulator = false;
+#else
+    bool search_for_64bit_emulator =
+            !force_32bit && android_getHostBitness() == 64;
+#endif
+
+    /* Only search in current path if there is no directory separator
+     * in |progName|. */
+#ifdef _WIN32
+    bool try_current_path =
+            (!strchr(progName, '/') && !strchr(progName, '\\'));
+#else
+    bool try_current_path = !strchr(progName, '/');
+#endif
+
+    /* Get program's directory name in progDir */
+    path_split(progName, &progDir, NULL);
+
+    const char* emulatorSuffix;
+
+    // Special case: for x86_64, first try to find emulator-x86_64 before
+    // looking for emulator-x86.
+    if (!strcmp(avdArch, "x86_64")) {
+        emulatorSuffix = "x86_64";
+
+        D("Looking for emulator backend for %s CPU\n", avdArch);
+
+        result = probeTargetEmulatorPath(progDir,
+                                         emulatorSuffix,
+                                         search_for_64bit_emulator,
+                                         try_current_path);
+        if (result) {
+            return result;
+        }
+    }
+
+    // Now for the regular case.
+    emulatorSuffix = emulator_getBackendSuffix(avdArch);
+    if (!emulatorSuffix) {
+        APANIC("This emulator cannot emulate %s CPUs!\n", avdArch);
+    }
+    D("Looking for emulator-%s to emulate '%s' CPU\n", emulatorSuffix,
+      avdArch);
+
+    result = probeTargetEmulatorPath(progDir,
+                                     emulatorSuffix,
+                                     search_for_64bit_emulator,
+                                     try_current_path);
+    if (result) {
+        return result;
+    }
+
     /* Otherwise, the program is missing */
-    APANIC("Missing arch-specific emulator program: %s\n", path);
+    APANIC("Missing emulator engine program for '%s' CPUS.\n", avdArch);
     return NULL;
 }