aboutsummaryrefslogtreecommitdiffstats
path: root/find_java/src
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@google.com>2014-06-11 21:28:58 -0700
committerXavier Ducrohet <xav@google.com>2014-06-11 21:37:37 -0700
commit53a6029a83a3b070f57dd5323f37f6fd18ca4633 (patch)
tree414d2b8d5123a7554154cb157d1b59bd37d71048 /find_java/src
parenta6e9f7b2fc87932fdb0bf23c12b6ceb8c7d832eb (diff)
downloadsdk-53a6029a83a3b070f57dd5323f37f6fd18ca4633.zip
sdk-53a6029a83a3b070f57dd5323f37f6fd18ca4633.tar.gz
sdk-53a6029a83a3b070f57dd5323f37f6fd18ca4633.tar.bz2
Compile find_java with Gradle.
Change-Id: I90ff236c35a857ebde82c3d63479709474aad204
Diffstat (limited to 'find_java/src')
-rwxr-xr-xfind_java/src/source/find_java.h36
-rw-r--r--find_java/src/source/find_java_exe.cpp155
-rwxr-xr-xfind_java/src/source/find_java_lib.cpp545
-rwxr-xr-xfind_java/src/source/utils.cpp202
-rwxr-xr-xfind_java/src/source/utils.h380
5 files changed, 1318 insertions, 0 deletions
diff --git a/find_java/src/source/find_java.h b/find_java/src/source/find_java.h
new file mode 100755
index 0000000..1181aa1
--- /dev/null
+++ b/find_java/src/source/find_java.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _H_FIND_JAVA
+#define _H_FIND_JAVA
+
+#ifdef _WIN32
+
+#include "utils.h"
+
+// We currently search for a Java version for at least 1.6
+#define MIN_JAVA_VERSION_MAJOR 1
+#define MIN_JAVA_VERSION_MINOR 6
+#define MIN_JAVA_VERSION (MIN_JAVA_VERSION_MAJOR * 1000 + MIN_JAVA_VERSION_MINOR)
+
+
+int findJavaInEnvPath(CPath *outJavaPath);
+int findJavaInRegistry(CPath *outJavaPath);
+int findJavaInProgramFiles(CPath *outJavaPath);
+bool getJavaVersion(CPath &javaPath, CString *outVersionStr, int *outVersionInt);
+
+#endif /* _WIN32 */
+#endif /* _H_FIND_JAVA */
diff --git a/find_java/src/source/find_java_exe.cpp b/find_java/src/source/find_java_exe.cpp
new file mode 100644
index 0000000..6b1add9
--- /dev/null
+++ b/find_java/src/source/find_java_exe.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * "find_java.exe", for Windows only.
+ * Tries to find a Java binary in a variety of places and prints the
+ * first one found on STDOUT and returns 0.
+ *
+ * If not found, returns error 1 with no message
+ * (unless ANDROID_SDKMAN_DEBUG or -d if set, in which case there's a message on STDERR).
+ *
+ * Implementation details:
+ * - We don't have access to ATL or MFC.
+ * - We don't want to pull in things like STL.
+ * - No Unicode/MBCS support for now.
+ *
+ * TODO for later version:
+ * - provide an env variable to let users override which version is being used.
+ * - if there's more than one java.exe found, enumerate them all.
+ * - and in that case take the one with the highest Java version number.
+ * - since that operation is expensive, do it only once and cache the result
+ * in a temp file. If the temp file is not found or the java binary no
+ * longer exists, re-run the enumaration.
+ */
+
+#ifdef _WIN32
+
+#include "utils.h"
+#include "find_java.h"
+#include <io.h>
+#include <fcntl.h>
+
+static void testFindJava() {
+
+ CPath javaPath("<not found>");
+ int v = findJavaInEnvPath(&javaPath);
+ printf("findJavaInEnvPath: [%d] %s\n", v, javaPath.cstr());
+
+ javaPath.set("<not found>");
+ v = findJavaInRegistry(&javaPath);
+ printf("findJavaInRegistry [%d] %s\n", v, javaPath.cstr());
+
+ javaPath.set("<not found>");
+ v = findJavaInProgramFiles(&javaPath);
+ printf("findJavaInProgramFiles [%d] %s\n", v, javaPath.cstr());
+}
+
+
+int main(int argc, char* argv[]) {
+
+ gIsConsole = true; // tell utils to to print errors to stderr
+ gIsDebug = (getenv("ANDROID_SDKMAN_DEBUG") != NULL);
+ bool doShortPath = false;
+ bool doVersion = false;
+ bool doJavaW = false;
+
+ for (int i = 1; i < argc; i++) {
+ if (strncmp(argv[i], "-t", 2) == 0) {
+ testFindJava();
+ return 0;
+
+ } else if (strncmp(argv[i], "-d", 2) == 0) {
+ gIsDebug = true;
+
+ } else if (strncmp(argv[i], "-s", 2) == 0) {
+ doShortPath = true;
+
+ } else if (strncmp(argv[i], "-v", 2) == 0) {
+ doVersion = true;
+
+ } else if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "-javaw") == 0) {
+ doJavaW = true;
+
+ } else {
+ printf(
+ "Outputs the path of the first Java.exe found on the local system.\n"
+ "Returns code 0 when found, 1 when not found.\n"
+ "Options:\n"
+ "-h / -help : This help.\n"
+ "-t / -test : Internal test.\n"
+ "-s / -short : Print path in short DOS form.\n"
+ "-w / -javaw : Search a matching javaw.exe; defaults to java.exe if not found.\n"
+ "-v / -version: Only prints the Java version found.\n"
+ );
+ return 2;
+ }
+ }
+
+ // Find the first suitable version of Java we can use.
+ CPath javaPath;
+ int version = findJavaInEnvPath(&javaPath);
+ if (version < MIN_JAVA_VERSION) {
+ version = findJavaInRegistry(&javaPath);
+ }
+ if (version < MIN_JAVA_VERSION) {
+ version = findJavaInProgramFiles(&javaPath);
+ }
+ if (version < MIN_JAVA_VERSION || javaPath.isEmpty()) {
+ if (gIsDebug) {
+ fprintf(stderr, "Failed to find Java on your system.\n");
+ }
+ return 1;
+ }
+ _ASSERT(!javaPath.isEmpty());
+
+ if (doShortPath) {
+ PVOID oldWow64Value = disableWow64FsRedirection();
+ if (!javaPath.toShortPath(&javaPath)) {
+ revertWow64FsRedirection(&oldWow64Value);
+ fprintf(stderr,
+ "Failed to convert path to a short DOS path: %s\n",
+ javaPath.cstr());
+ return 1;
+ }
+ revertWow64FsRedirection(&oldWow64Value);
+ }
+
+ if (doVersion) {
+ // Print version found. We already have the version as an integer
+ // so we don't need to run java -version a second time.
+ printf("%d.%d", version / 1000, version % 1000);
+ return 0;
+ }
+
+ if (doJavaW) {
+ // Try to find a javaw.exe instead of java.exe at the same location.
+ CPath javawPath(javaPath);
+ javawPath.replaceName("java.exe", "javaw.exe");
+ // Only accept it if we can actually find the exec
+ PVOID oldWow64Value = disableWow64FsRedirection();
+ if (javawPath.fileExists()) {
+ javaPath.set(javawPath.cstr());
+ }
+ revertWow64FsRedirection(&oldWow64Value);
+ }
+
+ // Print java.exe path found
+ printf("%s", javaPath.cstr());
+ return 0;
+}
+
+#endif /* _WIN32 */
diff --git a/find_java/src/source/find_java_lib.cpp b/find_java/src/source/find_java_lib.cpp
new file mode 100755
index 0000000..4c04e7f
--- /dev/null
+++ b/find_java/src/source/find_java_lib.cpp
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef _WIN32
+
+// Indicate we want at least all Windows Server 2003 (5.2) APIs.
+// Note: default is set by system/core/include/arch/windows/AndroidConfig.h to 0x0500
+// which is Win2K. However our minimum SDK tools requirement is Win XP (0x0501).
+// However we do need 0x0502 to get access to the WOW-64-32 constants for the
+// registry, except we'll need to be careful since they are not available on XP.
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0502
+// Indicate we want at least all IE 5 shell APIs
+#define _WIN32_IE 0x0500
+
+#include "find_java.h"
+#include <shlobj.h>
+#include <ctype.h>
+
+// Define some types missing in MingW
+#ifndef LSTATUS
+typedef LONG LSTATUS;
+#endif
+
+
+// Extract the first thing that looks like (digit.digit+).
+// Note: this will break when java reports a version with major > 9.
+// However it will reasonably cope with "1.10", if that ever happens.
+static bool extractJavaVersion(const char *start,
+ int length,
+ CString *outVersionStr,
+ int *outVersionInt) {
+ const char *end = start + length;
+ for (const char *c = start; c < end - 2; c++) {
+ if (isdigit(c[0]) &&
+ c[1] == '.' &&
+ isdigit(c[2])) {
+ const char *e = c+2;
+ while (isdigit(e[1])) {
+ e++;
+ }
+ if (outVersionStr != NULL) {
+ outVersionStr->set(c, e - c + 1);
+ }
+ if (outVersionInt != NULL) {
+ // add major * 1000, currently only 1 digit
+ int value = (*c - '0') * 1000;
+ // add minor
+ for (int m = 1; *e != '.'; e--, m *= 10) {
+ value += (*e - '0') * m;
+ }
+ *outVersionInt = value;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+// Check whether we can find $PATH/java.exe.
+// inOutPath should be the directory where we're looking at.
+// In output, it will be the java path we tested.
+// Returns the java version integer found (e.g. 1006 for 1.6).
+// Return 0 in case of error.
+static int checkPath(CPath *inOutPath) {
+ inOutPath->addPath("java.exe");
+
+ int result = 0;
+ PVOID oldWow64Value = disableWow64FsRedirection();
+ if (inOutPath->fileExists()) {
+ // Run java -version
+ // Reject the version if it's not at least our current minimum.
+ if (!getJavaVersion(*inOutPath, NULL /*versionStr*/, &result)) {
+ result = 0;
+ }
+ }
+
+ revertWow64FsRedirection(oldWow64Value);
+ return result;
+}
+
+// Check whether we can find $PATH/bin/java.exe
+// Returns the Java version found (e.g. 1006 for 1.6) or 0 in case of error.
+static int checkBinPath(CPath *inOutPath) {
+ inOutPath->addPath("bin");
+ return checkPath(inOutPath);
+}
+
+// Search java.exe in the environment
+int findJavaInEnvPath(CPath *outJavaPath) {
+ SetLastError(0);
+
+ int currVersion = 0;
+
+ const char* envPath = getenv("JAVA_HOME");
+ if (envPath != NULL) {
+ CPath p(envPath);
+ currVersion = checkBinPath(&p);
+ if (currVersion > 0) {
+ if (gIsDebug) {
+ fprintf(stderr, "Java %d found via JAVA_HOME: %s\n", currVersion, p.cstr());
+ }
+ *outJavaPath = p;
+ }
+ if (currVersion >= MIN_JAVA_VERSION) {
+ // As an optimization for runtime, if we find a suitable java
+ // version in JAVA_HOME we won't waste time looking at the PATH.
+ return currVersion;
+ }
+ }
+
+ envPath = getenv("PATH");
+ if (!envPath) return currVersion;
+
+ // Otherwise look at the entries in the current path.
+ // If we find more than one, keep the one with the highest version.
+
+ CArray<CString> *paths = CString(envPath).split(';');
+ for(int i = 0; i < paths->size(); i++) {
+ CPath p((*paths)[i].cstr());
+ int v = checkPath(&p);
+ if (v > currVersion) {
+ if (gIsDebug) {
+ fprintf(stderr, "Java %d found via env PATH: %s\n", v, p.cstr());
+ }
+ currVersion = v;
+ *outJavaPath = p;
+ }
+ }
+
+ delete paths;
+ return currVersion;
+}
+
+// --------------
+
+static bool getRegValue(const char *keyPath,
+ const char *keyName,
+ REGSAM access,
+ CString *outValue) {
+ HKEY key;
+ LSTATUS status = RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE, // hKey
+ keyPath, // lpSubKey
+ 0, // ulOptions
+ KEY_READ | access, // samDesired,
+ &key); // phkResult
+ if (status == ERROR_SUCCESS) {
+
+ LSTATUS ret = ERROR_MORE_DATA;
+ DWORD size = 4096; // MAX_PATH is 260, so 4 KB should be good enough
+ char* buffer = (char*) malloc(size);
+
+ while (ret == ERROR_MORE_DATA && size < (1<<16) /*64 KB*/) {
+ ret = RegQueryValueExA(
+ key, // hKey
+ keyName, // lpValueName
+ NULL, // lpReserved
+ NULL, // lpType
+ (LPBYTE) buffer, // lpData
+ &size); // lpcbData
+
+ if (ret == ERROR_MORE_DATA) {
+ size *= 2;
+ buffer = (char*) realloc(buffer, size);
+ } else {
+ buffer[size] = 0;
+ }
+ }
+
+ if (ret != ERROR_MORE_DATA) outValue->set(buffer);
+
+ free(buffer);
+ RegCloseKey(key);
+
+ return (ret != ERROR_MORE_DATA);
+ }
+
+ return false;
+}
+
+// Explore the registry to find a suitable version of Java.
+// Returns an int which is the version of Java found (e.g. 1006 for 1.6) and the
+// matching path in outJavaPath.
+// Returns 0 if nothing suitable was found.
+static int exploreJavaRegistry(const char *entry, REGSAM access, CPath *outJavaPath) {
+
+ // Let's visit HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment [CurrentVersion]
+ CPath rootKey("SOFTWARE\\JavaSoft\\");
+ rootKey.addPath(entry);
+
+ int versionInt = 0;
+ CString currentVersion;
+ CPath subKey(rootKey);
+ if (getRegValue(subKey.cstr(), "CurrentVersion", access, &currentVersion)) {
+ // CurrentVersion should be something like "1.7".
+ // We want to read HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.7 [JavaHome]
+ subKey.addPath(currentVersion);
+ CPath javaHome;
+ if (getRegValue(subKey.cstr(), "JavaHome", access, &javaHome)) {
+ versionInt = checkBinPath(&javaHome);
+ if (versionInt >= 0) {
+ if (gIsDebug) {
+ fprintf(stderr,
+ "Java %d found via registry: %s\n",
+ versionInt, javaHome.cstr());
+ }
+ *outJavaPath = javaHome;
+ }
+ if (versionInt >= MIN_JAVA_VERSION) {
+ // Heuristic: if the current version is good enough, stop here
+ return versionInt;
+ }
+ }
+ }
+
+ // Try again, but this time look at all the versions available
+ HKEY javaHomeKey;
+ LSTATUS status = RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE, // hKey
+ "SOFTWARE\\JavaSoft", // lpSubKey
+ 0, // ulOptions
+ KEY_READ | access, // samDesired
+ &javaHomeKey); // phkResult
+ if (status == ERROR_SUCCESS) {
+ char name[256];
+ DWORD index = 0;
+ CPath javaHome;
+ for (LONG result = ERROR_SUCCESS; result == ERROR_SUCCESS; index++) {
+ DWORD nameLen = 255;
+ name[nameLen] = 0;
+ result = RegEnumKeyExA(
+ javaHomeKey, // hKey
+ index, // dwIndex
+ name, // lpName
+ &nameLen, // lpcName
+ NULL, // lpReserved
+ NULL, // lpClass
+ NULL, // lpcClass,
+ NULL); // lpftLastWriteTime
+ if (result == ERROR_SUCCESS && nameLen < 256) {
+ name[nameLen] = 0;
+ CPath subKey(rootKey);
+ subKey.addPath(name);
+
+ if (getRegValue(subKey.cstr(), "JavaHome", access, &javaHome)) {
+ int v = checkBinPath(&javaHome);
+ if (v > versionInt) {
+ if (gIsDebug) {
+ fprintf(stderr,
+ "Java %d found via registry: %s\n",
+ versionInt, javaHome.cstr());
+ }
+ *outJavaPath = javaHome;
+ versionInt = v;
+ }
+ }
+ }
+ }
+
+ RegCloseKey(javaHomeKey);
+ }
+
+ return 0;
+}
+
+static bool getMaxJavaInRegistry(const char *entry, REGSAM access, CPath *outJavaPath, int *inOutVersion) {
+ CPath path;
+ int version = exploreJavaRegistry(entry, access, &path);
+ if (version > *inOutVersion) {
+ *outJavaPath = path;
+ *inOutVersion = version;
+ return true;
+ }
+ return false;
+}
+
+int findJavaInRegistry(CPath *outJavaPath) {
+ // We'll do the registry test 3 times: first using the default mode,
+ // then forcing the use of the 32-bit registry then forcing the use of
+ // 64-bit registry. On Windows 2k, the 2 latter will fail since the
+ // flags are not supported. On a 32-bit OS the 64-bit is obviously
+ // useless and the 2 first tests should be equivalent so we just
+ // need the first case.
+
+ // Check the JRE first, then the JDK.
+ int version = MIN_JAVA_VERSION - 1;
+ bool result = false;
+ result |= getMaxJavaInRegistry("Java Runtime Environment", 0, outJavaPath, &version);
+ result |= getMaxJavaInRegistry("Java Development Kit", 0, outJavaPath, &version);
+
+ // Get the app sysinfo state (the one hidden by WOW64)
+ SYSTEM_INFO sysInfo;
+ GetSystemInfo(&sysInfo);
+ WORD programArch = sysInfo.wProcessorArchitecture;
+ // Check the real sysinfo state (not the one hidden by WOW64) for x86
+ GetNativeSystemInfo(&sysInfo);
+ WORD actualArch = sysInfo.wProcessorArchitecture;
+
+ // Only try to access the WOW64-32 redirected keys on a 64-bit system.
+ // There's no point in doing this on a 32-bit system.
+ if (actualArch == PROCESSOR_ARCHITECTURE_AMD64) {
+ if (programArch != PROCESSOR_ARCHITECTURE_INTEL) {
+ // If we did the 32-bit case earlier, don't do it twice.
+ result |= getMaxJavaInRegistry(
+ "Java Runtime Environment", KEY_WOW64_32KEY, outJavaPath, &version);
+ result |= getMaxJavaInRegistry(
+ "Java Development Kit", KEY_WOW64_32KEY, outJavaPath, &version);
+
+ } else if (programArch != PROCESSOR_ARCHITECTURE_AMD64) {
+ // If we did the 64-bit case earlier, don't do it twice.
+ result |= getMaxJavaInRegistry(
+ "Java Runtime Environment", KEY_WOW64_64KEY, outJavaPath, &version);
+ result |= getMaxJavaInRegistry(
+ "Java Development Kit", KEY_WOW64_64KEY, outJavaPath, &version);
+ }
+ }
+
+ return result ? version : 0;
+}
+
+// --------------
+
+static bool checkProgramFiles(CPath *outJavaPath, int *inOutVersion) {
+
+ char programFilesPath[MAX_PATH + 1];
+ HRESULT result = SHGetFolderPathA(
+ NULL, // hwndOwner
+ CSIDL_PROGRAM_FILES, // nFolder
+ NULL, // hToken
+ SHGFP_TYPE_CURRENT, // dwFlags
+ programFilesPath); // pszPath
+ if (FAILED(result)) return false;
+
+ CPath path(programFilesPath);
+ path.addPath("Java");
+
+ // Do we have a C:\\Program Files\\Java directory?
+ if (!path.dirExists()) return false;
+
+ CPath glob(path);
+ glob.addPath("j*");
+
+ bool found = false;
+ WIN32_FIND_DATAA findData;
+ HANDLE findH = FindFirstFileA(glob.cstr(), &findData);
+ if (findH == INVALID_HANDLE_VALUE) return false;
+ do {
+ if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ CPath temp(path);
+ temp.addPath(findData.cFileName);
+ // Check C:\\Program Files[x86]\\Java\\j*\\bin\\java.exe
+ int v = checkBinPath(&temp);
+ if (v > *inOutVersion) {
+ found = true;
+ *inOutVersion = v;
+ *outJavaPath = temp;
+ }
+ }
+ } while (!found && FindNextFileA(findH, &findData) != 0);
+ FindClose(findH);
+
+ return found;
+}
+
+int findJavaInProgramFiles(CPath *outJavaPath) {
+
+ // Check the C:\\Program Files (x86) directory
+ // With WOW64 fs redirection in place by default, we should get the x86
+ // version on a 64-bit OS since this app is a 32-bit itself.
+ bool result = false;
+ int version = MIN_JAVA_VERSION - 1;
+ result |= checkProgramFiles(outJavaPath, &version);
+
+ // Check the real sysinfo state (not the one hidden by WOW64) for x86
+ SYSTEM_INFO sysInfo;
+ GetNativeSystemInfo(&sysInfo);
+
+ if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
+ // On a 64-bit OS, try again by disabling the fs redirection so
+ // that we can try the real C:\\Program Files directory.
+ PVOID oldWow64Value = disableWow64FsRedirection();
+ result |= checkProgramFiles(outJavaPath, &version);
+ revertWow64FsRedirection(oldWow64Value);
+ }
+
+ return result ? version : 0;
+}
+
+// --------------
+
+
+// Tries to invoke the java.exe at the given path and extract it's
+// version number.
+// - outVersionStr: if not null, will capture version as a string (e.g. "1.6")
+// - outVersionInt: if not null, will capture version as an int (major * 1000 + minor, e.g. 1006).
+bool getJavaVersion(CPath &javaPath, CString *outVersionStr, int *outVersionInt) {
+ bool result = false;
+
+ // Run "java -version", which outputs something like to *STDERR*:
+ //
+ // java version "1.6.0_29"
+ // Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
+ // Java HotSpot(TM) Client VM (build 20.4-b02, mixed mode, sharing)
+ //
+ // We want to capture the first line, and more exactly the "1.6" part.
+
+
+ CString cmd;
+ cmd.setf("\"%s\" -version", javaPath.cstr());
+
+ SECURITY_ATTRIBUTES saAttr;
+ STARTUPINFO startup;
+ PROCESS_INFORMATION pinfo;
+
+ // Want to inherit pipe handle
+ ZeroMemory(&saAttr, sizeof(saAttr));
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+
+ // Create pipe for stdout
+ HANDLE stdoutPipeRd, stdoutPipeWt;
+ if (!CreatePipe(
+ &stdoutPipeRd, // hReadPipe,
+ &stdoutPipeWt, // hWritePipe,
+ &saAttr, // lpPipeAttributes,
+ 0)) { // nSize (0=default buffer size)
+ if (gIsConsole || gIsDebug) displayLastError("CreatePipe failed: ");
+ return false;
+ }
+ if (!SetHandleInformation(stdoutPipeRd, HANDLE_FLAG_INHERIT, 0)) {
+ if (gIsConsole || gIsDebug) displayLastError("SetHandleInformation failed: ");
+ return false;
+ }
+
+ ZeroMemory(&pinfo, sizeof(pinfo));
+
+ ZeroMemory(&startup, sizeof(startup));
+ startup.cb = sizeof(startup);
+ startup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
+ startup.wShowWindow = SW_HIDE|SW_MINIMIZE;
+ // Capture both stderr and stdout
+ startup.hStdError = stdoutPipeWt;
+ startup.hStdOutput = stdoutPipeWt;
+ startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+
+ BOOL ok = CreateProcessA(
+ NULL, // program path
+ (LPSTR) cmd.cstr(), // command-line
+ NULL, // process handle is not inheritable
+ NULL, // thread handle is not inheritable
+ TRUE, // yes, inherit some handles
+ 0, // process creation flags
+ NULL, // use parent's environment block
+ NULL, // use parent's starting directory
+ &startup, // startup info, i.e. std handles
+ &pinfo);
+
+ if ((gIsConsole || gIsDebug) && !ok) displayLastError("CreateProcess failed: ");
+
+ // Close the write-end of the output pipe (we're only reading from it)
+ CloseHandle(stdoutPipeWt);
+
+ // Read from the output pipe. We don't need to read everything,
+ // the first line should be 'Java version "1.2.3_45"\r\n'
+ // so reading about 32 chars is all we need.
+ char first32[32 + 1];
+ int index = 0;
+ first32[0] = 0;
+
+ if (ok) {
+
+ #define SIZE 1024
+ char buffer[SIZE];
+ DWORD sizeRead = 0;
+
+ while (ok) {
+ // Keep reading in the same buffer location
+ ok = ReadFile(stdoutPipeRd, // hFile
+ buffer, // lpBuffer
+ SIZE, // DWORD buffer size to read
+ &sizeRead, // DWORD buffer size read
+ NULL); // overlapped
+ if (!ok || sizeRead == 0 || sizeRead > SIZE) break;
+
+ // Copy up to the first 32 characters
+ if (index < 32) {
+ DWORD n = 32 - index;
+ if (n > sizeRead) n = sizeRead;
+ // copy as lowercase to simplify checks later
+ for (char *b = buffer; n > 0; n--, b++, index++) {
+ char c = *b;
+ if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
+ first32[index] = c;
+ }
+ first32[index] = 0;
+ }
+ }
+
+ WaitForSingleObject(pinfo.hProcess, INFINITE);
+
+ DWORD exitCode;
+ if (GetExitCodeProcess(pinfo.hProcess, &exitCode)) {
+ // this should not return STILL_ACTIVE (259)
+ result = exitCode == 0;
+ }
+
+ CloseHandle(pinfo.hProcess);
+ CloseHandle(pinfo.hThread);
+ }
+ CloseHandle(stdoutPipeRd);
+
+ if (result && index > 0) {
+ // Look for a few keywords in the output however we don't
+ // care about specific ordering or case-senstiviness.
+ // We only captures roughtly the first line in lower case.
+ char *j = strstr(first32, "java");
+ char *v = strstr(first32, "version");
+ if ((gIsConsole || gIsDebug) && (!j || !v)) {
+ fprintf(stderr, "Error: keywords 'java version' not found in '%s'\n", first32);
+ }
+ if (j != NULL && v != NULL) {
+ result = extractJavaVersion(first32, index, outVersionStr, outVersionInt);
+ }
+ }
+
+ return result;
+}
+
+
+#endif /* _WIN32 */
diff --git a/find_java/src/source/utils.cpp b/find_java/src/source/utils.cpp
new file mode 100755
index 0000000..e2ce58f
--- /dev/null
+++ b/find_java/src/source/utils.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef _WIN32
+
+#include "utils.h"
+
+#define _CRT_SECURE_NO_WARNINGS 1
+
+// Set to true to get some extra debug information
+bool gIsDebug = false;
+// Set to true to output errors to stderr (for a Console app)
+// or to false to output using msg box (for a Windows UI app)
+bool gIsConsole = false;
+
+// Displays a message in an ok+info dialog box.
+void msgBox(const char* text, ...) {
+ CString formatted;
+ va_list ap;
+ va_start(ap, text);
+ formatted.setv(text, ap);
+ va_end(ap);
+
+ MessageBoxA(NULL, formatted.cstr(), "Android SDK Manager", MB_OK | MB_ICONINFORMATION);
+}
+
+// Displays GetLastError prefixed with a description in an error dialog box
+void displayLastError(const char *description, ...) {
+ CString formatted;
+ va_list ap;
+ va_start(ap, description);
+ formatted.setv(description, ap);
+ va_end(ap);
+
+ CString error;
+ error.setLastWin32Error(NULL);
+ formatted.add("\r\n");
+ formatted.add(error.cstr());
+
+ if (gIsConsole) {
+ fprintf(stderr, "%s\n", formatted.cstr());
+ } else {
+ MessageBox(NULL, formatted.cstr(), "Android SDK Manager - Error", MB_OK | MB_ICONERROR);
+ }
+}
+
+// Executes the command line. Does not wait for the program to finish.
+// The return code is from CreateProcess (0 means failure), not the running app.
+int execNoWait(const char *app, const char *params, const char *workDir) {
+ STARTUPINFO startup;
+ PROCESS_INFORMATION pinfo;
+
+ ZeroMemory(&pinfo, sizeof(pinfo));
+
+ ZeroMemory(&startup, sizeof(startup));
+ startup.cb = sizeof(startup);
+ startup.dwFlags = STARTF_USESHOWWINDOW;
+ startup.wShowWindow = SW_SHOWDEFAULT;
+
+ int ret = CreateProcessA(
+ (LPSTR) app, /* program path */
+ (LPSTR) params, /* command-line */
+ NULL, /* process handle is not inheritable */
+ NULL, /* thread handle is not inheritable */
+ TRUE, /* yes, inherit some handles */
+ 0, /* create flags */
+ NULL, /* use parent's environment block */
+ workDir, /* use parent's starting directory */
+ &startup, /* startup info, i.e. std handles */
+ &pinfo);
+
+ if (ret) {
+ CloseHandle(pinfo.hProcess);
+ CloseHandle(pinfo.hThread);
+ }
+
+ return ret;
+}
+
+// Executes command, waits for completion and returns exit code.
+// As indicated in MSDN for CreateProcess, callers should double-quote the program name
+// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";
+int execWait(const char *cmd) {
+ STARTUPINFO startup;
+ PROCESS_INFORMATION pinfo;
+
+ ZeroMemory(&pinfo, sizeof(pinfo));
+
+ ZeroMemory(&startup, sizeof(startup));
+ startup.cb = sizeof(startup);
+ startup.dwFlags = STARTF_USESHOWWINDOW;
+ startup.wShowWindow = SW_HIDE|SW_MINIMIZE;
+
+ int ret = CreateProcessA(
+ NULL, /* program path */
+ (LPSTR) cmd, /* command-line */
+ NULL, /* process handle is not inheritable */
+ NULL, /* thread handle is not inheritable */
+ TRUE, /* yes, inherit some handles */
+ CREATE_NO_WINDOW, /* we don't want a console */
+ NULL, /* use parent's environment block */
+ NULL, /* use parent's starting directory */
+ &startup, /* startup info, i.e. std handles */
+ &pinfo);
+
+ int result = -1;
+ if (ret) {
+ WaitForSingleObject(pinfo.hProcess, INFINITE);
+
+ DWORD exitCode;
+ if (GetExitCodeProcess(pinfo.hProcess, &exitCode)) {
+ // this should not return STILL_ACTIVE (259)
+ result = exitCode;
+ }
+ CloseHandle(pinfo.hProcess);
+ CloseHandle(pinfo.hThread);
+ }
+
+ return result;
+}
+
+bool getModuleDir(CPath *outDir) {
+ CHAR programDir[MAX_PATH];
+ int ret = GetModuleFileName(NULL, programDir, sizeof(programDir));
+ if (ret != 0) {
+ // Remove the last segment to keep only the directory.
+ int pos = ret - 1;
+ while (pos > 0 && programDir[pos] != '\\') {
+ --pos;
+ }
+ outDir->set(programDir, pos);
+ return true;
+ }
+ return false;
+}
+
+// Disables the FS redirection done by WOW64.
+// Because this runs as a 32-bit app, Windows automagically remaps some
+// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").
+// This prevents the app from correctly searching for java.exe in these folders.
+// The registry is also remapped. This method disables this redirection.
+// Caller should restore the redirection later by using revertWow64FsRedirection().
+PVOID disableWow64FsRedirection() {
+
+ // The call we want to make is the following:
+ // PVOID oldWow64Value;
+ // Wow64DisableWow64FsRedirection(&oldWow64Value);
+ // However that method may not exist (e.g. on XP non-64 systems) so
+ // we must not call it directly.
+
+ PVOID oldWow64Value = 0;
+
+ HMODULE hmod = LoadLibrary("kernel32.dll");
+ if (hmod != NULL) {
+ FARPROC proc = GetProcAddress(hmod, "Wow64DisableWow64FsRedirection");
+ if (proc != NULL) {
+ typedef BOOL (WINAPI *disableWow64FuncType)(PVOID *);
+ disableWow64FuncType funcPtr = (disableWow64FuncType)proc;
+ funcPtr(&oldWow64Value);
+ }
+
+ FreeLibrary(hmod);
+ }
+
+ return oldWow64Value;
+}
+
+// Reverts the redirection disabled in disableWow64FsRedirection.
+void revertWow64FsRedirection(PVOID oldWow64Value) {
+
+ // The call we want to make is the following:
+ // Wow64RevertWow64FsRedirection(oldWow64Value);
+ // However that method may not exist (e.g. on XP non-64 systems) so
+ // we must not call it directly.
+
+ HMODULE hmod = LoadLibrary("kernel32.dll");
+ if (hmod != NULL) {
+ FARPROC proc = GetProcAddress(hmod, "Wow64RevertWow64FsRedirection");
+ if (proc != NULL) {
+ typedef BOOL (WINAPI *revertWow64FuncType)(PVOID);
+ revertWow64FuncType funcPtr = (revertWow64FuncType)proc;
+ funcPtr(oldWow64Value);
+ }
+
+ FreeLibrary(hmod);
+ }
+}
+
+#endif /* _WIN32 */
diff --git a/find_java/src/source/utils.h b/find_java/src/source/utils.h
new file mode 100755
index 0000000..dc9031d
--- /dev/null
+++ b/find_java/src/source/utils.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _H_UTILS
+#define _H_UTILS
+
+#ifdef _WIN32
+
+#define _CRT_SECURE_NO_WARNINGS 1
+
+#include <direct.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <windows.h>
+
+// VS vs MINGW specific includes
+#ifdef USE_VS_CRT
+ #include <crtdbg.h> // for _ASSERT
+#else
+ #define _ASSERT(x) // undef
+#endif
+
+extern bool gIsDebug;
+extern bool gIsConsole;
+
+// An array that knows its own size. Not dynamically resizable.
+template <class T> class CArray {
+ T* mPtr;
+ int mSize;
+public:
+ explicit CArray(int size) {
+ mSize = size;
+ mPtr = new T[size];
+ }
+
+ ~CArray() {
+ if (mPtr != NULL) {
+ delete[] mPtr;
+ mPtr = NULL;
+ }
+ mSize = 0;
+ }
+
+ T& operator[](int i) {
+ _ASSERT(i >= 0 && i < mSize);
+ return mPtr[i];
+ }
+
+ int size() const {
+ return mSize;
+ }
+};
+
+// A simple string class wrapper.
+class CString {
+protected:
+ char *mStr;
+public:
+ CString() { mStr = NULL; }
+ CString(const CString &str) { mStr = NULL; set(str.mStr); }
+ explicit CString(const char *str) { mStr = NULL; set(str); }
+ CString(const char *start, int length) { mStr = NULL; set(start, length); }
+
+ CString& operator=(const CString &str) {
+ return set(str.cstr());
+ }
+
+ CString& set(const char *str) {
+ if (str != mStr) {
+ _free();
+ if (str != NULL) {
+ mStr = _strdup(str);
+ }
+ }
+ return *this;
+ }
+
+ CString& set(const char *start, int length) {
+ _free();
+ if (start != NULL) {
+ mStr = (char *)malloc(length + 1);
+ strncpy(mStr, start, length);
+ mStr[length] = 0;
+ }
+ return *this;
+ }
+
+ CString& setv(const char *str, va_list ap) {
+ _free();
+ // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.
+ // Instead we'll iterate till we have enough space to generate the string.
+ int len = strlen(str) + 1024;
+ mStr = (char *)malloc(len);
+ strcpy(mStr, str); // provide a default in case vsnprintf totally fails
+ for (int guard = 0; guard < 10; guard++) {
+ int ret = vsnprintf(mStr, len, str, ap);
+ if (ret == -1) {
+ // Some implementations don't give the proper size needed
+ // so double the space and try again.
+ len *= 2;
+ } else if (ret >= len) {
+ len = ret + 1;
+ } else {
+ // There was enough space to write.
+ break;
+ }
+ mStr = (char *)realloc((void *)mStr, len);
+ strcpy(mStr, str); // provide a default in case vsnprintf totally fails
+ }
+ return *this;
+ }
+
+ CString& setf(const char *str, ...) {
+ _free();
+ va_list ap;
+ va_start(ap, str);
+ setv(str, ap);
+ va_end(ap);
+ return *this;
+ }
+
+ virtual ~CString() { _free(); }
+
+ // Returns the C string owned by this CString. It will be
+ // invalid as soon as this CString is deleted or out of scope.
+ const char * cstr() const {
+ return mStr;
+ }
+
+ bool isEmpty() const {
+ return mStr == NULL || *mStr == 0;
+ }
+
+ int length() const {
+ return mStr == NULL ? 0 : strlen(mStr);
+ }
+
+ CString& add(const char *str) {
+ if (mStr == NULL) {
+ set(str);
+ } else {
+ mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(str) + 1);
+ strcat(mStr, str);
+ }
+ return *this;
+ }
+
+ CString& add(const char *str, int length) {
+ if (mStr == NULL) {
+ set(str, length);
+ } else {
+ int l1 = strlen(mStr);
+ mStr = (char *)realloc((void *)mStr, l1 + length + 1);
+ strncpy(mStr + l1, str, length);
+ mStr[l1 + length] = 0;
+ }
+ return *this;
+ }
+
+ CArray<CString> * split(char sep) const {
+ if (mStr == NULL) {
+ return new CArray<CString>(0);
+ }
+ const char *last = NULL;
+ int n = 0;
+ for (const char *s = mStr; *s; s++) {
+ if (*s == sep && s != mStr && (last == NULL || s > last+1)) {
+ n++;
+ last = s;
+ }
+ }
+
+ CArray<CString> *result = new CArray<CString>(n);
+ last = NULL;
+ n = 0;
+ for (const char *s = mStr; *s; s++) {
+ if (*s == sep) {
+ if (s != mStr && (last == NULL || s > last+1)) {
+ const char *start = last ? last : mStr;
+ (*result)[n++].set(start, s-start);
+ }
+ last = s+1;
+ }
+ }
+
+ return result;
+ }
+
+ // Sets the string to the message matching Win32 GetLastError.
+ // If message is non-null, it is prepended to the last error string.
+ CString& setLastWin32Error(const char *message) {
+ DWORD err = GetLastError();
+ LPSTR errStr;
+ if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, /* lpSource */
+ err, /* dwMessageId */
+ 0, /* dwLanguageId */
+ (LPSTR)&errStr, /* lpBuffer */
+ 0, /* nSize */
+ NULL) != 0) { /* va_list args */
+ if (message == NULL) {
+ setf("[%d] %s", err, errStr);
+ } else {
+ setf("%s[%d] %s", message, err, errStr);
+ }
+ LocalFree(errStr);
+ }
+ return *this;
+ }
+
+private:
+ void _free() {
+ if (mStr != NULL) {
+ free((void *)mStr);
+ mStr = NULL;
+ }
+ }
+
+};
+
+// A simple path class wrapper.
+class CPath : public CString {
+public:
+ CPath() : CString() { }
+ CPath(const CString &str) : CString(str) { }
+ CPath(const CPath &str) : CString(str) { }
+ explicit CPath(const char *str) : CString(str) { }
+ CPath(const char *start, int length) : CString(start, length) { }
+
+ CPath& operator=(const CPath &str) {
+ set(str.cstr());
+ return *this;
+ }
+
+ // Appends a path segment, adding a \ as necessary.
+ CPath& addPath(const CString &s) {
+ return addPath(s.cstr());
+ }
+
+ // Appends a path segment, adding a \ as necessary.
+ CPath& addPath(const char *s) {
+ _ASSERT(s != NULL);
+ if (s != NULL && s[0] != 0) {
+ int n = length();
+ if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");
+ add(s);
+ }
+ return *this;
+ }
+
+ // Returns true if file exist and is not a directory.
+ // There's no garantee we have rights to access it.
+ bool fileExists() const {
+ if (mStr == NULL) return false;
+ DWORD attribs = GetFileAttributesA(mStr);
+ return attribs != INVALID_FILE_ATTRIBUTES &&
+ !(attribs & FILE_ATTRIBUTE_DIRECTORY);
+ }
+
+ // Returns true if file exist and is a directory.
+ // There's no garantee we have rights to access it.
+ bool dirExists() const {
+ if (mStr == NULL) return false;
+ DWORD attribs = GetFileAttributesA(mStr);
+ return attribs != INVALID_FILE_ATTRIBUTES &&
+ (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ }
+
+ // Returns a copy of the directory portion of the path, if any
+ CPath dirName() const {
+ CPath result;
+ if (mStr != NULL) {
+ char *pos = strrchr(mStr, '\\');
+ if (pos != NULL) {
+ result.set(mStr, pos - mStr);
+ }
+ }
+ return result;
+ }
+
+ // Returns a pointer to the baseName part of the path.
+ // It becomes invalid if the path changes.
+ const char * baseName() const {
+ if (mStr != NULL) {
+ char *pos = strrchr(mStr, '\\');
+ if (pos != NULL) {
+ return pos + 1;
+ }
+ }
+ return NULL;
+ }
+
+ // If the path ends with the given searchName, replace in-place by the new name
+ void replaceName(const char *searchName, const char* newName) {
+ if (mStr == NULL) return;
+ int n = length();
+ int sn = strlen(searchName);
+ if (n < sn) return;
+ // if mStr ends with searchName
+ if (strcmp(mStr + n - sn, searchName) == 0) {
+ int sn2 = strlen(newName);
+ if (sn2 > sn) {
+ mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);
+ }
+ strcpy(mStr + n - sn, newName);
+ mStr[n + sn2 - sn] = 0;
+ }
+ }
+
+ // Returns a copy of this path as a DOS short path in the destination.
+ // Returns true if the Win32 getShortPathName method worked.
+ // In case of error, returns false and does not change the destination.
+ // It's OK to invoke this->toShortPath(this).
+ bool toShortPath(CPath *dest) {
+ const char *longPath = mStr;
+ if (mStr == NULL) return false;
+
+ DWORD lenShort = strlen(longPath) + 1;
+ char * shortPath = (char *)malloc(lenShort);
+
+ DWORD length = GetShortPathName(longPath, shortPath, lenShort);
+ if (length > lenShort) {
+ // The buffer wasn't big enough, this is the size to use.
+ free(shortPath);
+ lenShort = length;
+ shortPath = (char *)malloc(length);
+ length = GetShortPathName(longPath, shortPath, lenShort);
+ }
+
+ if (length != 0) dest->set(shortPath);
+
+ free(shortPath);
+ return length != 0;
+ }
+};
+
+// Displays a message in an ok+info dialog box.
+void msgBox(const char* text, ...);
+
+// Displays GetLastError prefixed with a description in an error dialog box
+void displayLastError(const char *description, ...);
+
+// Executes the command line. Does not wait for the program to finish.
+// The return code is from CreateProcess (0 means failure), not the running app.
+int execNoWait(const char *app, const char *params, const char *workDir);
+
+// Executes command, waits for completion and returns exit code.
+// As indicated in MSDN for CreateProcess, callers should double-quote the program name
+// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";
+int execWait(const char *cmd);
+
+bool getModuleDir(CPath *outDir);
+
+// Disables the FS redirection done by WOW64.
+// Because this runs as a 32-bit app, Windows automagically remaps some
+// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").
+// This prevents the app from correctly searching for java.exe in these folders.
+// The registry is also remapped.
+PVOID disableWow64FsRedirection();
+
+// Reverts the redirection disabled in disableWow64FsRedirection.
+void revertWow64FsRedirection(PVOID oldWow64Value);
+
+#endif /* _WIN32 */
+#endif /* _H_UTILS */